合并:concat
本教程共 54 篇 · 第 33 篇 · 更新于 2026-08-11 · 约 6 分钟阅读
本节目标:会用 pd.concat 上下、左右拼接数据,搞懂 ignore_index、keys、join 参数各自解决什么问题。
concat 是拼接,不是连接
pandas 合并数据有两类工具:concat 是纯拼接,把表简单叠在一起;merge 是按键连接(下一章讲),像 SQL 的 JOIN。
concat 把多个 DataFrame 沿某个轴摞起来。默认 axis=0,上下摞(增加行):
import pandas as pd
df1 = pd.DataFrame({"姓名": ["张三", "李四"], "成绩": [85, 92]})
df2 = pd.DataFrame({"姓名": ["王五"], "成绩": [78]})
result = pd.concat([df1, df2])
print(result)
用法分三步:
- 把要拼的表收进一个列表(一次拼任意多张);
- 选方向:axis=0 加行,axis=1 加列;
- 按需处理索引:ignore_index 重建、keys 加标签。
concat 不要求各表有相同的列或索引——列名对不上不报错,这正是它和 merge 的区别:merge 必须有键,concat 不需要。
concat 也接受 Series。axis=0 拼 Series 就是”首尾相连”,结果是更长的 Series:
s1 = pd.Series([1, 2], name="x")
s2 = pd.Series([3, 4], name="x")
print(pd.concat([s1, s2]))
Warning别在循环里反复 concat——每次都会复制数据,又慢又费内存。先把所有表收进列表,最后统一 concat 一次。
axis=1:左右拼接
axis=1 时按列摞(增加列):
df3 = pd.DataFrame({"城市": ["北京", "上海", "广州"]})
result = pd.concat([df1, df3], axis=1)
print(result)
行数不一致时,多出来的位置自动填 NaN。axis=1 拼 Series 时,有名字的 Series 用名字当列名,没名字的按 0、1、2 编号。
axis=1 拼接时两边出现同名列,结果里列名会重复(比如两个”姓名”)。这时用 df.columns 区分位置,或拼接前先 rename 去重。
join 参数:内外模式
左右拼接时两边行索引对不上,用 join 决定取舍:
- join=“outer”(默认):取两边索引的并集,缺失位置填 NaN;
- join=“inner”:只取交集,两边都有的行才保留。
df4 = pd.DataFrame({"语文": [90, 88]}, index=[0, 2])
result = pd.concat([df1, df4], axis=1, join="inner")
print(result)
上下拼接时 join 作用于列:outer 保留所有列(没有的列填 NaN),inner 只留两边都有的列。看个列对不上的例子:
df5 = pd.DataFrame({"姓名": ["张三"], "城市": ["北京"]})
print(pd.concat([df1, df5]))
df1 有”成绩”、df5 有”城市”,默认 outer 两边列都保留,缺的填 NaN。想要只留公共列,join=“inner”。
Tip想按左边表的索引精确对齐(相当于 left join),拼完再 reindex:pd.concat([df1, df4], axis=1).reindex(df1.index)。这种需求通常用 merge 更顺手。
ignore_index:重建索引
上下拼接时各表索引都从 0 开始,结果索引会重复:
print(pd.concat([df1, df1]))
索引重复以后,df.loc[0] 一次取到两行,很多操作会变得别扭。想要连续的 0..n-1,用 ignore_index=True:
print(pd.concat([df1, df1], ignore_index=True))
ignore_index 只影响拼接轴上的索引,不动列名。它和 keys 可以一起用:先按 keys 分块,再忽略块内的原索引。
keys:给每块数据贴标签
拼接多批数据时,想记住每行来自哪张表,用 keys 生成多级索引:
result = pd.concat([df1, df2], keys=["上学期", "下学期"])
print(result)
索引变成两层:外层是标签,内层是原索引。之后用 result.loc[“上学期”] 取回对应批次。传字典也行:pd.concat({“上学期”: df1, “下学期”: df2}),效果等价。注意 keys 的标签数量和传入的表数量必须一致,少一个都会报错。
外层索引的名字可以指定:
result = pd.concat(
[df1, df2],
keys=["上学期", "下学期"],
names=["批次"],
)
print(result)
Notekeys 配合 axis=1 时,标签加在列上,变成多层列名,适合并排展示几批统计结果。
追加行:append 已移除,用 concat
老教程里的 df.append() 在 pandas 2.0 已移除,统一用 concat。追加一行,先把 Series 转成一行再拼:
new_row = pd.Series({"姓名": "赵六", "成绩": 95})
result = pd.concat([df1, new_row.to_frame().T], ignore_index=True)
print(result)
to_frame() 把 Series 变成一列,.T 转置成一行,再和原表上下拼接。这就是 append 曾经的用法,记住这个组合就行。
追加多行更简单,直接 concat 一个 DataFrame:
new_rows = pd.DataFrame({"姓名": ["赵六", "钱七"], "成绩": [95, 88]})
result = pd.concat([df1, new_rows], ignore_index=True)
print(result)
追加的 DataFrame 列和原表对不上也没关系,缺的列自动填 NaN。
另外,怀疑拼接结果有重复索引时,可以加 verify_integrity=True,有重复就抛 ValueError 提醒。
concat 与 merge 的分工
一句话区分:concat 只管”叠”,不管”配”;merge 才管”配”——按键值匹配行。叠的时候如果两边索引恰好对齐,效果看起来像连接,但语义不同:concat 按标签对齐后堆叠,merge 按键值匹配后合并。
想”把两张表按索引并排”用 concat(axis=1);想”按某列值把信息合到一张表”用 merge。方向选错了,结果往往就是一堆 NaN 或重复列。
小结
concat 是纯拼接:axis=0 加行、axis=1 加列,ignore_index 重建索引、keys 贴批次标签、join 决定内外模式。追加行用 concat + to_frame().T(§06 提过),别再用已移除的 append。一句话:concat 只管”叠”,merge 才管”配”。