[Python 100일 챌린지] Day 44 - CSV 파일 처리
df = pd.read_csv('sales.csv')→df[df['금액'] > 10000]고객만 필터링! 😊엑셀보다 빠르고 강력한 데이터 처리! 판매 데이터 분석, 회원 통계, 월별 리포트… 수십만 줄 CSV도 Python으로 1초 만에 분석합니다!
(40-50분 완독 ⭐⭐⭐ 난이도: 중급)
🎯 학습 목표
📚 사전 지식
- Day 41: 파일 시스템과 경로 관리
- Day 42: 텍스트 파일 고급 처리
- Day 43: JSON 데이터 처리
- Phase 4의 객체지향 프로그래밍 개념
🎯 학습 목표 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 처리 시 주의사항
- Windows 개행 문제:
newline=''사용 필수 - 한글 인코딩:
encoding='utf-8-sig'(Excel 호환) - 결측치 처리: 분석 전 반드시 처리
- inplace 파라미터: 원본 수정 여부 주의
- 대용량 파일: 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
요구사항:
csv모듈을 사용하여 파일 읽기- 수학 점수가 80점 이상인 학생만 필터링
- 결과를
high_scorers.csv에 저장
출력 예시 (high_scorers.csv):
name,math,english,science
Alice,85,92,78
Charlie,95,88,92
Emma,88,95,90
💡 힌트
csv.DictReader()로 파일 읽기int(row['math']) >= 80조건으로 필터링csv.DictWriter()로 결과 저장- 람다 함수 사용:
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
요구사항:
- Pandas를 사용하여 파일 읽기
- 총액 (price × quantity) 열 추가
- 결과를
inventory_with_total.csv에 저장 - 총액이 높은 순으로 정렬
출력 예시 (inventory_with_total.csv):
product,price,quantity,total
Laptop,1200000,5,6000000
Monitor,350000,8,2800000
Keyboard,80000,15,1200000
Mouse,30000,20,600000
💡 힌트
pd.read_csv()로 파일 읽기df['total'] = df['price'] * df['quantity']로 새 열 추가df.sort_values(by='total', ascending=False)로 정렬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원
📝 오늘 배운 내용 정리
핵심 정리
- csv 모듈:
csv.reader(): 리스트로 읽기csv.DictReader(): 딕셔너리로 읽기csv.writer(),csv.DictWriter(): 쓰기
- Pandas:
pd.read_csv(): CSV 읽기df.to_csv(): CSV 저장- 필터링, 정렬, 그룹화
- 데이터 정제:
- 결측치 처리:
dropna(),fillna() - 중복 제거:
drop_duplicates() - 타입 변환:
astype(),to_numeric()
- 결측치 처리:
- 실전 활용:
- 데이터 병합, 변환, 분석, 검증
체크리스트
- CSV 형식과 csv 모듈 이해
csv.reader()와csv.DictReader()사용법 숙지newline=''파라미터의 필요성 이해- Pandas 라이브러리의 장점 이해
encoding='utf-8-sig'와 BOM 개념 이해- DataFrame 필터링, 정렬, 그룹화 방법 숙지
- 결측치 처리 방법 이해
inplace파라미터의 의미 이해- CSV ↔ Excel 변환 방법 숙지
🔗 관련 자료
📚 이전 학습
JSON 파일 읽기/쓰기, 데이터 변환, 중첩 JSON 처리를 배웠습니다!
📚 다음 학습
내일은 예외 처리 기초, try-except 구문, 에러 타입별 처리를 배웁니다!
“늦었다고 생각할 때가 가장 빠른 때입니다. 오늘도 한 걸음 전진하셨습니다!” 🚀
이제와서 시작하는 Python 마스터하기 - Day 44 완료! 🎉
