Pandas concat拼接DataFrame时莫名多出全NaN重复列如何解决
问题根因
这是非常典型的列名隐藏字符问题,和DataFrame列数无关。
你看到的“所有表列头完全一致”只是视觉上的一致:至少有一个DataFrame的Article ID列名带了肉眼看不到的字符,最常见的是首尾多了空格、制表符,或是爬取RSS内容时混入了零宽空格、全角空格这类不可见特殊字符。pd.concat()是严格按列名字符串的精确值做对齐拼接的,只要列名的字符串值不完全相等,哪怕视觉上看不出区别,也会被识别成两个独立列。匹配不到对应列的行位置会自动填充NaN,最终就会出现你看到的“多了一个同名空列”的现象。
之前用shape只能确认每个表的列数量是8,根本检测不到列名里的隐藏字符,自然查不出问题。
排查方法
直接打印每个DataFrame列名的原始表示,就能立刻定位到隐藏字符的位置,运行以下代码即可:
for idx, df in enumerate(frames): print(f"===== 第{idx+1}个DataFrame的列名 =====") print([repr(col) for col in df.columns])
输出结果里你肯定能看到至少一个Article ID的打印结果和其他的存在差异,比如显示为'Article ID '(末尾多空格)、'Article\u3000ID'(中间为全角空格)这类形式。
解决方案
最稳妥、零踩坑的方案是直接给所有待拼接的DataFrame强制赋值标准列名——既然你已经确认所有表的列顺序、字段含义完全一致,根本不需要纠结列名里藏了什么特殊字符,直接覆盖列名的效率最高,还能顺便避免其他列出现同类问题:
# 定义标准列名,顺序和现有表的列顺序严格对应 standard_columns = ["Source", "Tags", "Date", "Title", "Summary", "Link", "Article ID", "Article Text"] # 遍历重设所有DataFrame的列名 for i in range(len(frames)): frames[i].columns = standard_columns # 拼接时加上ignore_index=True重置行索引,避免行索引重复 result_df = pd.concat(frames, ignore_index=True)
如果你不想强制覆盖列名,也可以批量清洗所有列名的首尾空白、移除常见特殊字符后再拼接:
for i in range(len(frames)): # 去除列名首尾所有空白字符 frames[i].columns = frames[i].columns.str.strip() # 如果排查出有零宽空格类特殊字符,再加一行替换规则即可 # frames[i].columns = frames[i].columns.str.replace(r'[\u200b\u200c\u200d\ufeff]', '', regex=True)
内容的提问来源于stack exchange,提问作者dbgg
相关产品推荐
相关产品推荐

