结论先行:merge 出问题,八成不是语法错,而是连接键的重复值、dtype 不一致、以及 how 的默认值这三件事。本文用 9 组「症状 → 原因 → 修法」对照表,把 merge 的坑一次说清。
症状:左表 1000 行,右表 500 行,merge 完变 5000 行。
原因:连接键在右表有重复值,一对多会逐行展开。
df_right["key"].duplicated().sum()
r = df_right.drop_duplicates(subset="key", keep="last")
df.merge(r, on="key", how="left")
df.merge(r, on="key", how="left", validate="many_to_one")症状:明明键值一样,右表的列全是 NaN。
原因:dtype 不一致——左表是 int64,右表是从 CSV 读进来的 str,'1001' != 1001。
df_left["key"].dtype, df_right["key"].dtype # int64 vs object
df_right["key"] = df_right["key"].astype(df_left["key"].dtype)场景 | 检查点 |
|---|---|
从 CSV 读 | 数字键是否被读成字符串 |
有前导零 | 编号 |
空值 | 键里混了 |
_x / _y症状:合并后出现 score_x、score_y,不知道哪个是自己的。
原因:两表有同名非键列,pandas 自动加后缀。
r = df_right.rename(columns={"score": "score_2025"})
df.merge(r, on="key", how="left")how 默认 inner,数据被悄悄丢了症状:左表 1000 行,merge 完只剩 800 行。
原因:how 的默认值是 'inner',只保留交集。
how | 结果 |
|---|---|
| 只留两表都有的键 |
| 保留左表全部,右表缺失填 NaN |
| 保留右表全部 |
| 全部保留 |
建议:显式写 how=,别依赖默认值。
on 与索引混用症状:KeyError: 'key',或合并结果不对。
原因:键在索引上而不是列里,得用 left_index=True / right_index=True。
df.merge(r, left_on="key", right_index=True, how="left")症状:原本是整数的 age 列,合并后变成 18.0。
原因:该行没匹配上,填入了 NaN,而 NaN 是浮点,整列被向上转型成 float64。
df["age"] = df["age"].astype("Int64")症状:用 on=["a","b"] 合并,行数比预期少。
原因:多键是按组合匹配的,任一列对不上就整行不匹配。
merged = df.merge(r, on=["a", "b"], how="left", indicator=True)
merged["_merge"].value_counts() # left_only 有多少indicator=True 会加一列 _merge,直接告诉你每行是 both 还是 left_only。
suffixes 没设,后缀撞车症状:多次合并后列名变成 score_x_x。
修法:每次合并显式给后缀。
df.merge(r, on="key", suffixes=("", "_right"), how="left")症状:几百万行合并时卡死或 MemoryError。
原因:merge 前没做三件事——降 dtype、去无用列、去重。
r2 = r[["key", "val"]].copy()
r2["key"] = r2["key"].astype("category")
df.merge(r2, on="key", how="left")症状 | 第一怀疑对象 |
|---|---|
行数暴涨 | 右表键有重复(笛卡尔积) |
全是 NaN | 键 dtype 不一致 |
行数变少 |
|
出现 | 同名列冲突 |
int 变 float | NaN 导致向上转型 |
慢 / 爆内存 | 未降 dtype、未去冗余列 |
记住三句话:merge 前先查键的 dtype 与重复值;how 一定显式写;加上 validate= 和 indicator=True**,让 pandas 替你把错报出来**。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。