使用df.corrwith(axis=1)计算行Pearson相关系数返回空值排查
解决pandas corrwith(axis=1)返回空值的问题
我碰到过好几个用户遇到同样的问题——以为corrwith(axis=1)会逐行计算两个DataFrame的Pearson相关系数,结果却全是NaN,但Excel的CORREL却能算出值。这里的问题大概率出在pandas corrwith的行为逻辑或者数据对齐/格式上,咱们一步步拆解解决:
为什么你的corrwith返回空值?
先搞清楚corrwith(axis=1)的真实作用:它要求两个DataFrame的行索引完全匹配,且列数一致,然后才会计算每一行对应位置的系列相关系数。如果满足不了这两个前提,或者每行数据存在以下情况,就会返回NaN:
- 两个DataFrame的行索引不匹配,对齐后没有重叠的行;
- 某一行的两个系列(df_A的行和df_B的行)中有一个/两个的方差为0(比如整行都是同一个值);
- 某一行的非NaN值不足2个,无法计算相关系数;
- 列数不一致,导致无法生成等长的系列来计算相关系数。
而Excel的CORREL会自动忽略单元格中的NaN,且只要有至少2对非空值就能计算,这也是它能出结果的原因。
解决方案:用更可靠的逐行计算方式
与其依赖corrwith的对齐逻辑,不如直接手动实现逐行的Pearson相关系数计算,这样更可控:
方法1:用scipy.stats逐行计算(易读性高)
import pandas as pd import scipy.stats as stats # 先确保两个DataFrame的行索引一致(重置索引避免对齐问题) df_A = df_A.reset_index(drop=True) df_B = df_B.reset_index(drop=True) def calculate_row_corr(row_a, row_b): # 过滤掉两行中任意一个为NaN的位置 valid_mask = ~row_a.isna() & ~row_b.isna() filtered_a = row_a[valid_mask] filtered_b = row_b[valid_mask] # 至少需要2个有效数据点才能计算相关系数 if len(filtered_a) < 2: return None # 检查方差是否为0(避免除以0错误) if filtered_a.var() == 0 or filtered_b.var() == 0: return None # 返回Pearson相关系数(scipy的pearsonr返回系数和p值,取第一个) return stats.pearsonr(filtered_a, filtered_b)[0] # 逐行应用函数生成结果 corr_series = pd.Series( [calculate_row_corr(df_A.iloc[i], df_B.iloc[i]) for i in range(len(df_A))], index=df_A.index, name="Pearson_Correlation" )
方法2:用numpy批量计算(效率更高,适合大数据集)
如果你的DataFrame行数很多,用循环会比较慢,可以用numpy实现向量化计算:
import pandas as pd import numpy as np # 转换为numpy数组 a_np = df_A.to_numpy() b_np = df_B.to_numpy() # 计算每行的均值(忽略NaN) mean_a = np.nanmean(a_np, axis=1, keepdims=True) mean_b = np.nanmean(b_np, axis=1, keepdims=True) # 计算协方差分子 covariance = np.nansum((a_np - mean_a) * (b_np - mean_b), axis=1) # 计算标准差的乘积(分母) std_a = np.sqrt(np.nansum((a_np - mean_a)**2, axis=1)) std_b = np.sqrt(np.nansum((b_np - mean_b)**2, axis=1)) # 计算相关系数,处理分母为0的情况(返回NaN) corr_array = np.where((std_a == 0) | (std_b == 0), np.nan, covariance / (std_a * std_b)) # 转换为pandas Series corr_series = pd.Series(corr_array, index=df_A.index, name="Pearson_Correlation")
验证结果是否和Excel一致
运行上面的代码后,你可以取几行和Excel的CORREL结果对比,应该就能匹配上了。如果还是有差异,检查一下:
- 是否Excel中某些行的NaN被你手动忽略了?
- 两个DataFrame的对应行数据是否完全一致(比如有没有导入时的格式错误)?
内容的提问来源于stack exchange,提问作者Gautham Kanthasamy
相关产品推荐
相关产品推荐

