协方差、协方差矩阵、PCA的理解(附python代码)
均值、方差、标准差
均值:
X
ˉ
=
∑
i
=
1
n
X
i
n
\bar{X}=\frac{\sum_{i=1}^n{X_i}}{n}
Xˉ=n∑i=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=n−1∑i=1n(Xi−Xˉ)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=n−1∑i=1n(Xi−Xˉ)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)=n−1∑i=1n(Xi−Xˉ)(Yi−Yˉ)
从下面这个式子来看方差和协方差:
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)=n−1∑i=1n(Xi−Xˉ)(Xi−Xˉ)
协方差的结果有什么意义呢?
如果结果为正值,则说明两者是正相关的。如果结果为负值, 就说明两者是负相关。如果为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.49−1.31−1.210.390.990.090.291.291.090.490.790.19−0.31−0.81−0.81−0.31−0.31−0.71−1.01]
转置相乘除以
n
−
1
n-1
n−1:
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.6778734−0.6778734−0.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=eigVect⋅Datas
我们来看下是如何降维的:
[
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