merge、concat、join:三张表合并搞崩你的不是语法是逻辑

📅 2026/7/5 14:56:50 👁️ 阅读次数 📝 编程学习
merge、concat、join:三张表合并搞崩你的不是语法是逻辑

merge、concat、join:三张表合并搞崩你的不是语法是逻辑

数据分析里很少只用一张表。订单表、用户表、商品表——三张拼一起才能出洞察。

但表合并是 Pandas 新手最容易写错的地方。今天把 concat、merge、join 的区别一次说清。

concat:简单粗暴的拼接

concat 就像在 Excel 里把两张表头一样的表上下贴在一起。

importpandasaspd df1=pd.DataFrame({"A":[1,2],"B":[3,4]})df2=pd.DataFrame({"A":[5,6],"B":[7,8]})# 纵向拼接(默认)result=pd.concat([df1,df2],ignore_index=True)print(result)# A B# 0 1 3# 1 2 4# 2 5 7# 3 6 8# 横向拼接result=pd.concat([df1,df2],axis=1)print(result)

列不一样怎么办?

df1=pd.DataFrame({"A":[1,2],"B":[3,4]})df2=pd.DataFrame({"B":[5,6],"C":[7,8]})# join="outer":取并集,缺的地方填 NaNresult=pd.concat([df1,df2],join="outer")# A B C# 0 1.0 3 NaN# 1 2.0 4 NaN# 0 NaN 5 7.0# 1 NaN 6 8.0# join="inner":取交集,只保留共有的列result=pd.concat([df1,df2],join="inner")# B# 0 3# 1 4# 0 5# 1 6

merge:像 SQL 的 JOIN

# 用户表users=pd.DataFrame({"user_id":[1,2,3,4],"name":["张三","李四","王五","赵六"],"city":["北京","上海","广州","深圳"]})# 订单表orders=pd.DataFrame({"order_id":[101,102,103,104,105],"user_id":[1,2,2,3,5],# 注意:user_id=5 不在用户表里"amount":[150,200,300,100,500]})

四种连接方式:

# inner:只保留两边都有的(交集)result=pd.merge(users,orders,on="user_id",how="inner")print(f"inner:{len(result)}行")# 4行,user_id=5被排除# left:保留左边全部,右边没有的填 NaNresult=pd.merge(users,orders,on="user_id",how="left")print(f"left:{len(result)}行")# 5行,赵六没有订单# right:保留右边全部result=pd.merge(users,orders,on="user_id",how="right")print(f"right:{len(result)}行")# 5行,user_id=5的用户信息是NaN# outer:两边都保留result=pd.merge(users,orders,on="user_id",how="outer")print(f"outer:{len(result)}行")# 6行

怎么选?记住这个:

需求
“所有用户和他们的订单”(用户必须有)left(users 在左)
“有订单的用户信息”inner
“所有用户和所有订单全都要”outer

列名不一样时

users=pd.DataFrame({"uid":[1,2,3],"name":["张三","李四","王五"]})orders=pd.DataFrame({"user_id":[1,2,2],"amount":[150,200,300]})# left_on 和 right_on 分别指定result=pd.merge(users,orders,left_on="uid",right_on="user_id")print(result)# 合并后删掉重复列result.drop(columns=["user_id"],inplace=True)

join:按索引合并

df1=pd.DataFrame({"A":[1,2,3]},index=["a","b","c"])df2=pd.DataFrame({"B":[4,5]},index=["a","c"])# join 按索引合并,默认 leftresult=df1.join(df2,how="left")print(result)# A B# a 1 4.0# b 2 NaN# c 3 5.0

merge 也可以按索引:pd.merge(df1, df2, left_index=True, right_index=True)

合并后数据验证:防丢数据

# 合并前后行数检查print(f"users:{len(users)}, orders:{len(orders)}")result=pd.merge(users,orders,on="user_id",how="left")print(f"合并后:{len(result)}")# 检查有没有丢数据lost_users=set(users["user_id"])-set(result["user_id"])iflost_users:print(f"丢失的用户ID:{lost_users}")# 检查重复ifresult.duplicated(subset=["user_id"]).any():print("警告:有重复的 user_id!")

实战:订单+用户+商品三表联查

# 三张表users=pd.DataFrame({"user_id":[1,2,3],"name":["张三","李四","王五"],"level":["VIP","普通","VIP"]})products=pd.DataFrame({"product_id":[101,102,103],"product_name":["手机","电脑","耳机"],"category":["电子","电子","配件"]})orders=pd.DataFrame({"order_id":[1001,1002,1003,1004,1005],"user_id":[1,1,2,3,2],"product_id":[101,102,101,103,102],"quantity":[1,1,2,5,1],"price":[2999,5999,2999,199,5999]})# 三表合并full=orders.merge(users,on="user_id")\.merge(products,on="product_id")print("=== 完整订单明细 ===")print(full.head())# 分析:各等级用户消费print("\n=== 各等级消费总额 ===")print(full.groupby("level")["price"].sum())# 分析:各品类销量print("\n=== 各品类销量 ===")print(full.groupby("category")["quantity"].sum())# 各用户最常买的品类print("\n=== 用户偏好 ===")pref=full.groupby(["name","category"])["quantity"].sum()print(pref)

新手常见坑

坑1:合并后行数变多

# 右表有重复的关联键 → 行数膨胀# 比如一个用户有3条订单,合并后这个用户出现3次# 这是正常的,但要注意检查print(f"合并前行数:{len(df1)}+{len(df2)}={len(df1)+len(df2)}")print(f"合并后行数:{len(result)}")

坑2:关联键类型不一致

# df1 的 id 是 int,df2 的 id 是 str → 合并不上!df1["id"]=df1["id"].astype(str)# 或者df2["id"]=df2["id"].astype(int)

坑3:concat 时列顺序不对

# 列名对不上会创建新列# 先统一列名df2.columns=df1.columns result=pd.concat([df1,df2])

动手试试

  1. 创建两张表,用 merge 做 inner join 并检查结果
  2. 把三个 CSV 文件用 concat 拼成一个
  3. 做一个三表联查的分析,输出汇总结果

写在最后

表合并是数据分析的基本功。三点建议:

  1. 合并前print(len(df))确认行数
  2. 合并后检查有没有丢数据
  3. 搞清楚 inner/left/right/outer 的区别,别瞎试

下一篇开始画图——Matplotlib 入门。