公式的numpy协方差和协方差矩阵产生不同的结果
numpy covariance and covariance matrix by formula is producing different results
我生成了一个矩阵,我想得到它的协方差:
test=np.array([4,2,.6,4.2,2.1,.59,3.9,2,.58,4.3,2.1,.62,4.1,2.2,.63]).reshape(5,3)
test
array([[ 4. , 2. , 0.6 ],
[ 4.2 , 2.1 , 0.59],
[ 3.9 , 2. , 0.58],
[ 4.3 , 2.1 , 0.62],
[ 4.1 , 2.2 , 0.63]])
我用numpy函数计算协方差:
np.cov(test)
array([[ 2.92 , 3.098 , 2.846 , 3.164 , 2.966 ],
[ 3.098 , 3.28703333, 3.0199 , 3.3566 , 3.1479 ],
[ 2.846 , 3.0199 , 2.7748 , 3.0832 , 2.8933 ],
[ 3.164 , 3.3566 , 3.0832 , 3.4288 , 3.2122 ],
[ 2.966 , 3.1479 , 2.8933 , 3.2122 , 3.0193 ]])
但这与遵循协方差公式不同:
mean=np.mean(test,0)
np.dot(test-mean,(test-mean).T)/(5-1)
array([[ 0.004104, -0.002886, 0.006624, -0.005416, -0.002426],
[-0.002886, 0.002649, -0.005316, 0.005044, 0.000509],
[ 0.006624, -0.005316, 0.011744, -0.010496, -0.002556],
[-0.005416, 0.005044, -0.010496, 0.010164, 0.000704],
[-0.002426, 0.000509, -0.002556, 0.000704, 0.003769]])
这与 numpy 的计算不符。
事实上,我看了一下 source code,方程式是 (x-m) * (x-m).T.conj() / (N - 1)
,我相信我正在执行。
区别在于np.cov
计算行向量之间的协方差,这就是为什么结果是5*5
而不是3*3
,但是np.mean
计算列向量的平均值,当您执行 test - mean
时,计算也会沿列广播,这与 np.cov
所做的不同,修复将分为两步:
首先,确保计算每一行的平均值,这可以通过简单地转置 test
矩阵来完成:
mean = np.mean(test.T, 0)
然后在计算 x - x_bar
时,重塑平均向量,使负值也沿着行,而且由于被测向量是行向量,维度将是 3
而不是 5
。经过这些修复后,它将给出与 np.cov
一致的结果:
np.dot(test-mean[:, None],(test-mean[:, None]).T)/(3-1)
# array([[ 2.92 , 3.098 , 2.846 , 3.164 , 2.966 ],
# [ 3.098 , 3.28703333, 3.0199 , 3.3566 , 3.1479 ],
# [ 2.846 , 3.0199 , 2.7748 , 3.0832 , 2.8933 ],
# [ 3.164 , 3.3566 , 3.0832 , 3.4288 , 3.2122 ],
# [ 2.966 , 3.1479 , 2.8933 , 3.2122 , 3.0193 ]])
我生成了一个矩阵,我想得到它的协方差:
test=np.array([4,2,.6,4.2,2.1,.59,3.9,2,.58,4.3,2.1,.62,4.1,2.2,.63]).reshape(5,3)
test
array([[ 4. , 2. , 0.6 ],
[ 4.2 , 2.1 , 0.59],
[ 3.9 , 2. , 0.58],
[ 4.3 , 2.1 , 0.62],
[ 4.1 , 2.2 , 0.63]])
我用numpy函数计算协方差:
np.cov(test)
array([[ 2.92 , 3.098 , 2.846 , 3.164 , 2.966 ],
[ 3.098 , 3.28703333, 3.0199 , 3.3566 , 3.1479 ],
[ 2.846 , 3.0199 , 2.7748 , 3.0832 , 2.8933 ],
[ 3.164 , 3.3566 , 3.0832 , 3.4288 , 3.2122 ],
[ 2.966 , 3.1479 , 2.8933 , 3.2122 , 3.0193 ]])
但这与遵循协方差公式不同:
mean=np.mean(test,0)
np.dot(test-mean,(test-mean).T)/(5-1)
array([[ 0.004104, -0.002886, 0.006624, -0.005416, -0.002426],
[-0.002886, 0.002649, -0.005316, 0.005044, 0.000509],
[ 0.006624, -0.005316, 0.011744, -0.010496, -0.002556],
[-0.005416, 0.005044, -0.010496, 0.010164, 0.000704],
[-0.002426, 0.000509, -0.002556, 0.000704, 0.003769]])
这与 numpy 的计算不符。
事实上,我看了一下 source code,方程式是 (x-m) * (x-m).T.conj() / (N - 1)
,我相信我正在执行。
区别在于np.cov
计算行向量之间的协方差,这就是为什么结果是5*5
而不是3*3
,但是np.mean
计算列向量的平均值,当您执行 test - mean
时,计算也会沿列广播,这与 np.cov
所做的不同,修复将分为两步:
首先,确保计算每一行的平均值,这可以通过简单地转置 test
矩阵来完成:
mean = np.mean(test.T, 0)
然后在计算 x - x_bar
时,重塑平均向量,使负值也沿着行,而且由于被测向量是行向量,维度将是 3
而不是 5
。经过这些修复后,它将给出与 np.cov
一致的结果:
np.dot(test-mean[:, None],(test-mean[:, None]).T)/(3-1)
# array([[ 2.92 , 3.098 , 2.846 , 3.164 , 2.966 ],
# [ 3.098 , 3.28703333, 3.0199 , 3.3566 , 3.1479 ],
# [ 2.846 , 3.0199 , 2.7748 , 3.0832 , 2.8933 ],
# [ 3.164 , 3.3566 , 3.0832 , 3.4288 , 3.2122 ],
# [ 2.966 , 3.1479 , 2.8933 , 3.2122 , 3.0193 ]])