how='left'保留左表所有行,右表仅补匹配行,不匹配处填nan;不自动去重或排序,需显式指定on参数,nan键不参与匹配,索引默认重置。

merge函数里how='left'到底做了什么
它让左表的每一行都保留,右表只补上能匹配上的字段;没匹配上的,右表对应列全填NaN。不是“取交集”,也不是“以右表为准”,就是“左表不动,右表来凑”。
常见错误是以为how='left'会自动去重或排序——它不会。如果左表有重复key,结果里就可能出现多行重复;如果右表有多个匹配项,也会被全部展开(即笛卡尔式扩展)。
- 适用场景:查用户基本信息(左表)+ 补充订单记录(右表),要看到所有用户,哪怕没下单
- 右表的
key列如果有重复值,会导致左表某行在结果中出现多次 - 默认按
on指定列对齐;不指定时,会取两表列名交集作为key,容易误匹配
必须显式指定on参数,别依赖自动推断
很多人写pd.merge(df1, df2, how='left')后发现结果列变多了、数据乱了,问题往往出在没设on。Pandas真会拿两个DataFrame的公共列名当连接键,而你可能根本没意识到某列名在两边都存在(比如都叫id,但语义不同)。
更危险的是,如果左右表公共列名不止一个,它会拿全部当复合键——你未必想要这样。
- 安全做法:始终写明
on='user_id'或left_on='uid',right_on='id' - 如果键名不同,必须用
left_on和right_on配对,不能只写一个 -
suffixes=('_left', '_right')建议始终加上,避免同名列被自动改名成col_x/col_y这种难读的名字
性能陷阱:右表没索引时,大表left merge很慢
how='left'本身不改变算法复杂度,但Pandas内部仍需对右表做多次查找。如果右表有百万行且on列没索引,每次匹配都要扫全表——实际是O(n×m)级别。
这不是bug,是设计使然:Pandas merge不做预建哈希索引(除非你手动设validate或用join替代)。
- 提速方法:对右表连接键调用
set_index()再join,比merge快得多(尤其右表远大于左表时) - 或者提前用
df2 = df2.drop_duplicates(subset=['key'])去重,避免无谓膨胀 - 注意:
merge不会警告你右表有重复键,但结果行数可能暴增,得自己核对len(result) / len(left)比值
NULL值怎么参与连接?答案是:默认不匹配
如果左表user_id是NaN,右表也有NaN,它们不会连到一起。merge把NaN当未知值,不等于任何东西(包括另一个NaN)。这是SQL标准行为,也是Pandas的默认逻辑。
有人想“把空值也连上”,结果发现how='left'后左表的NaN行,右表字段全是NaN——没错,这就是对的。
- 需要特殊处理空值?得先用
fillna()占位(如-999),再连,连完再换回来 - 或者改用
combine_first()这类按索引对齐的操作,但它不解决关联逻辑,只适合简单覆盖 - 别指望
how='left'自动帮你补全缺失键的业务含义——那是清洗阶段的事
最常被忽略的一点:merge返回的新DataFrame,索引是默认整数序号,和原表索引无关。如果你依赖左表索引做后续定位(比如df.loc[123]),merge之后这个索引就失效了——得手动用left_index=True保留,或者merge完立刻重设。










