首页 / Pandas 入门教程 / 合并:concat

Pandas 入门教程

合并:concat

本教程共 54 篇 · 第 33 篇 · 更新于 2026-08-11 · 约 6 分钟阅读

PandasPandas 入门教程concat数据合并ignore_indexkeys

本节目标:会用 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)

用法分三步:

  1. 把要拼的表收进一个列表(一次拼任意多张);
  2. 选方向:axis=0 加行,axis=1 加列;
  3. 按需处理索引: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)
Note

keys 配合 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 才管”配”。