Pandas 2.1.3多索引Join为何意外匹配NaN值?
Pandas多索引join匹配NaN的问题分析
问题描述
使用Pandas 2.1.3版本,尝试基于多索引的部分级别连接两个DataFrame,其中一个DataFrame的索引包含NaN值,得到的连接结果与预期不符。
复现代码
import pandas as pd import numpy as np a = pd.DataFrame({ 'idx_a':['A', 'A', 'B'], 'idx_b':['alpha', 'beta', 'gamma'], 'idx_c': [1.0, 1.0, 1.0], 'x':[10, 20, 30] }).set_index(['idx_a', 'idx_b', 'idx_c']) b = pd.DataFrame({ 'idx_b':['gamma', 'delta', 'epsilon', np.nan, np.nan], 'idx_c': [1.0, 1.0, 1.0, 1.0, 1.0], 'y':[100, 200, 300, 400, 500] }).set_index(['idx_b', 'idx_c']) # 执行连接 c = a.join( b, how='inner', on=['idx_b', 'idx_c'] ) print("DataFrame a:") print(a) print("\nDataFrame b:") print(b) print("\n实际连接结果:") print(c)
实际输出
DataFrame a: x idx_a idx_b idx_c A alpha 1.0 10 beta 1.0 20 B gamma 1.0 30 DataFrame b: y idx_b idx_c gamma 1.0 100 delta 1.0 200 epsilon 1.0 300 NaN 1.0 400 1.0 500 实际连接结果: x y idx_a idx_b idx_c B gamma 1.0 30 100 1.0 30 400 1.0 30 500
预期结果
x y idx_a idx_b idx_c B gamma 1.0 30 100
疑问
为什么join会将非NaN的idx_b='gamma'与idx_b=NaN的行匹配?
原因分析
这是Pandas 2.1.3版本中join方法处理多索引与指定连接键时的异常行为:当使用on参数指定多索引的部分列作为连接键,且另一个DataFrame的索引包含NaN时,内部匹配逻辑出现偏差——错误地仅以idx_c的匹配为依据,忽略了idx_b中非NaN与NaN的不相等性,进而对符合idx_c匹配条件的行执行了笛卡尔积连接。
正常情况下,Pandas的连接操作应该要求所有指定的连接键完全匹配才会合并行,NaN与任何非NaN值都不应被视为相等。但在该场景下,join的多索引对齐逻辑出现了错误。
解决方法
方法1:改用merge方法
通过重置索引为普通列,明确指定连接键执行合并,再重新设置索引:
c = pd.merge(a.reset_index(), b.reset_index(), on=['idx_b', 'idx_c'], how='inner').set_index(['idx_a', 'idx_b', 'idx_c']) print(c)
方法2:过滤NaN索引行
先过滤掉b中包含NaN的索引行,再执行join:
# 过滤idx_b为NaN的行 b_filtered = b[b.index.get_level_values('idx_b').notna()] c = a.join(b_filtered, how='inner', on=['idx_b', 'idx_c']) print(c)
两种方法都能得到预期的正确结果。
内容的提问来源于stack exchange,提问作者tcquinn
相关产品推荐
相关产品推荐

