Pandas df.corrwith计算透视表DF相关系数时返回异常NaN问题
Pandas 1.4.1 corrwith()返回NaN问题说明
问题现象
使用Pandas 1.4.1版本调用df.corrwith()计算两个DataFrame的相关系数时出现不符合预期的结果:形状完全相同的两个DataFrame,手动构造时计算结果正常,数据来自pd.pivot_table()生成的透视表时返回全NaN值,和手动计算结果不符。
复现场景
1. 正常场景
直接构造两个形状为(6,1)、列名均为rating的DataFrame,代码如下:
import pandas as pd import numpy as np aa = np.arange(6,dtype='float64') bb = np.arange(6,dtype='float64') dd1 = {'rating':aa} dd2 = {'rating':bb} df_1 = pd.DataFrame(dd1) df_2 = pd.DataFrame(dd2) print('output of corrwith = \n', df_1.corrwith(df_2,axis=0)) print('df_1.shape = ', df_1.shape) print('df_2.shape = ', df_2.shape) print('-'*80)
运行结果符合预期,返回rating列相关系数为1.0:
output of corrwith = rating 1.0 dtype: float64 df_1.shape = (6, 1) df_2.shape = (6, 1)
2. 异常场景
两个DataFrame形状和正常场景完全一致,唯一区别是数据来自pd.pivot_table()生成的透视表(经fillna(0)填充空值),分别取透视表两列得到df_4、df_5,代码如下:
import pandas as pd import numpy as np dd3 = {'user': [1,2,1,2,3,4,5,1,2,6], 'movie': [1,2,1,3,4,5,6,1,3,2], 'rating':[1,2,1,5,4,3,3,2,1,5] } df_3 = pd.DataFrame(dd3) df_pivot = pd.pivot_table(df_3,index='user',columns='movie',values='rating').fillna(0) print(df_pivot) print('-'*80) df_4 = df_pivot.iloc[:,[1]] df_5 = df_pivot.iloc[:,[2]] print('output of corrwith = \n', df_4.corrwith(df_5,axis=0)) print('df_4.shape = ', df_4.shape) print('df_5.shape = ', df_5.shape) print('-'*80)
运行后返回两个NaN值,手动计算两列相关系数实际约为0.2:
output of corrwith = movie 2 NaN 3 NaN dtype: float64 df_4.shape = (6, 1) df_5.shape = (6, 1)
根本原因
这不是版本bug,是corrwith()的默认匹配规则和直觉预期不一致:axis=0模式下,corrwith()是按列名对齐配对计算,不是按列的位置配对。
- 正常场景中两个DataFrame的列名完全一致,都是
rating,可以成功匹配到计算对,因此返回正确的相关系数1.0。 - 透视表生成的
df_pivot列名是movie字段的取值:df_4是切出来的第2列,列名为2;df_5是切出来的第3列,列名为3。两个DataFrame没有任何重名的列。 - 函数匹配列时,
df_4的列2在df_5中找不到同名列,df_5的列3在df_4中找不到同名列,没有可以计算的有效列对,自然返回全NaN。两个DataFrame形状一致不代表列名能匹配上,和数据来源是不是透视表也没有直接关系。
解决方法
如果需要按位置计算两列的相关系数,任选以下一种方式处理即可:
- 方法1:将两个DataFrame的列名重命名为一致名称,再调用
corrwith()
df_4.columns = ['target_col'] df_5.columns = ['target_col'] print(df_4.corrwith(df_5, axis=0))
- 方法2:直接提取为Series对象计算相关系数,Series计算不依赖名称对齐
print(df_4.iloc[:,0].corr(df_5.iloc[:,0]))
两种方式都可以得到正确结果约0.208。
内容的提问来源于stack exchange,提问作者NNN
相关产品推荐
相关产品推荐

