포스트

[Python 100일 챌린지] Day 44 - CSV 파일 처리

[Python 100일 챌린지] Day 44 - CSV 파일 처리

df = pd.read_csv('sales.csv')df[df['금액'] > 10000] 고객만 필터링! 😊

엑셀보다 빠르고 강력한 데이터 처리! 판매 데이터 분석, 회원 통계, 월별 리포트… 수십만 줄 CSV도 Python으로 1초 만에 분석합니다!

(40-50분 완독 ⭐⭐⭐ 난이도: 중급)

🎯 학습 목표

📚 사전 지식


🎯 학습 목표 1: CSV 형식의 개념 이해하기

1.1 CSV란?

CSV (Comma-Separated Values):

  • 쉼표로 구분된 값들
  • 엑셀, 구글 시트 등에서 사용
  • 간단하고 범용적
name,age,city
Alice,25,Seoul
Bob,30,Busan
Charlie,35,Incheon

1.2 csv 모듈

1
2
3
4
5
6
7
8
import csv

# CSV 읽기
with open('data.csv', 'r', encoding='utf-8') as f:
    reader = csv.reader(f)

    for row in reader:
        print(row)  # ['Alice', '25', 'Seoul']

🎯 학습 목표 2: csv 모듈로 CSV 읽기

2.1 기본 읽기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import csv

def read_csv_basic(filename):
    """CSV 파일 기본 읽기"""
    with open(filename, 'r', encoding='utf-8') as f:
        reader = csv.reader(f)

        # 헤더
        headers = next(reader)
        print(f"컬럼: {headers}")

        # 데이터
        for row in reader:
            print(row)

# read_csv_basic('users.csv')

2.2 DictReader (딕셔너리로 읽기)

1
2
3
4
5
6
7
8
9
10
def read_csv_dict(filename):
    """CSV를 딕셔너리로 읽기"""
    with open(filename, 'r', encoding='utf-8') as f:
        reader = csv.DictReader(f)

        for row in reader:
            print(row)  # OrderedDict (딕셔너리처럼 사용 가능)
            print(f"이름: {row['name']}, 나이: {row['age']}")

# read_csv_dict('users.csv')

2.3 다양한 구분자

1
2
3
4
5
6
7
8
9
10
11
# 탭(TSV)
with open('data.tsv', 'r') as f:
    reader = csv.reader(f, delimiter='\t')
    for row in reader:
        print(row)

# 파이프(|)
with open('data.txt', 'r') as f:
    reader = csv.reader(f, delimiter='|')
    for row in reader:
        print(row)

🎯 학습 목표 3: csv 모듈로 CSV 쓰기

newline=''이 필요한 이유

Windows 개행 문제:

  • Windows는 줄바꿈을 \r\n(CR+LF)로 표현
  • Python은 자동으로 \n\r\n으로 변환
  • CSV 쓰기 시 이중 변환으로 빈 줄 생성
  • newline=''로 자동 변환 방지!

3.1 기본 쓰기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def write_csv_basic(filename, data):
    """CSV 파일 쓰기"""
    with open(filename, 'w', newline='', encoding='utf-8') as f:
        writer = csv.writer(f)

        # 헤더
        writer.writerow(['이름', '나이', '도시'])

        # 데이터
        for row in data:
            writer.writerow(row)

# 사용
data = [
    ['Alice', 25, 'Seoul'],
    ['Bob', 30, 'Busan'],
    ['Charlie', 35, 'Incheon']
]
write_csv_basic('output.csv', data)

주의: newline='' 필수! (Windows에서 빈 줄 방지)

3.2 DictWriter (딕셔너리로 쓰기)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def write_csv_dict(filename, data):
    """딕셔너리를 CSV로 쓰기"""
    if not data:
        return

    fieldnames = data[0].keys()

    with open(filename, 'w', newline='', encoding='utf-8') as f:
        writer = csv.DictWriter(f, fieldnames=fieldnames)

        writer.writeheader()  # 헤더 자동 작성
        writer.writerows(data)

# 사용
users = [
    {'name': 'Alice', 'age': 25, 'city': 'Seoul'},
    {'name': 'Bob', 'age': 30, 'city': 'Busan'}
]
write_csv_dict('users.csv', users)

3.3 CSV 추가 모드

1
2
3
4
5
6
7
8
def append_to_csv(filename, row):
    """CSV 파일에 행 추가"""
    with open(filename, 'a', newline='', encoding='utf-8') as f:
        writer = csv.writer(f)
        writer.writerow(row)

# 사용
append_to_csv('users.csv', ['David', 28, 'Daegu'])

🎯 학습 목표 4: Pandas로 CSV 데이터 처리하기

⚙️ 시작 전 설치 필요

오늘 학습에는 외부 라이브러리가 필요합니다:

1
pip install pandas openpyxl
라이브러리 용도
pandas 데이터 분석 및 CSV 처리
openpyxl Excel 파일 처리 (CSV ↔ Excel 변환)

참고: Python 표준 라이브러리 csv 모듈은 별도 설치 없이 사용 가능합니다!

Pandas란?

Pandas (Python Data Analysis Library):

  • 데이터 분석을 위한 가장 인기 있는 Python 라이브러리
  • 표 형태 데이터를 쉽게 처리 (엑셀처럼!)
  • csv 모듈보다 훨씬 강력하고 편리

주요 장점:

  • 빠른 데이터 읽기/쓰기
  • 강력한 필터링, 정렬, 그룹화 기능
  • 결측치 처리, 통계 분석 기능 내장
  • Excel, SQL, JSON 등 다양한 형식 지원

4.1 Pandas 기본

1
2
3
4
5
6
7
8
9
10
# pip install pandas

import pandas as pd

# CSV 읽기
df = pd.read_csv('users.csv')

print(df.head())      # 상위 5개 행
print(df.info())      # 데이터 정보
print(df.describe())  # 통계 요약

4.2 Pandas CSV 쓰기

encoding=’utf-8-sig’란?

  • utf-8-sig: UTF-8 + BOM(Byte Order Mark)
  • BOM: 파일 인코딩을 알려주는 특수 바이트
  • Excel에서 한글 CSV를 올바르게 인식하게 함
  • Windows Excel 사용 시 필수!
1
2
3
4
5
6
# CSV 저장
df.to_csv('output.csv', index=False, encoding='utf-8-sig')

# 옵션
# index=False: 인덱스 열 제외
# encoding='utf-8-sig': Excel 한글 호환 (BOM 추가)

4.3 데이터 필터링

1
2
3
4
5
6
7
8
# 나이 30 이상
adults = df[df['age'] >= 30]

# 서울 거주자
seoul_users = df[df['city'] == 'Seoul']

# 여러 조건
result = df[(df['age'] >= 25) & (df['city'] == 'Seoul')]

4.4 데이터 정렬

1
2
3
4
5
6
7
8
# 나이 순 정렬
df_sorted = df.sort_values('age')

# 내림차순
df_sorted = df.sort_values('age', ascending=False)

# 여러 컬럼
df_sorted = df.sort_values(['city', 'age'])

4.5 데이터 그룹화

1
2
3
4
5
6
7
8
9
10
11
# 도시별 평균 나이
city_stats = df.groupby('city')['age'].mean()

# 도시별 인원수
city_counts = df.groupby('city').size()

# 여러 통계
stats = df.groupby('city').agg({
    'age': ['mean', 'min', 'max'],
    'name': 'count'
})

🎯 학습 목표 5: 데이터 정제와 검증하기

inplace 파라미터란?

inplace의 의미:

  • inplace=False (기본값): 새로운 DataFrame 반환, 원본 유지
  • inplace=True: 원본 DataFrame 직접 수정, 반환값 없음
1
2
3
4
5
# inplace=False (기본): 새 DataFrame 생성
df_new = df.fillna(0)  # df는 그대로, df_new는 채워진 상태

# inplace=True: 원본 수정
df.fillna(0, inplace=True)  # df 자체가 수정됨

5.1 결측치 처리

결측치(Missing Values)란?

  • 비어있는 값, NaN(Not a Number)로 표현
  • 데이터 수집 중 누락되거나 잘못된 값
  • 분석 전 반드시 처리 필요!
1
2
3
4
5
6
7
8
9
# 결측치 확인
print(df.isnull().sum())

# 결측치 제거
df_cleaned = df.dropna()

# 결측치 채우기
df['age'].fillna(df['age'].mean(), inplace=True)  # 평균값으로 채우기
df['city'].fillna('Unknown', inplace=True)  # 기본값으로 채우기

5.2 중복 제거

1
2
3
4
5
6
7
8
# 중복 확인
print(df.duplicated().sum())

# 중복 제거
df_unique = df.drop_duplicates()

# 특정 컬럼 기준
df_unique = df.drop_duplicates(subset=['name'])

5.3 데이터 타입 변환

1
2
3
4
5
6
7
8
# 문자열 → 숫자
df['age'] = pd.to_numeric(df['age'], errors='coerce')

# 문자열 → 날짜
df['date'] = pd.to_datetime(df['date'])

# 카테고리형
df['city'] = df['city'].astype('category')

5.4 CSV 데이터 검증

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def validate_csv(filename, schema):
    """CSV 데이터 유효성 검증"""
    df = pd.read_csv(filename)

    errors = []

    for col, rules in schema.items():
        if col not in df.columns:
            errors.append(f"컬럼 누락: {col}")
            continue

        # 타입 검증
        if 'type' in rules:
            expected_type = rules['type']
            if expected_type == 'int':
                if not pd.api.types.is_integer_dtype(df[col]):
                    errors.append(f"{col}: 정수 타입 아님")

        # 범위 검증
        if 'min' in rules:
            if (df[col] < rules['min']).any():
                errors.append(f"{col}: 최소값 {rules['min']} 미만")

        if 'max' in rules:
            if (df[col] > rules['max']).any():
                errors.append(f"{col}: 최대값 {rules['max']} 초과")

        # 필수 값
        if rules.get('required', False):
            if df[col].isnull().any():
                errors.append(f"{col}: 필수 값 누락")

    if errors:
        print("❌ 검증 실패:")
        for error in errors:
            print(f"{error}")
        return False
    else:
        print("✅ 검증 성공")
        return True

# 사용
schema = {
    'age': {'type': 'int', 'min': 0, 'max': 150, 'required': True},
    'name': {'required': True},
    'email': {'required': False}
}

validate_csv('users.csv', schema)

🎯 학습 목표 6: CSV-Excel 변환과 실전 활용

openpyxl 라이브러리란?

openpyxl:

  • Python에서 Excel 파일(.xlsx)을 다루는 라이브러리
  • Pandas와 함께 사용하여 CSV ↔ Excel 변환
  • 설치: pip install openpyxl

6.1 CSV → Excel 변환

1
2
3
4
5
6
7
8
9
10
# pip install openpyxl

# CSV → Excel
df = pd.read_csv('data.csv')
df.to_excel('data.xlsx', index=False, sheet_name='Sheet1')

# 여러 시트
with pd.ExcelWriter('report.xlsx') as writer:
    df1.to_excel(writer, sheet_name='Users', index=False)
    df2.to_excel(writer, sheet_name='Sales', index=False)

6.2 Excel → CSV

1
2
3
4
5
# Excel 읽기
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')

# CSV 저장
df.to_csv('data.csv', index=False, encoding='utf-8-sig')

6.3 실전 종합 예제

예제 1: CSV 병합

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def merge_csv_files(file_list, output_file):
    """여러 CSV 파일 병합"""
    dfs = []

    for file in file_list:
        df = pd.read_csv(file)
        dfs.append(df)

    # ignore_index=True: 인덱스를 0부터 다시 매기기
    merged = pd.concat(dfs, ignore_index=True)
    merged.to_csv(output_file, index=False, encoding='utf-8-sig')

    print(f"{len(file_list)}개 파일 → {output_file}")
    print(f"{len(merged)}")

# 사용
files = ['2024-01.csv', '2024-02.csv', '2024-03.csv']
merge_csv_files(files, '2024-Q1.csv')

예제 2: CSV 변환 (Wide → Long)

💡 Wide vs. Long 형식이란?

데이터를 표현하는 두 가지 방식입니다:

  • Wide (넓은) 형식: 각 연도가 별도 컬럼 → 사람이 보기 편함
  • Long (긴) 형식: 연도-값이 행으로 나열 → 분석 및 시각화에 유리

언제 사용하나요?

  • 그래프 그리기, 통계 분석, 데이터베이스 저장 시 → Long 형식 필요
  • Pandas, Matplotlib 등은 Long 형식을 선호
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Wide 형식 (사람이 보기 편함)
# name,2023,2024,2025
# Alice,100,110,120

# Long 형식으로 변환 (분석에 유리)
# name,year,value
# Alice,2023,100
# Alice,2024,110
# Alice,2025,120

df_wide = pd.read_csv('wide.csv')

# Wide → Long 변환
df_long = df_wide.melt(
    id_vars=['name'],        # 고정할 컬럼 (이름)
    var_name='year',         # 기존 컬럼명들을 담을 새 컬럼명
    value_name='value'       # 값들을 담을 새 컬럼명
)
df_long.to_csv('long.csv', index=False)

예제 3: 매출 분석

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# sales.csv: date,product,amount,quantity

df = pd.read_csv('sales.csv')
df['date'] = pd.to_datetime(df['date'])

# 월별 매출
monthly = df.groupby(df['date'].dt.to_period('M')).agg({
    'amount': 'sum',
    'quantity': 'sum'
})

# 제품별 매출
product_sales = df.groupby('product')['amount'].sum().sort_values(ascending=False)

# 상위 5개 제품
top_5 = product_sales.head(5)

print("월별 매출:")
print(monthly)
print("\n상위 5개 제품:")
print(top_5)

💡 실전 팁 & 주의사항

외부 라이브러리 정리

오늘 학습에서 사용한 외부 라이브러리들:

라이브러리 용도 설치 명령
pandas 데이터 분석 및 CSV 처리 pip install pandas
openpyxl Excel 파일 처리 pip install openpyxl

참고: Python 표준 라이브러리 csv 모듈은 별도 설치 없이 사용 가능합니다!

CSV 처리 시 주의사항

  1. Windows 개행 문제: newline='' 사용 필수
  2. 한글 인코딩: encoding='utf-8-sig' (Excel 호환)
  3. 결측치 처리: 분석 전 반드시 처리
  4. inplace 파라미터: 원본 수정 여부 주의
  5. 대용량 파일: Pandas의 chunksize 파라미터 활용

🧪 연습 문제

문제 1: 성적 데이터 필터링

상황: 학생 성적이 담긴 CSV 파일(grades.csv)이 있습니다.

입력 데이터 (grades.csv):

name,math,english,science
Alice,85,92,78
Bob,72,68,81
Charlie,95,88,92
David,65,71,69
Emma,88,95,90

요구사항:

  1. csv 모듈을 사용하여 파일 읽기
  2. 수학 점수가 80점 이상인 학생만 필터링
  3. 결과를 high_scorers.csv에 저장

출력 예시 (high_scorers.csv):

name,math,english,science
Alice,85,92,78
Charlie,95,88,92
Emma,88,95,90
💡 힌트
  1. csv.DictReader()로 파일 읽기
  2. int(row['math']) >= 80 조건으로 필터링
  3. csv.DictWriter()로 결과 저장
  4. 람다 함수 사용: lambda row: int(row['math']) >= 80
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import csv

def filter_csv(input_file, output_file, condition):
    """CSV 필터링"""
    with open(input_file, 'r', encoding='utf-8') as fin:
        reader = csv.DictReader(fin)
        fieldnames = reader.fieldnames

        filtered_rows = [row for row in reader if condition(row)]

    with open(output_file, 'w', newline='', encoding='utf-8') as fout:
        writer = csv.DictWriter(fout, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(filtered_rows)

# 사용: 수학 점수 80점 이상만 필터링
# lambda: 간단한 1줄 함수 (자세한 내용은 Day 28 참고)
# lambda row: ... → "각 row를 받아서 ... 조건을 확인"
filter_csv('grades.csv', 'high_scorers.csv',
           lambda row: int(row['math']) >= 80)

print("✅ 필터링 완료: high_scorers.csv")

# 💡 일반 함수로 작성하면 이렇게 됩니다:
# def is_high_scorer(row):
#     return int(row['math']) >= 80
# filter_csv('grades.csv', 'high_scorers.csv', is_high_scorer)

실행 결과:

1
✅ 필터링 완료: high_scorers.csv

문제 2: 상품 총액 계산

상황: 상품 재고 데이터가 담긴 CSV 파일(inventory.csv)이 있습니다.

입력 데이터 (inventory.csv):

product,price,quantity
Laptop,1200000,5
Mouse,30000,20
Keyboard,80000,15
Monitor,350000,8

요구사항:

  1. Pandas를 사용하여 파일 읽기
  2. 총액 (price × quantity) 열 추가
  3. 결과를 inventory_with_total.csv에 저장
  4. 총액이 높은 순으로 정렬

출력 예시 (inventory_with_total.csv):

product,price,quantity,total
Laptop,1200000,5,6000000
Monitor,350000,8,2800000
Keyboard,80000,15,1200000
Mouse,30000,20,600000
💡 힌트
  1. pd.read_csv()로 파일 읽기
  2. df['total'] = df['price'] * df['quantity']로 새 열 추가
  3. df.sort_values(by='total', ascending=False)로 정렬
  4. df.to_csv(..., index=False)로 저장
✅ 정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import pandas as pd

# CSV 읽기
df = pd.read_csv('inventory.csv')

# 총액 열 추가 (계산)
df['total'] = df['price'] * df['quantity']

# 총액 높은 순으로 정렬
df = df.sort_values(by='total', ascending=False)

# 저장
df.to_csv('inventory_with_total.csv', index=False, encoding='utf-8-sig')

print("✅ 총액 계산 완료: inventory_with_total.csv")
print(f"\n총 재고 가치: {df['total'].sum():,}")

실행 결과:

1
2
3
✅ 총액 계산 완료: inventory_with_total.csv

총 재고 가치: 10,600,000원

📝 오늘 배운 내용 정리

핵심 정리

  1. csv 모듈:
    • csv.reader(): 리스트로 읽기
    • csv.DictReader(): 딕셔너리로 읽기
    • csv.writer(), csv.DictWriter(): 쓰기
  2. Pandas:
    • pd.read_csv(): CSV 읽기
    • df.to_csv(): CSV 저장
    • 필터링, 정렬, 그룹화
  3. 데이터 정제:
    • 결측치 처리: dropna(), fillna()
    • 중복 제거: drop_duplicates()
    • 타입 변환: astype(), to_numeric()
  4. 실전 활용:
    • 데이터 병합, 변환, 분석, 검증

체크리스트

  • CSV 형식과 csv 모듈 이해
  • csv.reader()csv.DictReader() 사용법 숙지
  • newline='' 파라미터의 필요성 이해
  • Pandas 라이브러리의 장점 이해
  • encoding='utf-8-sig'와 BOM 개념 이해
  • DataFrame 필터링, 정렬, 그룹화 방법 숙지
  • 결측치 처리 방법 이해
  • inplace 파라미터의 의미 이해
  • CSV ↔ Excel 변환 방법 숙지

🔗 관련 자료


📚 이전 학습

← Day 43: JSON 데이터 처리

JSON 파일 읽기/쓰기, 데이터 변환, 중첩 JSON 처리를 배웠습니다!

📚 다음 학습

Day 45: 예외 처리 기초 →

내일은 예외 처리 기초, try-except 구문, 에러 타입별 처리를 배웁니다!


“늦었다고 생각할 때가 가장 빠른 때입니다. 오늘도 한 걸음 전진하셨습니다!” 🚀


이제와서 시작하는 Python 마스터하기 - Day 44 완료! 🎉

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.