对含有空值的数据使用 np.corrcoef
计算 Pearson 和 Spearman 相关系数¶
本文实验探究了 np.corrcoef
在对含有空值的数据计算 Pearson 相关系数和 Spearman 相关系数时的结果。
np.corrcoef
在计算相关系数时,如果数据中存在一个空值,那么空值所在列与其他列的相关系数也会为空值。- 如果需要忽略空值后计算相关系数,可以使用
np.ma.corrcoef
,它的参数allow_masked
默认为True
。当传入一个MaskedArray
对象时,np.ma.corrcoef
会忽略掉其中的空值。 - 在对含有空值的数据使用
argsort().argsort()
对数据进行排序后,空值会被当做最小值,它也会获得一个排序值,空值内部的排序值大小取决于该空值所在的位置。因此,计算 Spearman 相关系数时,需要先手动删除空值。
一列数据全为空值¶
Pearson 相关系数¶
# 创建一个 DataFrame,其中一列全是 NaN
df = pd.DataFrame({"A": np.random.rand(10), "B": np.full(10, np.nan)})
df
A B
0 0.374540 NaN
1 0.950714 NaN
2 0.731994 NaN
3 0.598658 NaN
4 0.156019 NaN
5 0.155995 NaN
6 0.058084 NaN
7 0.866176 NaN
8 0.601115 NaN
9 0.708073 NaN
若某一列全是空值,那么这一列与其他列的相关系数也为空值。
Spearman 相关系数¶
需要注意的是,在对含有空值的数据进行排序后,空值也会获得一个排序值 ,这些排序值的大小取决于该空值所在的位置。例如,下面的 B
列中,原本空值的排序变成了 0, 1, 2, ..., 9
。
# 使用 argsort().argsort() 对数据进行排序
df_ranks = df.apply(lambda x: x.argsort().argsort())
df_ranks
再计算相关系数时,空值的排序值会被当作实际值,因此会影响最终的计算结果。
# 计算 Spearman 相关系数
corr_matrix = np.corrcoef(df_ranks.values, rowvar=False)
print(corr_matrix)
一列数据部分为空值¶
Pearson 相关系数¶
# 创建两列随机数
df = pd.DataFrame({"A": np.random.rand(10), "B": np.random.rand(10)})
# 将 'B' 列的部分值设置为 NaN
df.loc[[0, 1], "B"] = np.nan
df
A B
0 0.020584 NaN
1 0.969910 NaN
2 0.832443 0.292145
3 0.212339 0.366362
4 0.181825 0.456070
5 0.183405 0.785176
6 0.304242 0.199674
7 0.524756 0.514234
8 0.431945 0.592415
9 0.291229 0.046450
对于部分为空值的数据,np.corrcoef
的结果也是 nan
。
如果我们需要忽略空值后计算相关系数,可以使用 np.ma.corrcoef
,它的参数 allow_masked
默认为 True
。当传入一个 MaskedArray
对象时,np.ma.corrcoef
会忽略掉其中的空值。如果某个变量的观测值全为空值,那么结果为 0。
np.ma.corrcoef 的 allow_masked 参数
If True, masked values are propagated pair-wise: if a value is masked in x, the corresponding value is masked in y. If False, raises an exception. Because bias is deprecated, this argument needs to be treated as keyword only to avoid a warning.
masked_data = np.ma.masked_invalid(df.values)
print(masked_data)
print("type: ", type(masked_data))
[[0.020584494295802447 --]
[0.9699098521619943 --]
[0.8324426408004217 0.29214464853521815]
[0.21233911067827616 0.3663618432936917]
[0.18182496720710062 0.45606998421703593]
[0.18340450985343382 0.7851759613930136]
[0.3042422429595377 0.19967378215835974]
[0.5247564316322378 0.5142344384136116]
[0.43194501864211576 0.5924145688620425]
[0.2912291401980419 0.046450412719997725]]
type: <class 'numpy.ma.core.MaskedArray'>
masked_data
中 第 1 行和第 2 行有空值,np.ma.corrcoef
会忽略掉空值所在的行,再计算相关系数。
下面,我们手动将前 2 行删去,再用 np.corrcoef
计算相关系数,可以看到结果与 np.ma.corrcoef
的结果一致。
Spearman 相关系数¶
# 使用 argsort().argsort() 对数据进行排序
df_ranks = df.apply(lambda x: x.argsort().argsort())
df_ranks
可以看到,空值会被当做最小值,并且同为空值的排序取决于空值所在的行号。因此,下面的结果是不准确的。
# 计算 Spearman 相关系数
corr_matrix = np.corrcoef(df_ranks.values, rowvar=False)
print(corr_matrix)
如果想要忽略空值后再计算 Spearman 相关系数,需要手动先将空值删除:
A B
2 0.832443 0.292145
3 0.212339 0.366362
4 0.181825 0.456070
5 0.183405 0.785176
6 0.304242 0.199674
7 0.524756 0.514234
8 0.431945 0.592415
9 0.291229 0.046450
# 计算 Spearman 相关系数
corr_matrix = np.corrcoef(df_no_nan_ranks.values, rowvar=False)
print(corr_matrix)