📋 목차
파이썬 pandas의 read_csv 함수로 CSV 파일을 불러오려는데 한글이 깨지거나 에러가 터져서 당황한 적 있으신가요? 인코딩 옵션 하나만 바꾸면 해결되는 경우가 대부분이고, 이 글에서 실제로 겪었던 삽질 과정과 핵심 옵션을 정리했어요.
처음 pandas를 접했을 때 솔직히 read_csv가 뭐가 어렵나 싶었거든요. 그냥 pd.read_csv(‘파일명.csv’) 한 줄이면 끝인 줄 알았어요. 근데 공공데이터 포털에서 받은 CSV를 열었더니 UnicodeDecodeError가 뜨면서 아예 읽히지를 않더라고요. 구글링해서 encoding=’cp949′ 넣으니까 되긴 했는데, 왜 이게 필요한 건지 이해가 안 됐어요.
그래서 그때부터 read_csv 옵션을 하나씩 써보면서 정리하기 시작했는데, 지금 돌이켜보면 그 시행착오가 가장 큰 공부였던 것 같아요. 특히 회사에서 수십만 행짜리 CSV를 다루게 되면서 chunksize나 dtype 같은 옵션이 진짜 중요하다는 걸 몸으로 체감했고요.
read_csv가 뭔데 이렇게 많이 쓰이는 건지
pandas의 read_csv() 함수는 CSV(Comma-Separated Values) 파일을 읽어서 DataFrame이라는 2차원 표 형태의 데이터 구조로 변환해주는 함수예요. 엑셀 시트를 떠올리면 이해하기 쉬운데, 행과 열이 있는 그 구조가 DataFrame이거든요. CSV가 데이터 분석에서 가장 흔하게 쓰이는 파일 형식이다 보니, read_csv는 pandas를 쓰는 사람이라면 거의 매일 쓰게 되는 함수예요.
왜 CSV가 이렇게 널리 쓰이냐면, 어떤 프로그램에서든 열 수 있고, 용량이 가볍거든요. 공공데이터 포털, 통계청, 캐글 같은 데이터 소스에서도 대부분 CSV 형태로 제공하고요. 엑셀로도 열리지만, 파이썬에서 자동화하려면 read_csv가 압도적으로 편해요.
한 가지 재밌는 건, read_csv는 로컬 파일만 읽는 게 아니라 URL도 바로 읽을 수 있어요. 예를 들어 깃허브에 올라간 CSV 파일의 raw URL을 그대로 넣으면 다운로드 없이 바로 데이터프레임으로 불러올 수 있거든요. 처음 알았을 때 꽤 놀랐어요.
기본 사용법부터 정리해보면
가장 기본적인 사용법은 진짜 단순해요. pandas를 import하고, read_csv에 파일 경로만 넘기면 끝이에요. 코드로 보면 이렇게 됩니다.
import pandas as pd 한 다음에 df = pd.read_csv(‘data.csv’) 이 한 줄이면 data.csv 파일이 df라는 데이터프레임 변수에 담겨요. 기본적으로 첫 번째 행을 컬럼명(header)으로 인식하고, 쉼표를 구분자로 사용해요.
근데 현실에서는 이렇게 깔끔하게 되는 경우가 오히려 드물어요. 탭으로 구분된 파일이 .csv 확장자로 올라와 있는 경우도 있고, 첫 번째 행이 헤더가 아니라 데이터인 경우도 있거든요. 그래서 알아두면 좋은 기본 옵션 세 가지가 있어요.
첫째는 sep 파라미터예요. 구분자가 쉼표가 아니라 탭이면 sep=’\t’을 넣어야 해요. 둘째는 header 파라미터인데, 헤더가 없는 파일이면 header=None으로 지정하면 pandas가 자동으로 0, 1, 2… 숫자를 컬럼명으로 붙여줘요. 셋째는 index_col 파라미터로, 특정 컬럼을 인덱스(행 이름)로 쓰고 싶을 때 index_col=’컬럼명’ 형태로 지정하면 돼요.
📊 실제 데이터
pandas 공식 문서(v3.0.3) 기준으로 read_csv에는 약 40개 이상의 파라미터가 있어요. 하지만 실무에서 자주 쓰는 건 10개 내외거든요. 나머지는 특수한 상황에서만 필요하니까 일단 핵심만 익히는 게 효율적이에요.
한글 인코딩 지옥에서 빠져나오는 법
한국에서 pandas를 쓸 때 가장 먼저 부딪히는 벽이 인코딩 문제예요. read_csv의 기본 인코딩이 utf-8이거든요. 그런데 한국 공공기관이나 기업에서 내려받는 CSV 파일은 대부분 cp949(또는 euc-kr)로 인코딩되어 있어요. 그러니까 아무 옵션 없이 읽으면 UnicodeDecodeError가 터지는 거예요.
해결법은 간단해요. encoding=’cp949′ 옵션을 추가하면 돼요. df = pd.read_csv(‘data.csv’, encoding=’cp949′) 이렇게요. cp949로도 안 되면 encoding=’euc-kr’을 시도해보고, 그래도 안 되면 encoding=’latin1’을 넣어보세요. latin1은 바이트를 그대로 통과시키기 때문에 에러는 안 나지만, 한글이 깨져서 나올 수 있어요.
제가 실제로 겪었던 황당한 경우가 있었는데, 같은 기관에서 받은 파일인데 2023년 데이터는 cp949이고 2024년 데이터는 utf-8이었어요. 통일을 안 해놓은 거죠. 그래서 저는 아예 파일을 읽을 때 try-except로 감싸는 습관이 생겼어요. 먼저 utf-8로 시도하고, 에러 나면 cp949로 다시 읽는 방식이에요.
또 하나 팁이 있는데, 파일 중간에 깨진 행이 섞여 있으면 on_bad_lines=’skip’ 옵션을 쓰면 문제가 되는 행만 건너뛰고 나머지를 읽어줘요. 데이터 몇 줄 빠지는 건 감수해야 하지만, 아예 못 읽는 것보단 나으니까요.
실무에서 자주 쓰는 옵션 비교
read_csv의 파라미터가 40개가 넘다 보니 처음에는 뭐가 중요한지 감이 안 잡혀요. 제가 1년 넘게 데이터 분석 업무를 하면서 실제로 자주 쓰게 된 옵션을 표로 정리해봤어요.
| 옵션 | 용도 | 예시 |
|---|---|---|
| encoding | 한글 깨짐 해결 | encoding=’cp949′ |
| usecols | 필요한 열만 선택 | usecols=[‘이름’,’나이’] |
| dtype | 컬럼별 타입 지정 | dtype={‘코드’: str} |
| parse_dates | 날짜 자동 변환 | parse_dates=[‘가입일’] |
| nrows | 앞부분만 미리보기 | nrows=100 |
이 중에서 제가 가장 늦게 알았는데 가장 유용했던 게 usecols예요. 30개 컬럼짜리 CSV인데 분석에 필요한 건 3개뿐인 경우가 많거든요. usecols로 필요한 열만 지정하면 메모리도 아끼고 읽는 속도도 빨라져요.
dtype도 의외로 중요해요. 우편번호 같은 컬럼이 숫자로 인식되면 앞의 0이 날아가거든요. ‘01234’가 1234가 되어버리는 거예요. 이럴 때 dtype={‘우편번호’: str}로 문자열 타입을 강제 지정하면 원본 그대로 보존돼요. 이걸 몰랐을 때 우편번호 데이터를 통째로 망친 적이 있어요.
parse_dates는 날짜 컬럼을 자동으로 datetime 타입으로 변환해주는 옵션인데, 날짜 형식이 ‘2024-01-15’처럼 표준적이면 잘 작동해요. 하지만 ‘20240115’나 ’15/01/2024′ 같은 비표준 형식이면 date_format 파라미터를 함께 써서 형식을 알려줘야 정확하게 파싱돼요.
💡 꿀팁
대용량 파일 구조를 먼저 파악하고 싶을 때는 nrows=5로 앞의 5행만 빠르게 읽어보세요. 컬럼명, 데이터 형태, 구분자를 확인한 다음에 전체를 읽으면 시행착오가 훨씬 줄어요.
대용량 CSV 파일 터지지 않게 읽는 방법
수백 MB, 심하면 수 GB짜리 CSV 파일을 만날 때가 있어요. 이걸 그냥 read_csv로 한 번에 읽으면 메모리가 부족해서 커널이 죽어버리거든요. 주피터 노트북에서 셀 실행했는데 별 반응 없이 커널이 재시작되면 대부분 이 문제예요.
이때 쓰는 게 chunksize 옵션이에요. chunksize=10000을 넣으면 한 번에 만 행씩 끊어서 읽어요. 반환값이 데이터프레임이 아니라 TextFileReader라는 이터레이터 객체가 되고, for문으로 순회하면서 청크 단위로 처리하면 돼요.
근데 솔직히 chunksize를 처음 써봤을 때 좀 헷갈렸어요. 청크마다 집계를 따로 하고 나중에 합치는 로직을 짜야 하니까요. 단순히 전체 합계를 구하는 거라면 각 청크의 합을 누적시키면 되는데, 평균 같은 건 단순 평균의 평균이 아니라 전체 합을 전체 개수로 나눠야 해서 살짝 까다로워요.
chunksize 말고 메모리를 절약하는 방법이 또 있어요. 아까 말한 usecols로 필요 없는 열을 아예 안 읽는 거, 그리고 dtype을 명시적으로 지정해서 불필요하게 큰 타입을 쓰지 않는 거예요. 예를 들어 0~255 범위의 정수인데 int64로 읽히면 메모리를 8배나 낭비하는 셈이거든요. dtype={‘점수’: ‘int8’}로 지정하면 확 줄어요.
pandas 공식 문서에서는 C 엔진(기본값)과 pyarrow 엔진도 선택할 수 있다고 안내하고 있어요. engine=’pyarrow’를 쓰면 멀티스레딩을 지원해서 대용량 파일 읽기가 눈에 띄게 빨라지는 경우가 있어요. 다만 일부 옵션이 pyarrow 엔진에서는 지원되지 않을 수 있으니까, 기본 C 엔진에서 문제가 없으면 굳이 바꿀 필요는 없고요.
⚠️ 주의
chunksize를 너무 작게 설정하면 (예: 100) 반복 횟수가 늘어나면서 오히려 전체 처리 시간이 길어질 수 있어요. 보통 10,000~100,000 정도가 적당한데, 자기 컴퓨터 메모리에 맞춰서 조절하는 게 맞아요.
데이터프레임을 다시 CSV로 저장할 때 주의점
read_csv로 데이터를 읽었으면 분석하고 가공한 다음에 다시 저장할 일이 생기죠. 이때 쓰는 게 df.to_csv(‘결과.csv’)예요. 근데 여기서 초보 때 실수하기 쉬운 포인트가 있어요.
to_csv는 기본적으로 인덱스를 함께 저장해요. 그래서 저장된 파일을 엑셀로 열어보면 맨 앞에 0, 1, 2, 3… 이런 의미 없는 숫자 컬럼이 하나 더 붙어 있거든요. 이게 싫으면 index=False를 넣어야 해요. 거의 매번 쓰게 되는 옵션이에요.
한글 데이터를 저장할 때도 인코딩 문제가 또 나와요. to_csv의 기본 인코딩은 utf-8인데, 이 파일을 엑셀에서 바로 열면 한글이 깨져요. 엑셀이 utf-8 BOM을 기대하기 때문이에요. 그래서 엑셀에서도 깨지지 않게 하려면 encoding=’utf-8-sig’를 써야 해요. utf-8-sig는 파일 앞에 BOM(Byte Order Mark)을 붙여줘서 엑셀이 인코딩을 올바르게 인식하게 해주는 거예요.
이거 몰랐을 때 팀원한테 CSV 보냈더니 “한글이 다 깨져있어요”라는 답장을 받았던 적이 있어요. 제 컴퓨터에서는 잘 보여서 뭐가 문제인지 한참 헤맸거든요. 결국 상대방이 엑셀로 열었기 때문이었고, utf-8-sig 하나로 해결됐어요.
그 밖에 sep=’\t’으로 탭 구분 파일로 저장할 수도 있고, columns 파라미터로 특정 컬럼만 골라서 저장할 수도 있어요. mode=’a’를 쓰면 기존 파일 뒤에 이어쓰기도 되고요.
💬 직접 써본 경험
read_csv로 읽고 to_csv로 저장하는 과정을 반복하다 보면, 읽을 때는 encoding=’cp949′, 저장할 때는 encoding=’utf-8-sig’ 이 조합이 가장 안전하더라고요. 한국 공공데이터 + 엑셀 사용 환경이라면 이 패턴을 외워두면 인코딩 문제로 고생할 일이 거의 없어요.
자주 묻는 질문
Q. read_csv와 read_excel은 뭐가 다른가요?
read_csv는 텍스트 기반 CSV 파일을 읽고, read_excel은 .xlsx나 .xls 같은 엑셀 파일을 읽어요. 엑셀 파일을 읽으려면 openpyxl 같은 별도 라이브러리가 추가로 필요하고, 일반적으로 CSV 읽기가 속도가 더 빨라요.
Q. CSV 파일 안에 쉼표가 포함된 데이터가 있으면 어떻게 되나요?
정상적으로 만들어진 CSV라면 쉼표가 포함된 값은 큰따옴표로 감싸져 있어요. pandas의 read_csv는 이 규칙을 자동으로 인식하기 때문에 별도 설정 없이 올바르게 읽어요. quotechar 옵션으로 인용 부호 문자를 변경할 수도 있어요.
Q. read_csv로 URL에서 직접 읽을 수 있나요?
네, http나 https URL을 파일 경로 대신 넣으면 바로 읽어와요. 깃허브의 raw 파일 URL이나 공공데이터 API에서 CSV를 제공하는 경우에 유용해요. 다만 네트워크 상태에 따라 속도 차이가 있을 수 있어요.
Q. pandas 설치는 어떻게 하나요?
터미널이나 명령 프롬프트에서 pip install pandas를 입력하면 돼요. 아나콘다 환경이라면 이미 설치되어 있는 경우가 대부분이에요. 2026년 5월 기준으로 pandas 3.x 버전대가 최신이에요.
Q. TSV 파일도 read_csv로 읽을 수 있나요?
당연히 가능해요. sep=’\t’ 옵션만 추가하면 탭으로 구분된 TSV 파일도 동일하게 읽어요. 또는 pandas에서 별도로 제공하는 read_table() 함수를 써도 되는데, 이 함수는 기본 구분자가 탭이에요.
본 포스팅은 개인 경험과 공개 자료를 바탕으로 작성되었으며, 전문적인 의료·법률·재무 조언을 대체하지 않습니다. 정확한 정보는 해당 분야 전문가 또는 공식 기관에 확인하시기 바랍니다.
pandas read_csv는 한 줄로 CSV를 불러올 수 있는 강력한 함수지만, 인코딩과 데이터 타입을 제대로 지정하지 않으면 예상치 못한 문제가 생겨요. 특히 한국어 데이터를 다룬다면 encoding 옵션은 필수이고, 대용량 파일을 만날 때를 대비해서 chunksize와 usecols도 익혀두면 좋아요.
CSV 읽기에서 겪었던 시행착오나 꿀팁이 있으면 댓글로 공유해주세요. 도움이 되셨다면 블로그 이웃 추가나 공유도 부탁드려요.