说明:本篇为系列教程,区分两个核心合并函数:
merge():按关键字关联(类似SQL的JOIN),横向拼接,一对一、一对多匹配concat():按行/按列直接堆叠,不做匹配,单纯上下追加或者左右拼接
附带join()简要说明(底层是merge,基于索引关联)
1. 环境准备 & 测试数据
pip install pandas
import pandas as pd
# 表1:订单主表
df_order = pd.DataFrame({
"order_id": [1001,1002,1003,1004],
"user_id": [1,2,3,4],
"amount": [120,250,88,360]
})
# 表2:用户信息表
df_user = pd.DataFrame({
"user_id": [1,2,3,5],
"username": ["张三","李四","王五","赵六"],
"city": ["杭州","上海","广州","深圳"]
})
# 表3:追加用的新订单表
df_order_new = pd.DataFrame({
"order_id": [1005,1006],
"user_id": [5,1],
"amount": [200,150]
})
2. merge —— 关键字关联(SQL JOIN)
语法
pd.merge(
left,
right,
on=None, # 关联键,两表列名相同
left_on=None, # 左表关联列
right_on=None, # 右表关联列
how="inner", # inner / left / right / outer
suffixes=("_x","_y"), # 重名列后缀
indicator=False, # 新增标记列,标记来自哪边
)
2.1 inner 内连接(默认)
只保留两边匹配成功的数据,交集
res_inner = pd.merge(df_order, df_user, on="user_id", how="inner")
print("inner内连接:")
print(res_inner)
结果:只保留 user_id 同时存在两张表的行,user_id=4、user_id=5 被过滤
2.2 left 左连接(业务最常用)
以左表全部数据为主,右表匹配,匹配不到填充 NaN
res_left = pd.merge(df_order, df_user, on="user_id", how="left")
print("left左连接:")
print(res_left)
订单表全部保留,user_id=4 在用户表没有记录,username、city 为 NaN
2.3 right 右连接
以右表全部数据为主
res_right = pd.merge(df_order, df_user, on="user_id", how="right")
print("right右连接:")
print(res_right)
2.4 outer 全外连接
并集,两边所有数据都保留,匹配不到填充NaN
res_outer = pd.merge(df_order, df_user, on="user_id", how="outer")
print("outer全外连接:")
print(res_outer)
2.5 两表关联字段名字不一样
左表key叫uid,右表key叫user_id,使用 left_on / right_on
df_a = pd.DataFrame({"uid":[1,2,3],"val":[10,20,30]})
df_b = pd.DataFrame({"user_id":[2,3,4],"name":["A","B","C"]})
res = pd.merge(df_a, df_b, left_on="uid", right_on="user_id", how="left")
print(res)
2.6 suffixes 重名字段处理
两张表有同名非关联列,自动加后缀区分
res = pd.merge(df_order, df_user, on="user_id", suffixes=("_order","_user"))
2.7 indicator 标记数据来源
新增 _merge 列:both / left_only / right_only
res = pd.merge(df_order, df_user, on="user_id", how="outer", indicator=True)
print(res)
2.8 多键关联(多个字段同时匹配)
res = pd.merge(df1, df2, on=["region","product"], how="left")
3. concat —— 直接堆叠拼接(无匹配逻辑)
语法
pd.concat(
objs,
axis=0, # 0 按行上下追加(默认);1 按列左右拼接
ignore_index=False, # 是否重置行索引
join="outer", # outer / inner,列对齐策略
)
3.1 axis=0 上下追加(最常用,合并同结构表)
适合多张结构一样的明细表,追加数据
res_concat_row = pd.concat([df_order, df_order_new], axis=0, ignore_index=True)
print("按行追加:")
print(res_concat_row)
✅
ignore_index=True:重新生成连续索引,避免索引重复混乱
3.2 axis=1 左右拼接(按索引对齐)
⚠️ 重点:concat(axis=1) 不是按字段匹配!是按行索引对齐
只有索引一致的行才会并排,索引对不上就出NaN
df1 = pd.DataFrame({"a":[1,2]}, index=[0,1])
df2 = pd.DataFrame({"b":[10,20]}, index=[1,2])
res_concat_col = pd.concat([df1, df2], axis=1)
print(res_concat_col)
业务关联优先用 merge,不要用 concat(axis=1),很容易踩坑
3.3 join 参数:inner / outer
join="outer":保留所有列(默认)join="inner":只保留两边都存在的列
res = pd.concat([df_order, df_order_new], axis=0, join="inner", ignore_index=True)
4. join() 简要说明
df.join(other),基于索引做左连接,底层封装merge
df1 = df_order.set_index("user_id")
df2 = df_user.set_index("user_id")
res = df1.join(df2, how="left")
print(res)
适合索引就是关联键的场景;常规业务优先 merge,可读性更好。
5. merge vs concat 选型对照表
| 函数 | 作用 | 对齐依据 | 类比SQL | 适用场景 |
|---|---|---|---|---|
| merge | 横向关联 | 指定关键字(on) | JOIN | 主表+维度表关联、匹配字段 |
| concat(axis=0) | 上下堆叠 | 列名对齐 | UNION ALL | 多张同结构明细表合并 |
| concat(axis=1) | 左右并排 | 行索引对齐 | 无 | 极少用,索引对齐场景 |
一句话口诀:
要匹配关联用merge,多张表追加数据用concat(axis=0)
6. 高频实战示例
订单表左连接用户表,追加新订单,导出报表
import pandas as pd
df_order = pd.DataFrame({
"order_id": [1001,1002,1003,1004],
"user_id": [1,2,3,4],
"amount": [120,250,88,360]
})
df_user = pd.DataFrame({
"user_id": [1,2,3,5],
"username": ["张三","李四","王五","赵六"],
"city": ["杭州","上海","广州","深圳"]
})
df_order_new = pd.DataFrame({
"order_id": [1005,1006],
"user_id": [5,1],
"amount": [200,150]
})
# 1. 合并所有订单
df_all_order = pd.concat([df_order, df_order_new], axis=0, ignore_index=True)
# 2. 左关联用户信息
df_report = pd.merge(df_all_order, df_user, on="user_id", how="left")
print(df_report)
df_report.to_excel("merge_report.xlsx", index=False)
7. 避坑清单
- merge 关联键有重复值,会产生笛卡尔积(一对多自动展开),注意数据膨胀
- concat 上下追加,只看列名,列顺序不影响;列不一样会填充NaN
- concat(axis=1) 按索引对齐,不是按业务id,新手极易搞错
- merge 大量数据关联前,关联键建议转为category,提速
- 多表合并:先concat合并明细,再merge关联维度表,性能更好
- 空值:匹配不到的地方统一填充NaN,后续可以
.fillna()处理 - 列名重名:merge设置suffixes,避免列覆盖
8. 扩展:去重
合并后如果存在重复行,用 drop_duplicates()
res = pd.concat([df1,df2],ignore_index=True).drop_duplicates()
0 条笔记