自学教程 学编程从这里开始

Pandas merge、concat 多表合并详解

说明:本篇为系列教程,区分两个核心合并函数:

  • 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. 避坑清单

  1. merge 关联键有重复值,会产生笛卡尔积(一对多自动展开),注意数据膨胀
  2. concat 上下追加,只看列名,列顺序不影响;列不一样会填充NaN
  3. concat(axis=1) 按索引对齐,不是按业务id,新手极易搞错
  4. merge 大量数据关联前,关联键建议转为category,提速
  5. 多表合并:先concat合并明细,再merge关联维度表,性能更好
  6. 空值:匹配不到的地方统一填充NaN,后续可以 .fillna() 处理
  7. 列名重名:merge设置suffixes,避免列覆盖

8. 扩展:去重

合并后如果存在重复行,用 drop_duplicates()

res = pd.concat([df1,df2],ignore_index=True).drop_duplicates()
标签:

0 条笔记