用 pandas.concat() 合并多个 .xlsx 文件前必须统一列结构,否则因列名不一致、顺序错乱、表头偏移、类型混杂等问题导致大量 nan 或失败;需预处理识别真实表头、标准化列名、reindex 对齐、动态读取 sheet、添加来源标记、控制内存与 dtype、优化输出格式,并妥善处理路径和异常。

用 pandas.concat() 合并多个 .xlsx 文件前必须统一列结构
直接 pandas.concat() 多个 Excel 文件大概率失败,不是因为数据量大,而是因为列名不一致、顺序错乱、空行/表头偏移、甚至同一列在不同文件里类型不一致(比如有的是字符串“N/A”,有的是 NaN,有的是空字符串)。pandas 默认按列名对齐,列名稍有差异(如 "Order ID" vs "order_id")就会生成大量 NaN,后续清洗成本远高于预处理。
实操建议:
- 先用
pd.read_excel(file, nrows=5)扫描每个文件前几行,人工或正则识别真实表头所在行(常见于第 3–6 行),避免误读合并标题或说明文字 - 对每个文件显式指定
header=参数,例如header=4;不要依赖header='infer' - 统一列名:读入后立刻执行
df.columns = df.columns.str.strip().str.replace(r'[\s\W]+', '_', regex=True).str.lower(),把“客户名称 ”、“客户-名称”都转成ke_hu_ming_cheng - 用
df.reindex(columns=standard_cols, fill_value=pd.NA)强制对齐字段,standard_cols是你从所有文件中归纳出的完整字段集合
处理含多张 sheet 的 Excel 工作簿时,别默认只读 Sheet1
上百个工作簿里,很可能有些是 Summary 在第一页,有些是 Data 在第二页,还有些带隐藏 sheet 或仅含格式模板。硬编码 sheet_name="Sheet1" 会漏掉关键数据,且不报错——pandas 静默跳过不存在的 sheet 名。
实操建议:
- 用
pd.ExcelFile(file).sheet_names获取实际可用 sheet 列表,再按业务规则筛选,例如[s for s in sheets if "data" in s.lower() or "raw" in s.lower()] - 若需合并同一工作簿内多个 sheet,先用
pd.concat([pd.read_excel(file, sheet_name=s) for s in target_sheets], ignore_index=True),注意加ignore_index=True,否则索引重复导致loc查找失效 - 为每条记录打上来源标记:
df["source_file"] = os.path.basename(file); df["source_sheet"] = s,后期溯源排查必备
内存爆掉?用 chunksize 和 dtype 控制单次加载量
一个 20MB 的 Excel 文件,用 pd.read_excel() 读入后常膨胀到 150MB+ 内存占用,尤其含长文本、混合类型列。合并上百个时,Python 很可能触发 MemoryError,而不是慢——它根本跑不完。
实操建议:
- 对超大单文件,改用
openpyxl流式读取(不推荐全量加载);更现实的是提前用 Excel 或xlwings拆分原始文件,或要求上游导出为 CSV - 强制指定
dtype:例如dtype={"order_id": "string", "amount": "float32", "status": "category"},避免 pandas 自动推断成object或float64 - 如果必须逐块处理,
pandas对 Excel 不支持chunksize,但可改用openpyxl读取指定行范围,再转pd.DataFrame,代价是失去自动类型推断
写入最终合并结果时,to_excel() 默认不压缩,文件体积爆炸
合并后 DataFrame 写入新 Excel,用默认参数生成的文件可能比原始所有文件加起来还大——因为 openpyxl 后端默认保存全部样式、空行、冗余格式信息,且不启用 ZIP 压缩。
实操建议:
- 用
engine="xlsxwriter"替代默认的openpyxl,它更快、更轻量,且默认禁用无用格式 - 显式关闭格式保留:
ExcelWriter(..., engine_kwargs={"options": {"strings_to_numbers": True}}) - 若结果仅用于分析,优先输出为
.parquet:df.to_parquet("merged.parquet", compression="snappy"),体积通常只有 Excel 的 1/5,且读取快 3–10 倍
最易被忽略的一点:路径中含中文或空格时,glob.glob("data/*.xlsx") 在 Windows 下可能返回空列表,应改用 pathlib.Path("data").glob("*.xlsx"),它对编码和特殊字符更鲁棒。另外,务必在循环开头加 try...except 包裹单个文件处理逻辑,用 logging.warning(f"跳过 {file}: {e}") 记录异常,别让一个损坏文件中断整个流程。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











