R / Richie全部文章 ↑

Python · 3 分钟阅读

Pandas 写入 Excel

2026 年现状:openpyxl 仍是 .xlsx 主力;读 .xls 用 xlrd(2.0 之后只读 .xls 格式)。大文件多 sheet 落盘有三种思路:一次性写完、用 ExcelWriter 增量写、用 pyarrow + Excel 二进制替代(暂不成熟)。本篇用 2.2+ 风格。

准备

pip install "pandas[pyarrow]" openpyxl

openpyxl 是 Pandas 写 .xlsx 的默认引擎。xlsxwriter 适合复杂格式(图表、条件格式)。

最简单的写法

import pandas as pd

df = pd.DataFrame({
    "name": ["Alice", "Bob", "Carol"],
    "age":  [30, 25, 40],
    "city": ["BJ", "SH", "GZ"],
})

df.to_excel("out.xlsx", index=False)

index=False 必加——否则 Pandas 会把 0、1、2 这种索引用作第一列写进去。

多个 sheet

with pd.ExcelWriter("report.xlsx", engine="openpyxl") as w:
    df1.to_excel(w, sheet_name="users", index=False)
    df2.to_excel(w, sheet_name="orders", index=False)
    summary.to_excel(w, sheet_name="summary", index=False)

with 块退出时文件自动关闭,失败也能正确清理。

指定起始单元格

df.to_excel("out.xlsx", sheet_name="data", startrow=2, startcol=1)

把表头从 C3 开始——常用于"先放标题,再放表"的报表模板。

处理大文件

写大 Excel(>100 万行)会遇到两个瓶颈:

  1. 内存:一次性 to_excel 全装进内存再写
  2. 格式:.xlsx 本身对 1,048,576 行有硬限制
# 1) 分块写多个文件
for i, chunk in enumerate(pd.read_csv("big.csv", chunksize=200_000)):
    chunk.to_excel(f"big_part_{i:03d}.xlsx", index=False)

# 2) 落地为 Parquet / CSV,再用 Excel 打开看
df.to_parquet("big.parquet", engine="pyarrow")

真大数据:别用 Excel。Parquet / DuckDB / SQLite 是 2026 年的默认答案。

改样式

Pandas 的样式 API 写起来很啰嗦,复杂格式通常用 openpyxl 直接画:

from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill

with pd.ExcelWriter("styled.xlsx", engine="openpyxl") as w:
    df.to_excel(w, sheet_name="data", index=False)

    ws = w.sheets["data"]
    # 表头加粗 + 背景色
    header_font = Font(bold=True, color="FFFFFF")
    header_fill = PatternFill("solid", fgColor="305496")
    for cell in ws[1]:
        cell.font = header_font
        cell.fill = header_fill

    # 列宽
    ws.column_dimensions["A"].width = 20
    ws.column_dimensions["B"].width = 10

多个 DataFrame 写到同一 sheet

with pd.ExcelWriter("multi.xlsx", engine="openpyxl") as w:
    df1.to_excel(w, sheet_name="all", index=False, startrow=0)
    df2.to_excel(w, sheet_name="all", index=False, startrow=len(df1) + 2)

注意留一行空行(+2 而不是 +1)做分隔。

日期与时区

df = pd.DataFrame({
    "ts": pd.to_datetime(["2026-08-04 10:00", "2026-08-04 11:00"]),
    "val": [1, 2],
})

with pd.ExcelWriter("time.xlsx", engine="openpyxl", datetime_format="YYYY-MM-DD HH:MM:SS") as w:
    df.to_excel(w, index=False)

datetime_format 控制时间列在 Excel 里怎么显示。

只写部分列

df.to_excel("out.xlsx", columns=["name", "age"], index=False)

columns 决定写哪些列 + 顺序。

常见问题

问题 原因 解决
ModuleNotFoundError: openpyxl 没装 pip install openpyxl
第一列多了索引 默认行为 index=False
写中文乱码 多半没事,但 Excel 可能要求 .xlsx 编码 用 .xlsx,避免 .xls
100 万行写失败 xlsx 硬限制 分文件 / 改 Parquet
读回来类型变了 Excel 不保留类型信息 dtype 显式指定

实战:导出一份带样式的月报

import pandas as pd
from openpyxl.styles import Font, PatternFill, Alignment

df = pd.read_parquet("sales.parquet")  # 列式读取,类型完整

# 简单聚合
pivot = (
    df.pivot_table(index="city", columns="month", values="amount", aggfunc="sum")
      .fillna(0)
      .round(0)
)

with pd.ExcelWriter("sales_report.xlsx", engine="openpyxl") as w:
    pivot.to_excel(w, sheet_name="summary")

    ws = w.sheets["summary"]
    header = Font(bold=True, color="FFFFFF")
    fill = PatternFill("solid", fgColor="305496")
    for cell in ws[1]:
        cell.font = header
        cell.fill = fill
        cell.alignment = Alignment(horizontal="center")

    # 数字格式
    for row in ws.iter_rows(min_row=2, max_row=ws.max_row, min_col=2):
        for c in row:
            c.number_format = "#,##0"

一些经验

  • 报表场景:先 Parquet 落盘做计算,最后一步才导 Excel 给非技术同事
  • 复杂样式(条件格式、图表、合并单元格)直接用 openpyxl / xlsxwriter,别死磕 Pandas 风格 API
  • 多个 sheet + 跨 sheet 引用:用 xlsxwriter 写公式最稳
  • Excel 当数据库用:会有"日期被转成 45678 数字"等坑,加载时 parse_dates=

参考