本系列博客旨在为机器学习(深度学习)提供数学理论基础。因此内容更为精简,适合二次学习的读者快速学习或查阅。
主成分分析(principal components analysis,PCA)是一个简单的机器学习算法,能够在损失精度尽可能少的前提下,对数据进行有损压缩。
设有
m
m
m 个点
{
x
i
,
…
,
x
m
}
\{x_{i},\dots,x_{m}\}
{xi,…,xm},每一个点都是一个
n
n
n 维向量 ,我们希望找到一个编码函数,根据输入返回编码,
c
=
f
(
x
)
c=f(x)
c=f(x) ;同时也希望找到一个解码函数,给定编码重构输入,
x
≈
g
(
f
(
x
)
)
x\approx g(f(x))
x≈g(f(x)) 。
令
g
(
c
)
=
D
c
g(c)=Dc
g(c)=Dc ,其中
D
∈
R
n
∗
l
,
(
l
<
n
)
D\in R^{n*l},(l
为了使解码后的结果与实际值之间的差值最小,有
arg min
c
∣
∣
g
(
c
)
−
x
∣
∣
2
\argmin_{c}||g(c)-x||_{2}
cargmin∣∣g(c)−x∣∣2
⇒
arg min
c
∣
∣
D
c
−
x
∣
∣
2
2
\Rightarrow\argmin_{c}||Dc-x||_{2}^{2}
⇒cargmin∣∣Dc−x∣∣22
⇒
arg min
c
(
D
c
−
x
)
T
(
D
c
−
x
)
\Rightarrow\argmin_{c}(Dc-x)^{T}(Dc-x)
⇒cargmin(Dc−x)T(Dc−x)
⇒
arg min
c
c
T
D
T
D
c
−
2
x
T
D
c
\Rightarrow\argmin_{c}\ c^{T}D^{T}Dc-2x^{T}Dc
⇒cargmin cTDTDc−2xTDc
求导并令导数为
0
,可得:
D
c
=
x
求导并令导数为0,可得:Dc=x
求导并令导数为0,可得:Dc=x 令
D
T
D
=
I
D^{T}D=I
DTD=I ,上式可转换为:
c
=
f
(
x
)
=
D
T
x
c=f(x)=D^{T}x
c=f(x)=DTx 解码函数找到了,接下来是找最好的D,使得压缩后的信息损失最小,即有:
arg min
D
∑
i
m
∣
∣
x
i
−
f
(
g
(
x
i
)
)
∣
∣
2
,
s
.
t
.
D
T
D
=
I
\argmin_{D}\sum_{i}^{m}||x_{i}-f(g(x_{i}))||^{2},s.t.D^{T}D=I
Dargmini∑m∣∣xi−f(g(xi))∣∣2,s.t.DTD=I
⇒
arg min
D
∑
i
m
∣
∣
x
i
−
D
D
T
x
∣
∣
2
,
s
.
t
.
D
T
D
=
I
\Rightarrow\argmin_{D}\sum_{i}^{m}||x_{i}-DD^{T}x||^{2},s.t.D^{T}D=I
⇒Dargmini∑m∣∣xi−DDTx∣∣2,s.t.DTD=I
⇒
arg min
D
∣
∣
X
−
D
D
T
X
∣
∣
F
2
,
s
.
t
.
D
T
D
=
I
\Rightarrow\argmin_{D}||X-DD^{T}X||^{2}_{F},s.t.D^{T}D=I
⇒Dargmin∣∣X−DDTX∣∣F2,s.t.DTD=I
⇒
arg min
D
T
r
[
(
X
−
D
D
T
X
)
T
(
X
−
D
D
T
X
)
]
,
s
.
t
.
D
T
D
=
I
\Rightarrow\argmin_{D}Tr[(X-DD^{T}X)^{T}(X-DD^{T}X)],s.t.D^{T}D=I
⇒DargminTr[(X−DDTX)T(X−DDTX)],s.t.DTD=I
⇒
arg max
D
T
r
(
D
D
T
X
X
T
)
+
λ
(
D
T
D
−
I
)
\Rightarrow\argmax_{D}Tr(DD^{T}XX^{T})+\lambda(D^{T}D-I)
⇒DargmaxTr(DDTXXT)+λ(DTD−I)
求导并令导数为
0
,可得:
X
X
T
D
=
λ
D
求导并令导数为0,可得:XX^{T}D=\lambda D
求导并令导数为0,可得:XXTD=λD 最终我们可以得出结论,D就是由矩阵
X
X
T
XX^{T}
XXT 的
l
l
l 个特征向量所构成。
import numpy as np
class PCAModel:
def __init__(self):
self.d = None
def fit(self, x, target_l):
"""
填充训练数据,进行主成分分析
:param x: 训练数据矩阵,每一个列向量为一条训练数据
:param target_l: 目标维度,应小于矩阵x中列向量的长度
"""
if target_l >= x.shape[0]:
raise ValueError("target_l should greater than x.shape[0]")
features, f_vec = np.linalg.eig(np.matmul(x, x.T))
self.d = f_vec[:, :target_l]
def transform(self, x):
"""
对数据x进行降维
"""
return np.matmul(self.d.T, x)
def reverse_transform(self, x):
"""
对数据x进行还原
"""
return np.matmul(self.d, x)
train_x = np.array([[1,2],[3,4],[5,6]])
print(train_x)
# [[1 2]
# [3 4]
# [5 6]]
model = PCAModel()
model.fit(tran_x, 2)
result = model.transform(train_x)
print(result)
# [[-5.90229186 -7.47652631]
# [ 0.40367167 -0.3186758 ]]
pred_y = model.reverse_transform(result)
print(pred_y)
# [[1. 2.]
# [3. 4.]
# [5. 6.]]
从运行结果中可以看出,对数据进行压缩后能够完美进行还原。