본문으로 건너뛰기
김신건의 로그

[Pandas] read_excel / to_excel

· 수정 · 📖 약 2분 · 635자/단어 #python #pandas #io #excel #openpyxl
Pandas read_excel, Pandas to_excel, Excel pandas, 엑셀 pandas, pandas 엑셀 읽기

정의

pandas.read_excel 는 Excel 파일 (.xlsx, .xls) 을 Pandas DataFrame 으로 읽는 함수. pandas.ExcelWriterDataFrame.to_excel 은 역방향 저장을 담당한다.

한국 실무에서 업무 보고서, 정산 파일, 외부 데이터 수신 등에 매우 자주 쓰인다.

의존 라이브러리

형식필요한 패키지
.xlsxopenpyxl
.xls (구형)xlrd (v1.2.0 이하)
.xlsbpyxlsb
.odsodfpy
.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_valuesNA 변환 값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 로드 후 날짜 컬럼이 (문자열) 로 읽혔…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기