图解机器学习 | 降维算法详解

8,390 阅读10分钟

引言

在互联网大数据场景下,我们经常需要面对高维数据,在对这些数据做分析和可视化的时候,我们通常会面对「高维」这个障碍。在数据挖掘和建模的过程中,高维数据也同样带来大的计算量,占据更多的资源,而且许多变量之间可能存在相关性,从而增加了分析与建模的复杂性。

我们希望找到一种方法,在对数据完成降维「压缩」的同时,尽量减少信息损失。由于各变量之间存在一定的相关关系,因此可以考虑将关系紧密的变量变成尽可能少的新变量,使这些新变量是两两不相关的,那么就可以用较少的综合指标分别代表存在于各个变量中的各类信息。机器学习中的降维算法就是这样的一类算法。

主成分分析(Principal Components Analysis,简称PCA)是最重要的数据降维方法之一。在数据压缩消除冗余和数据噪音消除等领域都有广泛的应用。本篇我们来展开讲解一下这个算法。

(本篇降维算法部分内容涉及到机器学习基础知识,没有先序知识储备的宝宝可以查看ShowMeAI的文章 图解机器学习 | 机器学习基础知识

1.PCA与最大可分性

对于X=[x1x2...xn]X = \begin {bmatrix} x_1 \\ x_2 \\ ... \\ x_n \end{bmatrix}XRnX \in R^n。我们希望XXnn维降到nn^{'}维,同时希望信息损失最少。比如,从n=2n = 2维降到n=1n^{'} = 1

左图为一个典型的例子,假如我们要对一系列人的样本进行数据降维(每个样本包含「身高」「体重」两个维度)。右图我们既可以降维到第一主成分轴,也可以降维到第二主成分轴。

哪个主成分轴更优呢?从直观感觉上,我们会认为「第一主成分轴」优于「第二主成分轴」,因为它比较大程度保留了数据之间的区分性(保留大部分信息)。

对PCA算法而言,我们希望找到小于原数据维度的若干个投影坐标方向,把数据投影在这些方向,获得压缩的信息表示。下面我们就一步一步来推导一下PCA算法原理。

2.基变换

先来复习一点点数学知识。我们知道要获得原始数据XX新的表示空间YY,最简单的方法是对原始数据进行线性变换(也叫做基变换)Y=PXY = PX。其中,XX是原始样本,PP是基向量,YY是新表达。

数学表达为:

[p1p2pr]r×n[x1x2xm]n×m=[p1x1p1x2p1xmp2x1p2x2p2xmprx1prx2prxm]r×m\begin{bmatrix} p_1 \\ p_2 \\ \vdots \\ p_r \end{bmatrix}_{r \times n} \begin{bmatrix} x_1 & x_2 & \cdots & x_m \end{bmatrix}_{n \times m} = \begin{bmatrix} p_1 x_1 & p_1 x_2 & \cdots & p_1 x_m \\ p_2 x_1 & p_2 x_2 & \cdots & p_2 x_m \\ \vdots & \vdots & \ddots & \vdots \\ p_r x_1 & p_r x_2 & \cdots & p_r x_m\end{bmatrix}_{r\times m}
  • 其中pip_i是行向量,表示第ii个基;

  • xjx_j是一个列向量,表示第jj个原始数据记录。

r<nr < n时,即「基的维度<数据维度」时,可达到降维的目的,即XRn×mYRr×mX \in R^{n \times m} \rightarrow Y \in R^{r \times m }

以直角坐标系下的点(3,2)(3,2)为例,要把点(3,2)(3,2)变换为新基上的坐标,就是用(3,2)(3,2)与第一个基做内积运算,作为第一个新的坐标分量,然后用(3,2)(3,2)与第二个基做内积运算,作为第二个新坐标的分量。

上述变化,在线性代数里,我们可以用矩阵相乘的形式简洁的来表示:

[12121212][32]=[5212]\begin{bmatrix}\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \\ -\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \end{bmatrix} \begin{bmatrix} 3 \\ 2\end{bmatrix} = \begin{bmatrix} \frac{5}{\sqrt 2} \\ - \frac{1}{\sqrt 2} \end{bmatrix}

再稍微推广一下,假如我们有m个二维向量,只要将二维向量按列排成一个两行m列矩阵,然后用「基矩阵」乘以这个矩阵,就得到了所有这些向量在新基下的值。例如(1,1)、(2,2)、(3,3),想变换到刚才那组基上,可以如下这样表示:

[12121212][123123]=[224262000]\begin{bmatrix}\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \\ -\frac{1}{\sqrt 2} & \frac{1}{\sqrt 2} \end{bmatrix} \begin{bmatrix} 1 & 2 & 3 \\ 1 & 2 & 3\end{bmatrix} = \begin{bmatrix} 2\sqrt 2 & 4\sqrt2 & 6\sqrt2 \\ 0 & 0 & 0 \end{bmatrix}

3.方差

在本文的开始部分,我们提到了,降维的目的是希望压缩数据但信息损失最少,也就是说,我们希望投影后的数据尽可能分散开。在数学上,这种分散程度我们用「方差」来表达,方差越大,数据越分散。

  • 定义方差VarVar:对于单一随机变量aaVar(a)=1mi=1m(aiμ)2Var(a) = \frac{1}{m} \sum_{i = 1}^m (a_i - \mu)^2

  • 对数据做去中心化(方便后面操作):Var(a)=1mi=1mai2Var(a) = \frac{1}{m} \sum_{i = 1}^m a_i ^2

Var(a)Var(a)表示aa的取值与其数学期望之间的偏离程度。若Var(a)Var(a)较小,意味着aa的取值主要集中在期望μ\mu也就是E(a)E(a))的附近;反之,若Var(a)Var(a)较大,意味着aa的取值比较分散。

我们来看一个具体的例子。假设我们5个样本数据,分别是x1=[11]x_1 = \begin{bmatrix} 1 \\ 1 \end{bmatrix}x2=[13]x_2 = \begin{bmatrix} 1 \\ 3\end{bmatrix}x3=[23]x_3 = \begin{bmatrix} 2 \\ 3\end{bmatrix}x4=[44]x_4 = \begin{bmatrix} 4 \\ 4\end{bmatrix}x5=[24]x_5 = \begin{bmatrix} 2 \\ 4 \end{bmatrix},将它们表示成矩阵形式:

X=[1124213344]X = \begin{bmatrix} 1 & 1 & 2 & 4 & 2 \\ 1 & 3 & 3 & 4 & 4 \end {bmatrix}

为了后续处理方便,我们首先将每个字段内所有值都减去字段均值,其结果是将每个字段都变为均值为0。

我们看上面的数据,设第一个特征为aa,第二个特征为bb,则某个样本可以写作xi=[ab]x_i = \begin{bmatrix} a \\ b \end {bmatrix} 且特征aa的均值为2,特征bb的均值为3。所以,变换后

X=[1102020011]X = \begin{bmatrix} -1 & -1 & 0 & 2 & 0 \\ -2 & 0 & 0 & 1 & 1 \end{bmatrix}
Var(a)=65Var(a ) = \frac{\sqrt 6} {5}
Var(b)=65Var(b ) = \frac{\sqrt 6} {5}

4.协方差

协方差(Covariance)在概率和统计学中用于衡量两个变量的总体误差。比如对于二维随机变量xi=[ab]x_i = \begin{bmatrix} a \\ b \end{bmatrix},特征aba、b除了自身的数学期望和方差,还需要讨论aba、b之间互相关系的数学特征。

定义协方差CovCov

Cov(a,b)=1mi=1maibiCov(a, b) = \frac{1}{m}\sum_{i = 1}^m a_i b_i

Cov(a,b)=0Cov(a, b) = 0时,变量aba、b完全独立,这也是我们希望达到的优化目标。方差是协方差的一种特殊情况,即当两个变量是相同的情况Cov(a,a)=Var(a)Cov(a, a) = Var(a)

5.协方差矩阵

对于二维随机变量xi=[ab]x_i = \begin{bmatrix} a \\ b \end {bmatrix},定义协方差矩阵C=[Var(a)Cov(a,b)Cov(b,a)Var(b)]C = \begin{bmatrix} Var(a) & Cov(a, b) \\ Cov(b, a) &Var(b)\end{bmatrix}

对于nn维随机变量 xi=[x1x2xn]x_{i}=\left[\begin{array}{c} x_{1} \\ x_{2} \\ \vdots \\ x_{n} \end{array}\right]

C=[Var(x1)Cov(x1,x2)Cov(x1,xn)Cov(x2,x1)Var(x2)Cov(x1,xn)Cov(xn,x1)Cov(xn,x2)Var(xn)]C = \begin{bmatrix} Var(x_1) & Cov(x_1, x_2) &\cdots & Cov(x_1, x_n)\\ Cov(x_2, x_1)& Var(x_2) & \cdots & Cov(x_1, x_n)\\ \vdots & \vdots & \ddots & \vdots \\ Cov(x_n, x_1) & Cov(x_n, x_2) & \cdots &Var(x_n) \end{bmatrix}

我们可以看到,协方差矩阵是nnnn列的对称矩阵,主对角线上是方差,而协对角线上是协方差。

我们再来用一个示例对应讲解一下。还是同样的5个样本数据

  • x1=[11]x_1 = \begin{bmatrix} 1 \\ 1 \end{bmatrix}

  • x2=[13]x_2 = \begin{bmatrix} 1 \\ 3\end{bmatrix}

  • x3=[23]x_3 = \begin{bmatrix} 2 \\ 3\end{bmatrix}

  • x4=[44]x_4 = \begin{bmatrix} 4 \\ 4\end{bmatrix}

  • x5=[24]x_5 = \begin{bmatrix} 2 \\ 4 \end{bmatrix}

去中心化后表示成矩阵

X=[1102020011]X = \begin{bmatrix} -1 & -1 & 0 & 2 & 0 \\ -2 & 0 & 0 & 1 & 1 \end{bmatrix}

那如果有mm个样本的话,X=[a1a2amb1b2bm]X =\begin{bmatrix} a_1 & a_2 & \cdots &a_m \\ b_1 & b_2 & \cdots & b_m\end{bmatrix}。对XX做一些变换,用XX乘以XX的转置,并乘上系数1/m1/m

1mXXT=1m[a1a2amb1b2bm][a1b1a2b2ambm]=[1mi=1mai21mi=1maibi1mi=1maibi1mi=1mbi2]\frac{1}{m}XX^T = \frac{1}{m}\begin{bmatrix} a_1 & a_2 & \cdots &a_m \\ b_1 & b_2 & \cdots & b_m\end{bmatrix}\begin{bmatrix} a_1 & b_1 \\ a_2 & b_2 \\ \vdots & \vdots \\ a_m &b_m \end{bmatrix} = \begin{bmatrix} \frac{1}{m} \sum_{i = 1}^m a_i ^2 & \frac{1}{m}\sum_{i = 1}^m a_i b_i \\ \frac{1}{m}\sum_{i = 1}^m a_i b_i& \frac{1}{m} \sum_{i = 1}^m b_i^2 \end{bmatrix}

这正是协方差矩阵!我们归纳得到:设我们有mmnn维数据记录,将其按列排成nnmm的矩阵XX,设C=1mXXTC = \frac{1}{m}XX^T,则CC是一个对称矩阵,其对角线分别个各个特征的方差,而第iijj列和jjii列元素相同,表示iijj两个特征之间的协方差。

6.协方差矩阵对角化

再回到我们的场景和目标:

  • 现在我们有mm个样本数据,每个样本有nn个特征,那么设这些原始数据为XXXXnnmm列的矩阵。

  • 想要找到一个基PP,使Yr×m=Pr×nXn×mY_{r \times m} = P_{r \times n}X_{n \times m},其中$$r,达到降维的目的。

XX的协方差矩阵为CCYY的协方差矩阵为DD,且Y=PXY = PX

  • 我们的目的变为:对原始数据XX做PCA后,得到的YY的协方差矩阵DD的各个方向方差最大,协方差为0。

那么CCDD是什么关系呢?

D=1mYYT=1m(PX)(PX)T=1mPXXTPT=1mP(XXT)PT=PCPT=P[1mi=1mai21mi=1maibi1mi=1maibi1mi=1mbi2]PT\begin{aligned} D & =\frac{1}{m} Y Y^{T} \\ & =\frac{1}{m}(P X)(P X)^{T} \\ & =\frac{1}{m} P X X^{T} P^{T} \\ & =\frac{1}{m} P\left(X X^{T}\right) P^{T} \\ & =P C P^{T} \\ & =P\left[\begin{array}{cc} \frac{1}{m} \sum_{i=1}^{m} a_{i}^{2} & \frac{1}{m} \sum_{i=1}^{m} a_{i} b_{i} \\ \frac{1}{m} \sum_{i=1}^{m} a_{i} b_{i} & \frac{1}{m} \sum_{i=1}^{m} b_{i}^{2} \end{array}\right] P^{T} \end{aligned}

我们发现,要找的PP不是别的,而是能让原始协方差矩阵对角化的PP

换句话说,优化目标变成了寻找一个矩阵PP,满足PCP𝖳PCP^𝖳是一个对角矩阵,并且对角元素按从大到小依次排列,那么P的前K行就是要寻找的基,用P的前K行组成的矩阵乘以X就使得X从N维降到了K维并满足上述优化条件。

最终我们聚焦在协方差矩阵对角化这个问题上。

由上文知道,协方差矩阵CC是一个是对称矩阵,在线性代数上,实对称矩阵有一系列非常好的性质:

1)实对称矩阵不同特征值对应的特征向量必然正交。

2)设特征向量λ\lambda重数为rr,则必然存在rr个线性无关的特征向量对应于λ\lambda,因此可以将这rr个特征向量单位正交化。

由上面两条可知,一个nnnn列的实对称矩阵一定可以找到nn个单位正交特征向量,设这nn个特征向量为e1,e2,,ene_1,e_2,⋯,e_n,我们将其按列组成矩阵:

E=[e1e2 en]E = \begin{bmatrix} e_1 & e_2 & \cdots \ e_n\end{bmatrix}

则对协方差矩阵CC有如下结论:

ETCE=Λ=[λ1λ2λn]E^T C E = \Lambda = \begin{bmatrix} \lambda_1 \\ & \lambda_2 \\ &&\ddots \\ &&&\lambda_n\end {bmatrix}

其中Λ\Lambda为对角矩阵,其对角元素为各特征向量对应的特征值(可能有重复)。 结合上面的公式:

D=PCPTD = PCP^T

其中,DD为对角矩阵,我们可以得到:

P=ETP = E^T

PP是协方差矩阵CC的特征向量单位化后按行排列出的矩阵,其中每一行都是CC的一个特征向量。如果设PP按照Λ\Lambda中特征值的从大到小,将特征向量从上到下排列,则用PP的前KK行组成的矩阵乘以原始数据矩阵XX,就得到了我们需要的降维后的数据矩阵YY

7.PCA算法

总结一下PCA的算法步骤:

设有mmnn维数据。

1)将原始数据按列组成nnmm列矩阵XX

2)将XX的每一行(代表一个特征)进行零均值化,即减去这一行的均值

3)求出协方差矩阵C=1mXX𝖳C=\frac{1}{m}XX^𝖳

4)求出协方差矩阵CC的特征值及对应的特征向量

5)将特征向量按对应特征值大小从上到下按行排列成矩阵,取前kk行组成矩阵PP

6)Y=PXY=PX即为降维到kk维后的数据

8.PCA代码实践

我们这里直接使用python机器学习工具库scikit-learn来给大家演示PCA算法应用(相关知识速查可以查看ShowMeAI文章AI建模工具速查|Scikit-learn使用指南),sklearn工具库中与PCA相关的类都在sklearn.decomposition包里,最常用的PCA类就是sklearn.decomposition.PCA。

1)参数介绍

sklearn中的PCA类使用简单,基本无需调参,一般只需要指定需要降维到的维度,或者降维后的主成分的方差和占原始维度所有特征方差和的比例阈值就可以了。

下面是sklearn.decomposition.PCA的主要参数介绍:

  • n_components:PCA降维后的特征维度数目。

  • whiten:是否进行白化。所谓白化,就是对降维后的数据的每个特征进行归一化,让方差都为1,默认值是False,即不进行白化。

  • svd_solver:奇异值分解SVD的方法,有4个可以选择的值:{‘auto’,‘full’,‘arpack’,‘randomized’}。

除上述输入参数,还有两个PCA类的成员属性也很重要:

  • explained_variance_,它代表降维后的各主成分的方差值。

  • explained_variance_ratio_,它代表降维后的各主成分的方差值占总方差值的比例。

2)代码实例

# 构建数据样本并可视化

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
%matplotlib inline
from sklearn.datasets import make_blobs

# X为样本特征,Y为样本簇类别, 共1000个样本,每个样本3个特征,共4个簇
X, y = make_blobs(n_samples=10000, n_features=3, centers=[[3,3, 3], [0,0,0], [1,1,1], [2,2,2]], cluster_std=[0.2, 0.1, 0.2, 0.2], 
                  random_state =9)
fig = plt.figure()
ax = Axes3D(fig, rect=[0, 0, 1, 1], elev=30, azim=20)
plt.scatter(X[:, 0], X[:, 1], X[:, 2],marker='x')

先不降维,只对数据进行投影,看看投影后的三个维度的方差分布,代码如下:

from sklearn.decomposition import PCA
pca = PCA(n_components=3)
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)

输出如下:

[0.98318212 0.00850037 0.00831751]
[3.78521638 0.03272613 0.03202212]

可以看出投影后三个特征维度的方差比例大约为98.3%:0.8%:0.8%。投影后第一个特征占了绝大多数的主成分比例。现在我们来进行降维,从三维降到2维,代码如下:

pca = PCA(n_components=2)
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)

输出如下:

[0.98318212 0.00850037]
[3.78521638 0.03272613]

这个结果其实可以预料,因为上面三个投影后的特征维度的方差分别为:[ 3.78521638 0.03272613],投影到二维后选择的肯定是前两个特征,而抛弃第三个特征。为了有个直观的认识,我们看看此时转化后的数据分布,代码如下:

X_new = pca.transform(X)
plt.scatter(X_new[:, 0], X_new[:, 1],marker='x')
plt.show()

从上图可以看出,降维后的数据依然清楚可见之前三维图中的4个簇。现在我们不直接指定降维的维度,而指定降维后的主成分方差和比例,来试验一下。

pca = PCA(n_components=0.9)
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)
print(pca.n_components_)

我们指定了主成分至少占90%,输出如下:

[0.98318212]
[3.78521638]
1

可见只有第一个投影特征被保留。这也很好理解,我们的第一个主成分占投影特征的方差比例高达98%。只选择这一个特征维度便可以满足90%的阈值。我们现在选择阈值99%看看,代码如下:

pca = PCA(n_components=0.99)
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)
print(pca.n_components_)

此时的输出如下:

[0.98318212 0.00850037]
[3.78521638 0.03272613]
2

这个结果也很好理解,因为我们第一个主成分占了98.3%的方差比例,第二个主成分占了0.8%的方差比例,两者一起可以满足我们的阈值。最后我们看看让MLE算法自己选择降维维度的效果,代码如下:

pca = PCA(n_components= 'mle',svd_solver='full')
pca.fit(X)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_)
print(pca.n_components_)

输出结果如下:

[0.98318212]
[3.78521638]
1

可见由于我们的数据的第一个投影特征的方差占比高达98.3%,MLE算法只保留了我们的第一个特征。

更多无监督学习的算法模型总结可以查看ShowMeAI的文章 AI知识技能速查 | 机器学习-无监督学习

参考链接

ShowMeAI相关文章推荐

ShowMeAI系列教程推荐