结合网络上关于协方差矩阵的公式推导和numpy库使用,实现协方差矩阵的计算,确切地说是相关系数矩阵。
协方差反映的是两个随机变量之间的线性相关程度,将程度值归一化到一个[-1, 1]的范围区间内,就得到相关系数,以便于理解和评估线性相关程度。特别注意:是线性相关。当一个随机变量变大,另一个随机变量也会变大,这就是正相关,相关系数会在[0, 1]之间,反之,如果在[-1, 0]之间,就是负相关。如果两个随机变量满足kx + b这样的严格线性关系,那么k>0时,相关系数为1,k<0时,相关系数为-1。
计算公式:
一个随机变量与自身的协方差,就是方差:
协方差归一化后的相关系数,更便于多个随机变量之间的比较,相关系数公式为:
在实际中,通常我们手头会有一些样本,样本有多个属性,每个样本可以看成一个多维随机变量的样本点,我们需要分析两个维度之间的线性关系。协方差及相关系数是度量随机变量间线性关系的参数,由于不知道具体的分布,只能通过样本来进行估计。
设样本对应的多维随机变量为,样本集合为,与样本方差的计算相似,a和b两个维度样本的协方差公式为:
这里分母为m−1是因为随机变量的数学期望未知,以样本均值代替,自由度减一。
python函数实现协方差、相关系数、协方差矩阵等:
import numpy as np
X = np.arange(10, dtype=np.float32)
#Y = 2 * X + 1 * np.random.rand(10)
Y = 2 * np.exp(X) + 1 * np.random.rand(10)
def variance(l):
avg = sum(l)/len(l)
return sum((avg - i)**2 for i in l) / (len(l)-1)
def covariance(a, b):
avg_a = sum(a) / len(a)
avg_b = sum(b) / len(b)
return sum((ai - avg_a) * (bi - avg_b) for ai, bi in zip(a,b)) / (len(a)-1)
def conv_matrix(*arr):
"""计算协方差矩阵,其实是计算相关系数矩阵"""
matrix = np.array(arr, dtype=np.float32)
for i,a in enumerate(matrix):
avg = np.average(a)
var = variance(a)
#matrix[i] = (a - avg) #不归一化就是协方差矩阵,归一化就是相关系数矩阵
matrix[i] = (a - avg) / var ** 0.5
rowNum, colNum = matrix.shape
resM = np.zeros((rowNum, rowNum), dtype=np.float32)
for f in range(colNum):
t = matrix[:,f]
squareMat = np.row_stack([t] * len(t))
resM += squareMat * squareMat.T
resM /= colNum - 1
print(resM)
print(X, Y)
varX = variance(X)
print(varX)
varY = variance(Y)
print(varY)
res = covariance(X, Y) / (varX * varY) ** 0.5
print(res)
conv_matrix(X, Y, X)
输出为:
[0. 1. 2. 3. 4. 5. 6. 7. 8. 9.] [2.28564822e+00 6.12990148e+00 1.51675016e+01 4.11676113e+01
1.09295178e+02 2.96868290e+02 8.06930621e+02 2.19363561e+03
5.96228109e+03 1.62062138e+04]
9.166666666666666
26446060.727093935
0.7168583584644617
[[0.9999999 0.7168583 0.9999999]
[0.7168583 1.0000001 0.7168583]
[0.9999999 0.7168583 0.9999999]]
当然,numpy函数库本身也提供了协方差矩阵的计算函数,使用时不需要自己实现。特别注意:numpy的函数均除以m,而不是m-1,不过无论是无偏估计还是有偏估计,相关系数的计算中都会约去,比较相关性时无影响:
np.var(X) #方差
np.cov([X, Y, X]) #协方差矩阵
np.corrcoef([X, Y, X]) #相关系数矩阵