2026-10-02 · 喵窝资源铺
按季度收上来的表格最让人头大的不是「怎么合并」,而是每个文件的列名都不一样:一月的叫「手机」,二月的叫「联系方式」,三月的英文导出叫 Mobile;「姓名/客户名/Name」是同一个人,程序却认成三列。直接 pd.concat 会得到一张歪歪扭扭、同义列散落各处的大宽表。这篇给一个 「列名对照表」方案:先把每个文件的列名归一成标准名,再拼接。本文代码实跑验证,真实输出见下。
需要 pandas + openpyxl(pip install pandas openpyxl)。存为 excel_alias_merge.py,运行 python excel_alias_merge.py 数据文件夹 merged.xlsx。核心就一件事:维护好 ALIAS 这张对照表——左边是统一名,右边是这个统一名在现实里出现过的所有叫法:
"""多个 Excel 列名不统一也能合并:按「列名对照表」先把各文件的列名归一,再拼接。
用法:python excel_alias_merge.py [输入目录] [输出xlsx]"""
import sys, glob, os
import pandas as pd
ALIAS = { # 各种叫法 -> 统一列名(按你的表增删即可)
"姓名": ["名字", "客户名", "联系人", "name"],
"手机号": ["手机", "电话", "联系方式", "tel", "mobile"],
"部门": ["所属部门", "科室", "dept"],
}
def norm(col, rev):
c = str(col).strip()
if c in rev: return rev[c]
return rev.get(c.lower(), c.lower()) # 兜底:自身小写,防止英文列名大小写不一
src = sys.argv[1] if len(sys.argv) > 1 else "."
out = sys.argv[2] if len(sys.argv) > 2 else "merged.xlsx"
rev = {a.lower(): std for std, als in ALIAS.items() for a in als + [std]}
rev.update({std: std for std in ALIAS}) # 精确中文名优先
frames = []
for f in sorted(glob.glob(os.path.join(src, "*.xlsx"))):
df = pd.read_excel(f)
orig = list(df.columns)
df.columns = [norm(c, rev) for c in df.columns]
df["_来源文件"] = os.path.basename(f)
frames.append(df)
print(f"{os.path.basename(f)}: {orig} -> {list(df.columns[:-1])}")
merged = pd.concat(frames, ignore_index=True)
merged.to_excel(out, index=False)
print(f"\n合并 {len(frames)} 个文件 -> {len(merged)} 行 -> {out}")
print("统一后的列:", list(merged.columns[:-1]))
我造了 3 个文件、共 6 条数据,故意让每个文件的列名都不一样:一月是「姓名/手机/部门」,二月是「客户名/联系方式」(还少了部门列),三月是英文导出「Name/MOBILE/所属部门」——注意 MOBILE 是全大写,专坑大小写敏感的匹配。跑一遍:
一月.xlsx: ['姓名', '手机', '部门'] -> ['姓名', '手机号', '部门'] 三月.xlsx: ['Name', 'MOBILE', '所属部门'] -> ['姓名', '手机号', '部门'] 二月.xlsx: ['客户名', '联系方式'] -> ['姓名', '手机号'] 合并 3 个文件 -> 6 行 -> merged.xlsx 统一后的列: ['姓名', '手机号', '部门']
读回来核对,6 条数据全部对位落进统一的三列,缺部门列的二月文件自动补了空值,_来源文件 列还标了每行出处(回头对账特别有用):
姓名 手机号 部门 _来源文件 张三 13812345678 销售 一月.xlsx 李四 13987654321 技术 一月.xlsx Zhao Liu 13566667777 销售 三月.xlsx 小元代订 13699998888 市场 三月.xlsx 张三 13812345678 二月.xlsx 王五 13711112222 二月.xlsx
注意「MOBILE」也被认出来了——匹配前统一转小写,大小写不再是坑。幂等验证:把合并结果再当输入跑一遍,还是 6 行、列不再变——因为已归一的列名在对照表里命中自己,重复运行不会越合越乱。
ALIAS,宁可多写几个同义词;新碰到一种叫法就补一行,这张表会越用越全。Mobile、MOBILE、"手机 "(带空格)在人眼里同一个东西,字符串比对全是 False。所以先 strip() 再统一转小写去查表,一个都不能少。pd.concat 会自动把缺的列补成空值——这正是想要的,而不是报错。想事后统一填充可以再加一行 merged["部门"] = merged["部门"].fillna("未填写")。对照表方式适合「叫法有限、能枚举」的场景。如果各文件列顺序也乱、同一列名在不同文件含义不同、或者要先去重再合并(同一个人出现在多个月份表里),逻辑要再包一层,可以直接找我们代写(见下)。
相关阅读:批量合并 Excel(列名一致版) | 多 CSV 合并去重 | 群接龙转 Excel | Excel 数据清洗常用脚本