[Pandas] read_excel / to_excel
Pandas read_excel, Pandas to_excel, Excel pandas, 엑셀 pandas, pandas 엑셀 읽기
정의
pandas.read_excel 는 Excel 파일 (.xlsx, .xls) 을 Pandas DataFrame 으로 읽는 함수. pandas.ExcelWriter 와 DataFrame.to_excel 은 역방향 저장을 담당한다.
한국 실무에서 업무 보고서, 정산 파일, 외부 데이터 수신 등에 매우 자주 쓰인다.
의존 라이브러리
| 형식 | 필요한 패키지 |
|---|---|
.xlsx | openpyxl |
.xls (구형) | xlrd (v1.2.0 이하) |
.xlsb | pyxlsb |
.ods | odfpy |
.xlsx (고속) | calamine (pandas 2.2+) |
pip install openpyxl # 기본 xlsx 지원
pip install python-calamine # 대용량 고속 읽기
읽기 흐름
flowchart TD
F["Excel 파일"] --> E{"engine 선택"}
E -->|".xlsx"| OP["openpyxl"]
E -->|".xls"| XL["xlrd"]
E -->|"고속"| CA["calamine"]
OP & XL & CA --> P["pandas 내부 파서"]
P --> D["DataFrame"]
D --> Q{"후처리 필요?"}
Q -->|"병합 셀"| FF["ffill()"]
Q -->|"멀티 헤더"| MH["header=list"]
Q -->|"dtype 교정"| DT["astype / dtype="]
Q -->|"완료"| OK["분석 시작"]
기본 사용
import pandas as pd
df = pd.read_excel('data.xlsx') # 첫 시트
df = pd.read_excel('data.xlsx', sheet_name='Sheet2')
df = pd.read_excel('data.xlsx', sheet_name=0) # 0번째 시트
핵심 옵션
| 옵션 | 의미 | 예시 |
|---|---|---|
sheet_name | 시트 이름/번호, None = 모든 시트 | sheet_name='Sales' |
header | 헤더 행 위치, None = 헤더 없음 | header=2 |
skiprows | 건너뛸 행 | skiprows=5 |
usecols | 열 범위 또는 이름 리스트 | usecols='A:D' |
dtype | 컬럼별 타입 | dtype={'id': str} |
parse_dates | 날짜 파싱 | parse_dates=['date'] |
na_values | NA 변환 값 | na_values=['-', 'N/A'] |
nrows | 읽을 행 수 | nrows=1000 |
engine | 파서 엔진 | engine='calamine' |
여러 시트 한 번에
python
# 모든 시트를 dict[name -> DataFrame] 으로
sheets = pd.read_excel('multi.xlsx', sheet_name=None)
print(list(sheets.keys()))
print(sheets['Sales'].shape) 결과
['Sales', 'Returns', 'Inventory']
(1234, 8)# 특정 시트 여러 개 선택
sheets = pd.read_excel('data.xlsx', sheet_name=['Jan', 'Feb', 'Mar'])
combined = pd.concat(sheets.values(), keys=sheets.keys())
일부 영역만
# A1:D100 영역만
df = pd.read_excel('data.xlsx',
usecols='A:D',
nrows=100,
skiprows=5,
)
# 컬럼명으로 선택
df = pd.read_excel('data.xlsx',
usecols=['날짜', '매출', '비용'],
)
dtype 다루기
Excel 자동 타입 추론을 방어하는 패턴.
# 문자로 봐야 하는 컬럼 (주민번호, 전화번호 등)
df = pd.read_excel('data.xlsx', dtype={
'phone': str,
'code': str,
'amount': float,
})
# 날짜 컬럼 파싱
df = pd.read_excel('data.xlsx', parse_dates=['order_date', 'ship_date'])
# 읽은 후 변환
df['date'] = pd.to_datetime(df['date'], format='%Y%m%d', errors='coerce')
실전 패턴
병합 셀 처리
df = pd.read_excel('report.xlsx')
# 병합 셀: 첫 셀에만 값, 나머지는 NaN
# forward fill 로 복원
df['department'] = df['department'].ffill()
df['quarter'] = df['quarter'].ffill()
멀티 헤더
# 1, 2행이 모두 헤더인 경우
df = pd.read_excel('data.xlsx', header=[0, 1])
# 결과: MultiIndex columns
df.columns.get_level_values(0) # 첫 번째 헤더 레벨
df.columns.get_level_values(1) # 두 번째 헤더 레벨
# 납작하게 펼치기
df.columns = ['_'.join(col).strip() for col in df.columns.values]
헤더가 없는 파일
df = pd.read_excel('raw.xlsx', header=None)
df.columns = ['id', 'name', 'amount', 'date']
특정 행부터 시작
# 3행이 실제 데이터 시작 (0번째 행이 주석, 1번째가 빈 행, 2번째가 헤더)
df = pd.read_excel('data.xlsx', skiprows=2, header=0)
저장 (to_excel)
df.to_excel('out.xlsx', index=False, sheet_name='데이터')
# 여러 시트
with pd.ExcelWriter('out.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sales', index=False)
df2.to_excel(writer, sheet_name='Returns', index=False)
ExcelWriter 심화
# 기존 파일에 시트 추가 (openpyxl 사용)
with pd.ExcelWriter('existing.xlsx', engine='openpyxl', mode='a') as writer:
df_new.to_excel(writer, sheet_name='NewSheet', index=False)
# 시작 행/열 오프셋
with pd.ExcelWriter('report.xlsx') as writer:
df.to_excel(writer, sheet_name='Report', startrow=3, startcol=1, index=False)
# 서식 추가 (xlsxwriter)
with pd.ExcelWriter('styled.xlsx', engine='xlsxwriter') as writer:
df.to_excel(writer, sheet_name='Report', index=False)
workbook = writer.book
worksheet = writer.sheets['Report']
money_fmt = workbook.add_format({'num_format': '#,##0', 'bold': False})
date_fmt = workbook.add_format({'num_format': 'yyyy-mm-dd'})
worksheet.set_column('B:B', 14, money_fmt)
worksheet.set_column('C:C', 12, date_fmt)
성능: 대용량 파일
# pandas 2.2+: calamine 엔진 (C 구현, openpyxl 대비 10배+)
df = pd.read_excel('large.xlsx', engine='calamine')
# 필요한 열만 읽기
df = pd.read_excel('large.xlsx', usecols='A:F', nrows=50_000, engine='calamine')
| 엔진 | 속도 | 특징 |
|---|---|---|
openpyxl (기본) | 보통 | 서식 읽기, 쓰기 모두 지원 |
calamine | 빠름 | 읽기 전용, pandas 2.2+ |
xlrd | 보통 | .xls 전용 |
xlsxwriter | - | 쓰기 전용, 서식 강점 |
TIP
100MB 이상의 Excel 이라면 CSV 나 Parquet 으로 변환 후 사용하는 것이 훨씬 빠르다. Excel 자체가 압축된 XML 이라 파싱 비용이 크다.
함정
1. Excel 자동 타입 추론
- 숫자처럼 보이는 문자 (
'0001') 가 정수로 변환됨 - 날짜처럼 보이는 문자가
datetime으로 변환됨 - 해법:
dtype={'col': str}명시
2. 큰 파일 성능
- Excel 은 압축된 XML 이라
read_csv보다 훨씬 느리다 - 가능하면 CSV / Parquet 사용 권장
- 정 Excel 이 필요하면
engine='calamine'(pandas 2.2+)
3. 병합된 셀
- 병합된 셀은 첫 셀에만 값, 나머지는
NaN - 해법:
df.ffill()로 forward fill
4. 시트 이름의 한글
- 일부 환경에서 한글 시트명이 깨질 수 있음
engine='openpyxl'로 명시
5. 날짜가 정수로 읽힘
# Excel 날짜 직렬화 숫자 (1900-01-01 기준)
# parse_dates 가 실패하는 경우
df['date'] = pd.TimedeltaIndex(df['date'], unit='d') + pd.Timestamp('1900-01-01')
WARNING
openpyxl 로 파일을 열 때 비밀번호 보호된 파일이나 매크로가 포함된 .xlsm 은 읽기 실패할 수 있다. 파일을 미리 열어 저장한 뒤 사용하라.
관련 위키
이 글의 용어 (6개)
- [Pandas] DataFramepandas
- 정의 은 2차원 레이블 테이블. 각 열이 , 모든 열이 같은 (행 라벨) 를 공유. SQL 테이블 / Excel 시트 / R data.frame 의 Python 대응체. 구조 시…
- [Pandas] DataFrame.stylepandas
- 정의 는 HTML/CSS 기반 서식을 DataFrame 에 적용하는 API. Jupyter 노트북, 보고서, Excel 출력에 활용. 데이터 자체는 변하지 않고 표시만 바뀐다. …
- [Pandas] dropna / fillnapandas
- 정의 - : NaN 이 있는 행/열 제거 - : NaN 을 특정 값으로 대체 데이터 분석의 가장 기본적인 결측치 처리. 사용 상황 - CSV 로드 후 빈 셀이 NaN 으로 읽혔을…
- [Pandas] read_csv / to_csvpandas
- 정의 는 CSV(Comma-Separated Values) 또는 구분자 기반 텍스트 파일을 DataFrame 으로 읽는 함수. pandas 사용의 출발점. 반대 방향은 : Dat…
- [Pandas] read_parquet / to_parquetpandas
- 정의 Parquet 은 column-oriented binary 포맷. CSV 대비 수십 배 빠르고 작다. dtype 보존, 압축, 부분 컬럼 읽기 지원. 데이터 분석의 사실상 …
- [Pandas] to_datetimepandas
- 정의 는 문자열, 정수, dict, DataFrame 컬럼을 타입으로 변환한다. pandas 시계열 작업의 출발점. 사용 상황 - CSV 로드 후 날짜 컬럼이 (문자열) 로 읽혔…
💬 댓글