我找不到能为数据中存在NaN的数组计算相关系数矩阵的函数,该数组包含两个以上变量的观测值。有一些函数可以对成对的变量(或者只是使用?is.nan()掩盖数组)。但是通过遍历大量变量来使用这些功能,计算每对变量的相关性可能非常耗时。
因此,我自己尝试一下,很快意识到这样做的复杂性是对协方差的正确归一化的问题。您的意见我将非常感兴趣。
这是代码:
def nancorr(X,nanfact=False):
X = X - np.nanmean(X,axis=1,keepdims = True)*np.ones((1,X.shape[1]))
if nanfact:
mask = np.isnan(X).astype(int)
fact = X.shape[1] - np.dot(mask,mask.T) - 1
X[np.isnan(X)] = 0
if nanfact:
cov = np.dot(X,X.T)/fact
else:
cov = np.dot(X,X.T)
d = np.diag(cov)
return cov/np.sqrt(np.multiply.outer(d,d))
该函数假定每一行都是一个变量。它基本上是numpy的corrcoeff()中的调整后代码。
我相信可以通过以下三种方式进行:
(1)对于每对变量,您只能采用一个变量都不是NaN的那些观测值。如果您想同时进行多对计算并且上面的代码中没有涉及,那么这无疑是最准确,也是最困难的编程。但是,为什么仅仅因为另一个变量的对应项是NaN而丢弃每个变量的均值和方差的信息?因此,还有两个选择。
(2)我们用它的nanmean来淡化每个变量,而每个变量的方差就是它的不变性。对于协方差,其中一个变量或另一个变量为NaN而不是两者均是NaN的每个观察值都是无协变量的观察值,因此将其设置为零。则协方差的因子为1 /(观察数,其中两个变量都不都是NaN-1),用n表示。相关系数的分母中的两个方差均由其对应的非NaN观测值减去1分别表示,分别由n1和n2表示。这可以通过在上面的函数中设置nanfact = True来实现。
(3)可能希望协方差和方差具有与没有NaNs的相关系数相同的因子。在这里执行此操作的唯一有意义的方法(如果选项(1)不可行)是简单地忽略(1 / n)/ sqrt(1 / n1 * n2)。由于此数字小于1,因此估计的相关系数(在绝对值上)将比(2)中的大,但将保持在-1,1之间。这可以通过设置nanfact = False来实现。
我会对您对方法(2)和(3)的意见非常感兴趣,尤其是,我非常希望看到不使用循环的(1)解决方案。
我认为您正在寻找的方法是pandas中的corr()。 例如,如下所示的数据框。 您也可以参考此问题。 如何有效地获取具有NaN值的数据帧的相关矩阵(具有p值)?
import pandas as pd
df = pd.DataFrame({'A': [2, None, 1, -4, None, None, 3],
'B': [None, 1, None, None, 1, 3, None],
'C': [2, 1, None, 2, 2.1, 1, 0],
'D': [-2, 1.1, 3.2, 2, None, 1, None]})
df
A B C D
0 2 NaN 2 -2
1 NaN 1 1 1.1
2 1 NaN NaN 3.2
3 -4 NaN 2 2
4 NaN 1 2.1 NaN
5 NaN 3 1 1
6 3 NaN 0 NaN
rho = df.corr()
rho
A B C D
A 1.000000 NaN -0.609994 -0.441784
B NaN 1.0 -0.500000 -1.000000
C -0.609994 -0.5 1.000000 -0.347928
D 0.041204 -1.0 -0.347928 1.000000
因此,熊猫显然提供了我在上述选项(1)下描述的内容。 也就是说,在计算成对相关性时,它仅使用在两个相应列中均不是Nan的观察值-甚至用于计算均值和方差。 我上面没有提到的另一个问题是,我不确定这是否保证半正定Cov。 顺便说一句,您似乎为示例数据框提供了错误的corr矩阵。 例如。 C,D条目应显示为-0.347928。
更正了corr-matrix结果。
对于带有nans的数组,panda.corr的速度很慢。 它基本上是一个手写的python循环。