本节为吴恩达教授机器学习课程笔记第十二部分,主成分分析,主要包括:主成分分析法PCA的来由和推导,python实现、奇异值分解SVD以及PCA和SVD的联系。
1. 简介与推导
在因子分析的讨论中,我们将数据
x
∈
R
n
x\in R^n
x∈Rn近似的建模在一个k维子空间上,其中
k
<
<
n
k<<n
k<<n,我们假设每个数据点
x
(
i
)
x^{(i)}
x(i)首先经某个在k维仿射空间
{
∧
z
+
μ
,
z
∈
R
k
}
\{\wedge z+\mu ,z\in R^k\}
{∧z+μ,z∈Rk}的
z
(
i
)
z^{(i)}
z(i)生成,然后加入协方差噪音
Ψ
\Psi
Ψ。因子分析建立在概率模型上,参数估计使用了迭代的EM算法。
本节将学习一种新的方法——主成分分析法(PCA, Principal Conmponents Analysis),来在低维子空间上对数据建模,但是PCA的计算更加直接,只需要特征向量,不需要使用EM算法。
给定数据集
{
x
(
i
)
;
i
=
1
,
.
.
.
,
m
}
\{x{(i)};i=1,...,m\}
{x(i);i=1,...,m},包含m个不同类型的汽车的参数,例如最大速度,扭矩等等,令
x
(
i
)
∈
R
n
(
n
<
<
m
)
x^{(i)}\in R^n(n<<m)
x(i)∈Rn(n<<m),但是其中两个参数可能表达的意思相近或者说二者具有线性关系,那么数据其实是可以近似建模在n-1维特征子空间上的。那么该如何检测出这个特征子空间呢?
这时候就需要PCA算法了,应用PCA算法之前,首先对数据进行预处理:
这样一来,所有特征的规模会相同,避免了参数极端值的影响,标准化之后,假设数据如下所示:
然后挑选一个向量u来代表上图数据中的方向,如下图所示,其中"
∙
\bullet
∙"表示原始数据在该条线上的投影。
可以看到上图中的投影数据仍然有较大的方差,数据点与原点距离也比较大,因此我们尝试选择与上面的线方向相反的一条线,并作投影如下图所示:
此时投影数据的已经变小,并且与原点更近。
我们的目标是自动得到图中的方向向量,下面给出形式化的定义。首先给定一个单位向量和一个数据点,记点在向量上的投影的长度为
x
T
u
x^Tu
xTu,因此为了最大化投影的方差我们需要最大化下面的式子:
可以看出最大化过程中令
∣
∣
u
2
∣
∣
=
1
||u^2||=1
∣∣u2∣∣=1给出了数据经验协方差矩阵
Σ
=
1
m
Σ
i
=
1
m
x
(
i
)
x
(
i
)
T
\Sigma= \frac 1 m \Sigma_{i=1}^m x^{(i)}{x^{(i)}}^T
Σ=m1Σi=1mx(i)x(i)T的主特征向量。
也就是说,如果我们要寻找数据可以近似建模的一维子空间,那么我们只需令u为协方差矩阵的主特征向量。如果我们要寻找数据可以近似建模的k维子空间,就需要选择协方差矩阵的u_1,…,u_k共k个特征向量,此时,u_i’s就形成了一个新的数据的正交基底。
为了用这个基底表示
x
i
x_i
xi,我们只需要计算对应的向量:
这样一来,对于任意
x
(
i
)
∈
R
n
x^{(i)} \in R^n
x(i)∈Rn,向量
y
(
i
)
y^{(i)}
y(i)就给出了一个k维的近似。这也就是PCA的中心思想,即数据降维,
u
1
,
.
.
.
,
u
k
u_1,...,u_k
u1,...,uk称为数据的k个主成分。综合来看PCA的算法流程如下所示:
2. PCA的理解和python实现
根据上面对PCA的数学原理的解释,我们可以了解到一些PCA的能力和限制。PCA本质上是将方差最大的方向作为主要特征,并且在各个正交方向上将数据“离相关”,也就是让它们在不同正交方向上没有相关性。
因此,PCA也存在一些限制,例如它可以很好的解除线性相关,但是对于高阶相关性就没有办法了,对于存在高阶相关性的数据,可以考虑Kernel PCA,通过Kernel函数将非线性相关转为线性相关,关于这点就不展开讨论了。另外,PCA假设数据各主特征是分布在正交方向上,如果在非正交方向上存在几个方差较大的方向,PCA的效果就大打折扣了。
最后需要说明的是,PCA是一种无参数技术,也就是说面对同样的数据,如果不考虑清洗,谁来做结果都一样,没有主观参数的介入,所以PCA便于通用实现,但是本身无法个性化的优化。
sklearn实现非常简单:
from sklearn import decomposition
pca = decomposition.PCA()
pca.fit(x)
我们也可以自己实现:
import numpy as np
def pca(X,k):#k is the components you want
#mean of each feature
n_samples, n_features = X.shape
mean=np.array([np.mean(X[:,i]) for i in range(n_features)])
#normalization
norm_X=X-mean
#scatter matrix
scatter_matrix=np.dot(np.transpose(norm_X),norm_X)
#Calculate the eigenvectors and eigenvalues
eig_val, eig_vec = np.linalg.eig(scatter_matrix)
eig_pairs = [(np.abs(eig_val[i]), eig_vec[:,i]) for i in range(n_features)]
# sort eig_vec based on eig_val from highest to lowest
eig_pairs.sort(reverse=True)
# select the top k eig_vec
feature=np.array([ele[1] for ele in eig_pairs[:k]])
#get new data
data=np.dot(norm_X,np.transpose(feature))
return data
代码中的实现没有求协方差矩阵,而是计算了散度矩阵,将协方差矩阵乘以系数(n-1)就得到了散布矩阵,二者有相同的特征值和特征向量。
但是由于sklearn中PCA是基于奇异值分解SVD实现的,这两个实现得到的特征向量可能会有所不同,PCA的核心问题在于对协方差矩阵
C
=
1
m
X
X
T
C=\frac{1}{m}XX^T
C=m1XXT的特征值分解。下面看SVD奇异值分解。
3.奇异值分解
奇异值分解要解决的问题是将
A
m
×
n
A_{m\times n}
Am×n矩阵分解为对角矩阵
Σ
m
×
n
\Sigma_{m\times n}
Σm×n,该矩阵中对角元素
σ
i
\sigma_i
σi称为矩阵
A
m
×
n
A_{m\times n}
Am×n的奇异值,如下所示:
其中左乘和右乘的两个矩阵均为正交矩阵。奇异值问题求解方法如下:
也就是说,
V
是
A
T
A
V是A^TA
V是ATA特征值分解的特征向量按列组成的正交矩阵,
Σ
2
是
A
T
A
\Sigma^2是A^TA
Σ2是ATA特征值组成的对角矩阵,可以看出
A
m
×
n
A_{m\times n}
Am×n的奇异值
σ
i
\sigma_i
σi是
A
T
A
A^TA
ATA特征值
λ
i
\lambda_i
λi的平方根,即
σ
i
=
λ
i
\sigma_i=\sqrt{\lambda_i}
σi=λi。
假如
A
T
A
A^TA
ATA的特征向量为
v
i
v_i
vi,
U
U
U中对应的
u
i
u_i
ui可以由下式给出即
u
i
=
A
v
i
σ
i
u_i=\frac{Av_i}{\sigma_i}
ui=σiAvi,可以看出SVD的核心在于对
A
T
A
A^TA
ATA进行特征值分解。
4. PCA与SVD的联系
P C A PCA PCA关键在于对协方差矩阵 C = 1 m X X T C=\frac 1 m XX^T C=m1XXT进行特征值分解,而SVD关键在于 A T A A^TA ATA的特征值分解,很明显二者都是对一个实对称矩阵进行特征值分解,若取 A = X T m A=\frac{X^T}{\sqrt m} A=mXT,则有 A T A = ( X T m ) T X T m = 1 m X X T A^TA=\left(\frac{X^T}{\sqrt m} \right)^T\frac{X^T}{\sqrt m}=\frac 1 m XX^T ATA=(mXT)TmXT=m1XXT,这样SVD与PCA等价,所以PCA可以转化为SVD问题求解,好处有:
- 一般X维度很高, A T A A^TA ATA的计算量很大
- 方阵的特征值分解计算效率底
- SVD除了特征值分解外,还有更高效准确的迭代求解法,避免了
A
T
A
A^TA
ATA的计算。
而且实际上,PCA只与SVD的右奇异向量的压缩效果相同:压缩行对应于样本数量减少,压缩列对应于特征维度降低。
欢迎扫描二维码关注微信公众号 深度学习与数学 [每天获取免费的大数据、AI等相关的学习资源、经典和最新的深度学习相关的论文研读,算法和其他互联网技能的学习,概率论、线性代数等高等数学知识的回顾]