
本文介绍如何在 polars 中不依赖 pandas,直接读取含多行表头的 excel 文件,将前 n 行作为复合列名、用指定分隔符拼接后赋给数据行,实现高性能、内存友好的表头扁平化。
本文介绍如何在 polars 中不依赖 pandas,直接读取含多行表头的 excel 文件,将前 n 行作为复合列名、用指定分隔符拼接后赋给数据行,实现高性能、内存友好的表头扁平化。
在实际数据分析中,尤其是处理业务导出的 Excel 报表时,常遇到「多行表头」结构(如第一行为大类 A/B,第二行为子类 one/two)。Pandas 通过 MultiIndex 原生支持该结构,但 Polars 作为列式、惰性计算的高性能 DataFrame 库,并不提供多级列索引。因此,常见做法是“先 Pandas → 扁平化 → 转 Polars → 计算 → 再转回 Pandas”,但这在大数据场景下会引发显著的序列化开销与内存冗余。
幸运的是,Polars 完全可以在不引入 Pandas 的前提下,原生完成多行表头的解析与扁平化——核心思路是:分两次读取 Excel:一次提取表头行构建列名,一次读取数据主体,再动态重命名列。整个过程纯 Polars、零中间转换、完全惰性友好。
✅ 推荐方案:双读取 + 列名拼接(原生 Polars)
以下为完整可运行示例(需安装 fastexcel 或 xlsxwriter):
import polars as pl
# 1. 模拟生成带双行表头的 Excel(仅用于演示;生产中直接读真实文件)
dummy_data = pl.DataFrame([
("A", "one", "1", "5"),
("A", "two", "2", "6"),
("B", "one", "3", "7"),
("B", "two", "4", "8"),
])
dummy_data.write_excel("Book1.xlsx", include_header=False) # 不写入默认表头
# 2. 提取前 N 行作为表头(N_HEADERS = 2)
N_HEADERS = 2
headers_df = pl.read_excel(
"Book1.xlsx",
read_options={"header_row": None, "n_rows": N_HEADERS}
)
# 将每列的 N_ROWS 值纵向拼接(如 ["A","A","B","B"] → "A-A-B-B" ❌ 错误!)
# 正确做法:按行横向拼接 —— 第0行 + 分隔符 + 第1行 → 得到 ["A-one", "A-two", "B-one", "B-two"]
flattened_cols = headers_df.transpose().select(
pl.all().str.join("-") # 关键:transpose 后每列变为一行,join("-") 即拼接该行所有单元格
).transpose().row(0) # 取第一行(即唯一行)作为新列名元组
# 3. 读取剩余数据(跳过表头行),并赋值列名
data_df = pl.read_excel(
"Book1.xlsx",
read_options={
"header_row": None,
"skip_rows": N_HEADERS,
"dtypes": pl.Int64 # 显式指定类型,避免字符串推断
}
)
data_df = data_df.rename(dict(zip(data_df.columns, flattened_cols)))
print(data_df)
输出:
shape: (2, 4) ┌───────┬───────┬───────┬───────┐ │ A-one ┆ A-two ┆ B-one ┆ B-two │ │ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ i64 ┆ i64 │ ╞═══════╪═══════╪═══════╪═══════╡ │ 1 ┆ 2 ┆ 3 ┆ 4 │ │ 5 ┆ 6 ┆ 7 ┆ 8 │ └───────┴───────┴───────┴───────┘
? 关键技巧说明:
transpose()是实现「按行拼接」的核心:它将原始 header 表(2 行 × 4 列)转为(4 行 × 2 列),此时每行对应一个最终列名的两个层级(如["A","one"]),再对每行调用.str.join("-")即得"A-one"。read_options={"header_row": None}禁用自动表头识别,确保精确控制读取逻辑。dtypes显式声明可避免字符串类型带来的后续计算开销与内存浪费。
⚠️ 注意事项与最佳实践
-
性能优势明显:全程无 Pandas 对象创建/转换,尤其适合 GB 级 Excel;
fastexcel引擎读取速度远超openpyxl。 -
分隔符灵活:将
"-"替换为"_"、"."或":"即可适配不同规范(如A.one,A:one)。 -
健壮性增强建议:
- 使用
pl.col("*").cast(pl.String)预处理 header 行,防止空值或数字导致str.join报错; - 对
flattened_cols添加去重与合法性校验(如是否含非法字符、长度是否匹配数据列数); - 若表头含空单元格,可用
pl.all().fill_null("")预填充。
- 使用
- 无需回写 Pandas:若最终需导出带格式 Excel(如合并单元格表头),仍需 Pandas + openpyxl;但仅做数据清洗/聚合时,Polars 全流程闭环即可,彻底规避跨库瓶颈。
综上,Polars 原生支持多行表头扁平化,不仅语法简洁、性能卓越,更契合其「显式、可控、高性能」的设计哲学。告别 Pandas 中转,让数据管道更轻、更快、更可靠。











