含NaN值分组列的Pandas Transform问题:两种分位数写法差异解析
问题原因分析
这个差异的根源在于pandas 0.25.2版本中groupby.transform对内置函数和自定义lambda函数的处理逻辑不同,再加上默认的dropna=True分组行为共同导致的:
- 默认分组行为:pandas 0.25.x中
groupby的dropna参数默认是True,也就是会自动排除分组键中包含NaN的行。当你设置df.loc[df.CUR=='SEK','ISSUER_INDUSTRY'] = numpy.nan后,原来的2条SEK数据会被排除在分组之外,只剩下NOK-BANK这一个有效分组(3行数据)。 - 内置函数
transform('quantile')的处理:当你使用字符串指定内置聚合函数时,pandas会自动为那些被排除的行填充NaN,最终返回的结果长度和原DataFrame完全一致(5行),所以不会报错。 - lambda函数
transform(lambda x: x.quantile(0.9))的处理:而使用自定义lambda函数时,pandas只会返回有效分组内的计算结果(这里是3个值),但原DataFrame有5行,就会触发Length mismatch的错误——因为transform期望返回的结果长度要和原数据匹配。
解决办法
最简单的修复方式就是在groupby时显式设置dropna=False,让NaN被当作一个合法的分组键,这样所有行都会被纳入分组计算,lambda函数的transform结果就能正确对齐原DataFrame的行数:
df['above_90_quantile_profit'] = df.PROFIT >= df.groupby(['CUR','ISSUER_INDUSTRY'], dropna=False).PROFIT.transform(lambda x: x.quantile(0.9))
这样处理后,分组会包含NOK-BANK和SEK-NaN两个组,lambda计算每个组的90分位数后,transform会将结果映射回原DataFrame的每一行,长度匹配就不会报错了。
另外补充一点:在pandas 1.0+版本中,groupby的dropna参数默认改为False,这个问题就不会再出现了——如果你有升级pandas的需求,升级到新版本也能解决这个问题。
内容的提问来源于stack exchange,提问作者hirolau
相关产品推荐
相关产品推荐

