- Published on
pandas read_csv UnicodeDecodeError 5분 해결법
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버 로그나 다운로드 받은 엑셀 내보내기 CSV를 pandas.read_csv로 읽는 순간, 아래 같은 에러로 멈추는 경우가 많습니다.
UnicodeDecodeError: 'utf-8' codec can't decode byte ...UnicodeDecodeError: 'cp949' codec can't decode byte ...
핵심은 간단합니다. read_csv는 기본적으로 encoding='utf-8'로 해석하려고 시도하며, 파일의 실제 인코딩과 다르면 바로 예외가 납니다. 이 글은 “원인 후보를 좁히는 2분 + 확정 해결 3분” 흐름으로 정리합니다.
1) 5분 해결 로드맵
- 파일이 어떤 인코딩인지 “추정”한다
- 가장 흔한 후보인
utf-8-sig,cp949,euc-kr로 “빠르게 시도”한다 - 그래도 안 되면 “깨진 줄 위치”를 찾아 CSV 구조 문제(구분자/따옴표/개행)를 확인한다
- 운영 파이프라인이라면 “자동 감지 + 폴백” 코드로 고정한다
장애 대응 관점에서는 원인 분석을 길게 하기보다, 재발 방지 가능한 형태로 흡수하는 게 중요합니다. 비슷한 트러블슈팅 접근은 다른 장애 글에서도 유효합니다. 예: OpenAI Structured Outputs 400 해결 - JSON Schema
2) 가장 빠른 해결: utf-8-sig 먼저
윈도우/엑셀 계열에서 CSV를 저장하면 UTF-8인데도 BOM(Byte Order Mark)이 붙는 경우가 흔합니다. 이때 utf-8로 읽으면 헤더 첫 컬럼에 보이지 않는 문자가 끼거나, 환경에 따라 디코딩 문제가 발생합니다.
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8-sig")
print(df.head())
utf-8-sig는 “UTF-8 + BOM 허용”입니다.- 한글 데이터가 섞인 CSV에서 가장 먼저 시도할 값입니다.
3) 한국에서 제일 흔한 원인: cp949 (또는 euc-kr)
공공데이터, 오래된 레거시 시스템, 윈도우 로컬 저장 파일은 cp949인 경우가 많습니다.
import pandas as pd
df = pd.read_csv("data.csv", encoding="cp949")
euc-kr도 시도할 수 있지만, 실무에서는 cp949가 더 넓게 커버합니다.
df = pd.read_csv("data.csv", encoding="euc-kr")
에러 메시지로 인코딩 힌트 얻기
- 메시지에
'utf-8' codec can't decode byte가 보이면 “파일이 UTF-8이 아닐 가능성”이 큽니다. - 반대로
'cp949' codec can't decode byte라면 “파일이 CP949가 아닐 가능성”이 큽니다.
여기서 중요한 점은, 인코딩이 맞아도 CSV 구조가 깨져 있으면 다른 예외가 날 수 있다는 것입니다. 다음 섹션에서 구조 문제를 분리 진단합니다.
4) 2분 진단: 인코딩 자동 추정(외부 라이브러리)
로컬에서 빠르게 확인하려면 charset-normalizer(파이썬 3 계열에서 권장) 또는 chardet을 씁니다.
charset-normalizer로 추정
from charset_normalizer import from_path
result = from_path("data.csv").best()
print(result.encoding)
print(result.percent_chaos)
encoding이 후보 인코딩percent_chaos가 높으면 텍스트로 보기 어려운 바이트가 섞였거나, 일부 행이 깨졌을 수 있습니다.
추정 결과를 read_csv에 적용
import pandas as pd
from charset_normalizer import from_path
enc = from_path("data.csv").best().encoding
df = pd.read_csv("data.csv", encoding=enc)
추정은 “정답 보장”이 아니라 “시도 순서 최적화” 정도로 생각하는 게 안전합니다.
5) 인코딩이 아니라 CSV 구조가 깨진 경우
인코딩을 바꿔도 계속 실패한다면, 실제로는 아래 문제일 수 있습니다.
- 따옴표가 닫히지 않아 한 줄이 끝나지 않음
- 구분자가 중간에 섞임(쉼표와 탭 혼재)
- 텍스트 필드에 개행이 들어갔는데 quoting 규칙이 깨짐
이때는 “몇 번째 줄에서 죽는지”를 확인해야 합니다.
engine='python'으로 더 자세한 파싱 시도
C 엔진보다 파이썬 엔진이 예외 메시지가 더 친절한 편입니다.
import pandas as pd
try:
df = pd.read_csv("data.csv", encoding="utf-8-sig", engine="python")
except Exception as e:
print(e)
문제 행을 건너뛰어 일단 로딩(응급처치)
운영에서 “일단 데이터 파이프라인을 살려야” 할 때가 있습니다. 그럴 땐 깨진 라인을 스킵하고, 별도 로그로 남겨 후처리합니다.
import pandas as pd
# pandas 1.3+ 권장 옵션
# on_bad_lines: 'error' | 'warn' | 'skip'
df = pd.read_csv(
"data.csv",
encoding="cp949",
on_bad_lines="skip",
engine="python",
)
- 이 방법은 데이터 유실이 발생할 수 있으니, 반드시 “스킵된 라인 수”와 “원본 파일”을 보관하세요.
구분자 확인: 쉼표가 아니라 탭일 수 있음
엑셀에서 “CSV(쉼표로 분리)”가 아니라 “텍스트(탭으로 분리)”로 저장된 파일을 CSV로 착각하는 경우가 많습니다.
import pandas as pd
df = pd.read_csv("data.csv", encoding="utf-8-sig", sep="\t")
6) 실전에서 가장 안전한 패턴: 폴백 전략
팀 단위로 운영하면 “파일 인코딩이 매번 다를 수 있다”는 전제를 받아들이는 편이 싸게 먹힙니다. 아래는 실패 확률을 낮추는 폴백 로딩 함수 예시입니다.
from __future__ import annotations
import pandas as pd
def read_csv_with_fallback(path: str, **kwargs) -> pd.DataFrame:
encodings = ["utf-8-sig", "utf-8", "cp949", "euc-kr"]
last_err = None
for enc in encodings:
try:
return pd.read_csv(path, encoding=enc, **kwargs)
except UnicodeDecodeError as e:
last_err = e
raise last_err # 모든 후보 실패 시 원인 그대로 노출
df = read_csv_with_fallback("data.csv")
여기에 sep 후보까지 넣으면 더 강해지지만, 자동화가 과해지면 “조용히 잘못 읽는” 리스크가 생깁니다. 운영 환경에서는 실패 시 알람을 확실히 내고, 입력 계약을 문서화하는 편이 더 좋습니다.
7) 깨짐 없는 표준화: 읽은 뒤 UTF-8로 재저장
한 번 읽는 데 성공했다면, 이후 파이프라인 안정성을 위해 UTF-8로 정규화해 두는 것이 좋습니다.
import pandas as pd
df = pd.read_csv("legacy.csv", encoding="cp949")
df.to_csv("normalized.csv", index=False, encoding="utf-8")
- 협업/재현성 측면에서 UTF-8이 사실상 표준입니다.
- 다만 윈도우 엑셀 호환이 중요하면
utf-8-sig로 저장하는 것도 선택지입니다.
df.to_csv("normalized_for_excel.csv", index=False, encoding="utf-8-sig")
8) 자주 묻는 케이스 Q&A
Q1. errors='ignore'로 무시하면 안 되나요?
파이썬의 open()에는 errors='ignore' 같은 옵션이 있지만, 이는 “문자를 조용히 버리는” 방식이라 데이터 품질을 망가뜨릴 수 있습니다. 분석 결과가 틀려도 원인을 찾기 어려워집니다. 응급 상황이 아니라면 권장하지 않습니다.
Q2. 같은 파일인데 어떤 PC에서는 되고 어떤 PC에서는 실패합니다
- 로케일/기본 인코딩 차이
- 파일을 만든 프로그램(엑셀 버전, 내보내기 옵션) 차이
- 중간에 업로드/다운로드를 거치며 인코딩이 변형
이런 이슈는 “환경 의존성”이 핵심이라, 코드에서 명시적으로 encoding을 고정하는 것이 좋습니다. 인프라에서도 비슷하게 “명시적 설정”이 문제를 줄입니다. 예: Terraform EKS 상태 꼬임으로 apply 무한 반복 끊기
Q3. UnicodeDecodeError가 아니라 ParserError가 나요
그건 인코딩보다 CSV 문법 문제일 확률이 큽니다. engine='python', sep 재확인, on_bad_lines로 문제 행 위치를 좁히는 접근이 더 빠릅니다.
9) 체크리스트(이대로만 하면 대부분 5분 컷)
encoding="utf-8-sig"먼저- 안 되면
encoding="cp949" - 그래도 안 되면
charset-normalizer로 추정 - 여전히 실패하면 CSV 구조 문제로 전환:
engine="python",sep확인 - 운영 파이프라인이면 폴백 함수로 흡수하고, 원본은 UTF-8로 정규화
문제 자체는 단순하지만, 재발은 잦습니다. 한 번 해결했을 때 “정규화 저장”과 “폴백 로더”까지 같이 넣어두면, 다음부터는 진짜로 5분 안에 끝납니다.