背景
解决过拟合的问题除了正则化和添加数据之外,降维是最好的方法。降维的思路来源于维度灾难,简单地例子
n维的球的体积:
C
R
n
CR^n
CRn
n维球体的体积与边长为
2
R
2R
2R的超立方体的比值:
lim
n
→
0
C
R
n
2
n
R
n
=
0
\lim\limits_{n\rightarrow0}\frac{CR^n}{2^nR^n}=0
n→0lim2nRnCRn=0
所谓的维度灾难,就是在高维数据中,主要样本都分布在立方体的边缘,也就是基本分布在外壳上,所以数据更加洗漱。
降维算法的分类:
- 直接降维 :特征选择
- 线性降维:PCA MDS等
- 非线性降维
为了方便,先补充方差和协方差的概念:
- 方差 : 用来刻画单个随机变量的离散程度
- 协方差: 用来刻画两个随机变量的相似程度,协方差矩阵就存储了所有特征两两之间的相似程度
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲S&=\frac{1}{N}\…
线性降维主成分分析
主成分分析中,基本的思想是将所有数据投影到一个子空间中,从而达到降维的目的,这个子空间应该是这样的:
1.所有数据在子空间更加分散 (最大投影方差)
2.投影后损失信息量最小 (最小重构误差)
这是两个思路。
原始数据可能是各个维度之间是相关的,希望得到一组
p
p
p 个线性无关的单位基
u
i
u_i
ui ,降维就是取得其中前
p
p
p 个基,对于样本
x
i
x_i
xi ,经过变化之后:
x
i
^
=
∑
i
=
1
p
(
u
i
T
x
i
)
u
i
=
∑
i
=
1
q
(
u
i
T
x
i
)
u
i
+
∑
i
=
q
+
1
p
(
u
i
T
x
i
)
u
i
\hat{x_i}=\sum\limits_{i=1}^p(u_i^Tx_i)u_i=\sum\limits_{i=1}^q(u_i^Tx_i)u_i+\sum\limits_{i=q+1}^p(u_i^Tx_i)u_i
xi^=i=1∑p(uiTxi)ui=i=1∑q(uiTxi)ui+i=q+1∑p(uiTxi)ui
假设存在新的空间中有一组 单位正交基(比说二维平面中的坐标系) u 1 u_1 u1 , u 2 u_2 u2 ,原始数据向这个新的坐标两个轴做投影,我们发现在坐标中方向投影都比较大,那么就可以使用这个新的坐标系表示这组数据(这两个正交基就是主成分),如果想得到Q维,就要找到前Q 个主成分
最大投影误差
刚才说了,原始数据向新的坐标系投影,在坐标轴方向投影比较大,因此我们想找个这些比较大的“方向”。
首先为了处理方便,我们将数据做中心化处理:
KaTeX parse error: No such environment: align at position 8: \begin{̲a̲l̲i̲g̲n̲}̲J&=\frac{1}{N}\…
那么就转化成了带约束的优化问题:
a
r
g
m
a
x
u
j
L
(
u
j
,
λ
)
=
a
r
g
m
a
x
u
j
u
j
T
S
u
j
+
λ
(
1
−
u
j
T
u
j
)
\mathop{argmax}_{u_j}L(u_j,\lambda)=\mathop{argmax}_{u_j}u_j^TSu_j+\lambda(1-u_j^Tu_j)
argmaxujL(uj,λ)=argmaxujujTSuj+λ(1−ujTuj)
得到:
S
u
j
=
λ
u
j
Su_j=\lambda u_j
Suj=λuj
可以看出来,最大投影误差降维就是 协方差矩阵的特征分解,得到的特征向量就是这组线性无关的正交基,也就是主成分,特征值从大到小排序,选择其中最大的k个。然后将其对应的k个特征向量分别作为行向量组成特征向量矩阵P。
实例 - 鸢尾花分类
使用python中的sklearn库实现鸢尾花数据降维,数据本身是4维的降成2维。
总样本数150,鸢尾花的类别有0.1.2
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
data = load_iris() # 载入鸢尾花数据
y = data.target
x = data.data
pca = PCA(n_components= 2 )# 加载PCA算法,设置将为后的主成分数量2
reduced_x = pca.fit_transform(x) # 对样本进行降维
red_x,red_y = [] , []
blue_x,blue_y = [] , []
green_x,green_y = [] , []
for i in range(len(reduced_x)):
if y[i] ==0:
red_x.append(reduced_x[i][0])
red_y.append(reduced_x[i][1])
elif y[i]==1:
blue_x.append(reduced_x[i][0])
blue_y.append(reduced_x[i][1])
else:
green_x.append(reduced_x[i][0])
green_y.append(reduced_x[i][1])
plt.scatter(red_x,red_y,c='r',marker='x')
plt.scatter(blue_x,blue_y,c='b',marker='D')
plt.scatter(green_x,green_y,c='g',marker='.')
plt.show()