분석가와 개발자를 위한 CSV 데이터 정제 팁
CSV 파일은 표 형식 데이터의 보편적인 교환 포맷입니다. 간단하고, 사람이 읽을 수 있으며, Excel에서 pandas까지 모든 도구에서 지원됩니다. 하지만 실제 CSV 파일은 종종 지저분합니다 — 일관성 없는 인코딩, 결측값, 혼합 데이터 타입, 잘못된 행들. 이 가이드에서는 CSV 데이터를 안정적으로 정제하는 실용적인 기법을 다룹니다.
일반적인 CSV 문제
1. 인코딩 문제
가장 답답한 CSV 문제는 인코딩입니다. Windows의 Excel에서 생성된 파일은 windows-1252를 사용할 수 있지만, Python 스크립트는 utf-8을 기대합니다.
증상: é 대신 é와 같은 깨진 문자(모지바케), 또는 UnicodeDecodeError 예외.
감지:
import chardet
with open('data.csv', 'rb') as f:
result = chardet.detect(f.read(10000))
print(result) # {'encoding': 'Windows-1252', 'confidence': 0.73}
수정: 감지된 인코딩으로 읽고, UTF-8로 저장합니다:
import pandas as pd
df = pd.read_csv('data.csv', encoding='windows-1252')
df.to_csv('data_clean.csv', encoding='utf-8', index=False)
2. 일관성 없는 구분자
모든 "CSV"가 쉼표를 사용하는 것은 아닙니다. 유럽 CSV 파일은 쉼표가 소수점 구분자인 많은 유럽 로캘에서 세미콜론을 자주 사용합니다.
# 구분자 자동 감지
import csv
with open('data.csv', 'r') as f:
dialect = csv.Sniffer().sniff(f.read(5000))
print(f"Delimiter: {repr(dialect.delimiter)}")
CSV 편집기는 구분자 감지를 자동으로 처리합니다 — 데이터를 붙여넣으면 포맷을 식별합니다.
3. 결측값
누락된 데이터는 여러 형태로 나타납니다: 빈 셀, NA, N/A, null, -, 또는 단순히 공백.
# 모든 결측값 표현을 표준화
df = pd.read_csv('data.csv', na_values=['NA', 'N/A', 'null', '-', '', ' '])
# 열별 결측값 확인
print(df.isnull().sum())
# 전략 1: 핵심 필드에 결측값이 있는 행 삭제
df = df.dropna(subset=['email', 'name'])
# 전략 2: 기본값으로 채우기
df['country'] = df['country'].fillna('Unknown')
# 전략 3: 전방 채우기 (시계열)
df['price'] = df['price'].ffill()
4. 중복 행
정확한 중복은 찾기 쉽습니다. 퍼지 중복 (약간 다른 이름 철자를 가진 같은 사람)은 더 어렵습니다.
# 정확한 중복 찾기
duplicates = df[df.duplicated(keep=False)]
print(f"Found {len(duplicates)} duplicate rows")
# 중복 제거, 첫 번째 발생 유지
df = df.drop_duplicates()
# 특정 열 기준으로 중복 제거
df = df.drop_duplicates(subset=['email'], keep='last')
5. 일관성 없는 데이터 포맷
혼합된 날짜 포맷, 국가 코드 유무가 다른 전화번호, 일관성 없는 대소문자:
# 날짜 표준화
df['date'] = pd.to_datetime(df['date'], format='mixed', dayfirst=False)
# 텍스트 필드 표준화
df['name'] = df['name'].str.strip().str.title()
df['email'] = df['email'].str.strip().str.lower()
# 전화번호 표준화 (기본)
df['phone'] = df['phone'].str.replace(r'[^0-9+]', '', regex=True)
6. 데이터 타입 문제
CSV는 모든 것을 텍스트로 저장합니다. 앞에 0이 있는 숫자, 우편번호, 전화번호는 파싱 시 포맷을 잃을 수 있습니다:
# 우편번호의 앞자리 0 보존
df = pd.read_csv('data.csv', dtype={'zip_code': str, 'phone': str})
# 통화 문자열을 숫자로 변환
df['price'] = df['price'].str.replace('$', '').str.replace(',', '').astype(float)
정제 후 검증
정제된 데이터를 항상 검증하세요:
# 행 수 확인 (예상치 못하게 행을 잃거나 얻지 않았는지?)
print(f"Rows: {len(df)}")
# 데이터 타입 확인
print(df.dtypes)
# 값 범위 확인
print(df.describe())
# 남은 null 확인
print(df.isnull().sum())
# 고유 제약 조건 검증
assert df['email'].is_unique, "Duplicate emails found!"
커맨드 라인 도구
코드 작성 없이 빠르게 정제하기:
# 인코딩 변환
iconv -f WINDOWS-1252 -t UTF-8 input.csv > output.csv
# 정렬하고 중복 행 제거
sort -u input.csv > output.csv
# 특정 열 추출 (cut)
cut -d',' -f1,3,5 input.csv > output.csv
# 행 필터링 (awk)
awk -F',' '$3 > 100' input.csv > filtered.csv
더 복잡한 변환을 위해 csvkit은 CSV 유틸리티의 전체 제품군을 제공합니다:
# 설치
pip install csvkit
# 열 이름 보기
csvcut -n data.csv
# 행 필터링
csvgrep -c country -m "USA" data.csv > usa_only.csv
# JSON으로 변환
csvjson data.csv > data.json
CSV와 JSON 간 변환이 필요하신가요? CSV to JSON 변환기가 즉시 처리합니다.
자주 묻는 질문
CSV 처리의 최대 파일 크기는 얼마인가요?
CSV 포맷에는 고유한 제한이 없습니다. 실질적 제한은 도구에 따라 다릅니다: Excel은 약 100만 행을 처리하고, pandas는 충분한 RAM으로 수 GB까지 잘 작동하며, Dask나 Polars 같은 도구는 메모리보다 큰 데이터셋을 처리합니다. 브라우저 기반 도구의 경우, CSV 편집기는 100MB까지의 파일을 처리합니다.
데이터 교환에 CSV와 JSON 중 어떤 것을 사용해야 하나요?
CSV는 평탄한 표 형식 데이터 (스프레드시트, 데이터베이스 내보내기, 단순 목록)에 적합합니다. JSON은 중첩된 계층 데이터 (API 응답, 설정, 구조가 다양한 문서)에 더 적합합니다. 자세한 비교는 CSV vs JSON vs XML 가이드를 참조하세요.
관련 리소스
- CSV 편집기 — 브라우저에서 CSV 데이터 편집 및 정제
- CSV to JSON 변환 가이드 — 포맷 간 변환
- JSON 포맷팅 모범 사례 — JSON 출력 작업