协方差、协方差矩阵、PCA的理解(附python代码)

均值、方差、标准差

均值: X ˉ = ∑ i = 1 n X i n \bar{X}=\frac{\sum_{i=1}^n{X_i}}{n} Xˉ=ni=1nXi
标准差: S = ∑ i = 1 n ( X i − X ˉ ) 2 n − 1 S=\sqrt{\frac{\sum_{i=1}^n({X_i-\bar{X}})^2}{n-1}} S=n1i=1n(XiXˉ)2
方差: S = ∑ i = 1 n ( X i − X ˉ ) 2 n − 1 S=\frac{\sum_{i=1}^n({X_i-\bar{X}})^2}{n-1} S=n1i=1n(XiXˉ)2
均值描述的是样本集合的中间点,标准差描述的是各个样本点到均值的距离之平均。方差则仅仅是标准差的平方。
[ 0 8 12 20 ] \begin{bmatrix} 0& 8& 12& 20\end{bmatrix} [081220] [ 8 9 11 12 ] \begin{bmatrix} 8& 9& 11& 12\end{bmatrix} [891112]为例:
均值都是10,但显然两个集合的差别是很大的。
计算两者的标准差,前者是8.3后者是1.8,显然后者较为集中,故其标准差小一些,标准差描述的就是这种“散布度”。

协方差

标准差和方差一般是用来描述一维数据的。
对于二维数据,协方差就产生了:
协方差: c o v ( X , Y ) = ∑ i = 1 n ( X i − X ˉ ) ( Y i − Y ˉ ) n − 1 cov(X,Y)=\frac{\sum_{i=1}^n({X_i-\bar{X}})({Y_i-\bar{Y}})}{n-1} cov(X,Y)=n1i=1n(XiXˉ)(YiYˉ)
从下面这个式子来看方差和协方差:
c o v ( X , X ) = v a r ( X , X ) = ∑ i = 1 n ( X i − X ˉ ) ( X i − X ˉ ) n − 1 cov(X,X)=var(X,X)=\frac{\sum_{i=1}^n({X_i-\bar{X}})({X_i-\bar{X}})}{n-1} cov(X,X)=var(X,X)=n1i=1n(XiXˉ)(XiXˉ)
协方差的结果有什么意义呢?
如果结果为正值,则说明两者是正相关的。如果结果为负值, 就说明两者是负相关。如果为0,则两者之间没有关系,也就是“相互独立”。

协方差矩阵

协方差矩阵:
C n × n = ( c i , j , c i , j = c o v ( D i m i , D i m j ) ) C_{n \times n} = (c_{i,j},\quad c_{i,j}=cov(Dim_{i}, Dim_{j})) Cn×n=(ci,j,ci,j=cov(Dimi,Dimj))
以三维为例:
C = ( c o v ( X , X ) c o v ( X , Y ) c o v ( X , Z ) c o v ( Y , X ) c o v ( Y , Y ) c o v ( Y , Z ) c o v ( Z , X ) c o v ( Z , Y ) c o v ( Z , Z ) ) C=\begin{pmatrix} cov(X,X) & cov(X,Y) & cov(X,Z) \\ cov(Y,X) & cov(Y,Y) & cov(Y,Z) \\ cov(Z,X) & cov(Z,Y) & cov(Z,Z) \end{pmatrix} C=cov(X,X)cov(Y,X)cov(Z,X)cov(X,Y)cov(Y,Y)cov(Z,Y)cov(X,Z)cov(Y,Z)cov(Z,Z)
协方差矩阵的计算:
(1)先让样本矩阵中心化,即每一维度减去该维度的均值,使每一维度上的均值为0;
(2)然后直接新的样本矩阵乘上新的样本矩阵的转置(用转置相乘实现两两维度的相乘);
(3)除以n-1。

现在有10个样例,每个样例有2个特征:
X = [ 2.5 0.5 2.2 1.9 3.1 2.3 2 1 1.5 1.1 ] X=\begin{bmatrix} 2.5& 0.5& 2.2& 1.9& 3.1& 2.3& 2& 1& 1.5& 1.1\end{bmatrix} X=[2.50.52.21.93.12.3211.51.1]
Y = [ 2.4 0.7 2.9 2.2 3 2.7 1.6 1.1 1.6 0.9 ] Y=\begin{bmatrix} 2.4& 0.7& 2.9& 2.2& 3& 2.7& 1.6& 1.1& 1.6& 0.9\end{bmatrix} Y=[2.40.72.92.232.71.61.11.60.9]
D a t a = [ 2.5 0.5 2.2 1.9 3.1 2.3 2 1 1.5 1.1 2.4 0.7 2.9 2.2 3 2.7 1.6 1.1 1.6 0.9 ] Data = \begin{bmatrix} 2.5& 0.5& 2.2& 1.9& 3.1& 2.3& 2& 1& 1.5& 1.1\\2.4& 0.7& 2.9& 2.2& 3& 2.7& 1.6& 1.1& 1.6& 0.9\end{bmatrix} Data=[2.52.40.50.72.22.91.92.23.132.32.721.611.11.51.61.10.9]
矩阵去中心化之后:
D a t a S = [ 0.69 − 1.31 0.39 0.09 1.29 0.49 0.19 − 0.81 − 0.31 − 0.71 0.49 − 1.21 0.99 0.29 1.09 0.79 − 0.31 − 0.81 − 0.31 − 1.01 ] Data_S = \begin{bmatrix} 0.69 & -1.31& 0.39& 0.09& 1.29&0.49& 0.19& -0.81& -0.31& -0.71\\0.49& -1.21& 0.99& 0.29& 1.09& 0.79& -0.31& -0.81& -0.31& -1.01\end{bmatrix} DataS=[0.690.491.311.210.390.990.090.291.291.090.490.790.190.310.810.810.310.310.711.01]
转置相乘除以 n − 1 n-1 n1
C = D a t a S . D a t a S T / 9 C = Data_S. Data_S^T /9 C=DataS.DataST/9
得到协方差矩阵为:
C = [ 0.61655556 0.61544444 0.61544444 0.71655556 ] C=\begin{bmatrix} 0.61655556 & 0.61544444 \\ 0.61544444 & 0.71655556 \end{bmatrix} C=[0.616555560.615444440.615444440.71655556]
0.61655556为 X X X的方差,0.71655556为 Y Y Y的方差。
0.61544444为 X X X Y Y Y的协方差。
代码如下:

import numpy as np

x = np.array([2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1])
y = np.array([2.4, 0.7, 2.9, 2.2, 3, 2.7, 1.6, 1.1, 1.6, 0.9])

# 归一化数据
scaled_x = x-np.mean(x)
scaled_y = y-np.mean(y)

# 组成矩阵
data = np.matrix([[scaled_x[i], scaled_y[i]] for i in range(len(scaled_x))])

# 求协方差矩阵
cov_matrix= np.dot(data.T, data)/(len(x)-1)

等价于:

import numpy as np

x = np.array([2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1])
y = np.array([2.4, 0.7, 2.9, 2.2, 3, 2.7, 1.6, 1.1, 1.6, 0.9])

# 求协方差矩阵
cov_matrix= np.cov(x, y)

PCA

先复习下矩阵的特征值和特征向量。

特征值、特征向量

定义1:设 A A A n n n阶方阵,若存在数 λ \lambda λ和非零向量 x x x,使得
A x = λ x ( x ≠ 0 ) Ax=\lambda x(x \neq 0) Ax=λx(x=0)
则称 λ \lambda λ A A A的一个特征值, x x x A A A对应于特征值 λ \lambda λ的特征向量。
在几何学中,矩阵A的特征向量是指经过与矩阵A变换后方向保持不变的向量。而特征值为在这个变化中特征向量的比例因子。
方阵的特征值的个数等于矩阵的阶数。

协方差矩阵的特征值和特征向量

接着上文的例子,已经求出 D a t a Data Data的协方差矩阵 C C C
D a t a = [ 2.5 0.5 2.2 1.9 3.1 2.3 2 1 1.5 1.1 2.4 0.7 2.9 2.2 3 2.7 1.6 1.1 1.6 0.9 ] Data = \begin{bmatrix} 2.5& 0.5& 2.2& 1.9& 3.1& 2.3& 2& 1& 1.5& 1.1\\2.4& 0.7& 2.9& 2.2& 3& 2.7& 1.6& 1.1& 1.6& 0.9\end{bmatrix} Data=[2.52.40.50.72.22.91.92.23.132.32.721.611.11.51.61.10.9]

C = [ 0.61655556 0.61544444 0.61544444 0.71655556 ] C=\begin{bmatrix} 0.61655556 & 0.61544444 \\ 0.61544444 & 0.71655556 \end{bmatrix} C=[0.616555560.615444440.615444440.71655556]

# 求协方差矩阵的特征值和特征向量
eig_val, eig_vec = np.linalg.eig(cov)

得到特征值:
e i g V a l u e = [ 0.0490834 1.28402771 ] eigValue=\begin{bmatrix} 0.0490834 & 1.28402771\end{bmatrix} eigValue=[0.04908341.28402771]
特征向量:
e i g V e c t M a t r i x = [ − 0.73517866 − 0.6778734 0.6778734 − 0.73517866 ] eigVectMatrix=\begin{bmatrix} -0.73517866&-0.6778734\\ 0.6778734&-0.73517866\end{bmatrix} eigVectMatrix=[0.735178660.67787340.67787340.73517866]

选取前k个特征(降到k维度)

将特征值按照从大到小的顺序排序,选择其中最大的 k k k个,然后将其对应的 k k k个特征向量分别作为列向量组成特征向量矩阵。
这里特征值只有2个,我们选择其中最大的那个。
这里是1.28402771,对应的特征向量是 e i g V e c t = ( − 0.6778734 , − 0.73517866 ) eigVect=\begin{pmatrix} -0.6778734,&-0.73517866\end{pmatrix} eigVect=(0.6778734,0.73517866)

将样本点投影到选取的特征向量上

获取低维特征空间的数据:
l o w D a t a = e i g V e c t ⋅ D a t a s lowData= eigVect\cdot Data_s lowData=eigVectDatas
我们来看下是如何降维的: [ 1 , 2 ] ⋅ [ 2 , 10 ] → [ 1 , 10 ] [1,2]\cdot [2,10]\to[1,10] [1,2][2,10][1,10]

完整代码如下:

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

x = np.array([2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1])
y = np.array([2.4, 0.7, 2.9, 2.2, 3, 2.7, 1.6, 1.1, 1.6, 0.9])

# 归一化数据
mean_x = np.mean(x)
mean_y = np.mean(y)
scaled_x = x-mean_x
scaled_y = y-mean_y

data = np.matrix([[scaled_x[i], scaled_y[i]] for i in range(len(scaled_x))])

# 绘制散点图查看数据分布
plt.plot(x, y, 'r*', label='原始数据')
plt.plot(scaled_x, scaled_y, 'go', label='去中心化后数据')

# 求协方差矩阵
dot = np.dot(data.T, data)
dott = dot/(len(x)-1)

cov = np.cov(x, y)

# 求协方差矩阵的特征值和特征向量
eig_val, eig_vec = np.linalg.eig(cov)

# 求出特征向量后,我们需要选择降维后的数据维度 k(n 维数据降为 k 维数据),但我们的数据只有2维,所以只能降1维
eig_pairs = [(np.abs(eig_val[i]), eig_vec[:, i]) for i in range(len(eig_val))]
eig_pairs.sort(reverse=True)
feature = eig_pairs[0][1]

# 转化得到降维后的数据
new_data_reduced = np.transpose(np.dot(feature, np.transpose(data)))
new_y = np.zeros(len(x))
plt.plot(new_data_reduced, new_y, 'b.', label='降维后数据')

plt.legend()
plt.show()

结果:
在这里插入图片描述

附:
为什么要用协方差矩阵来算PCA?请看这篇,讲得很好。
https://blog.csdn.net/a10767891/article/details/80288463

  • 9
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值