diff --git "a/docs/8.\351\231\215\347\273\264.md" "b/docs/8.\351\231\215\347\273\264.md" index 9fdeb5a8b004145dce3a8f198acbb375de40a3dd..c48018c3e320933fd5cf78449b615145cae3f22b 100644 --- "a/docs/8.\351\231\215\347\273\264.md" +++ "b/docs/8.\351\231\215\347\273\264.md" @@ -111,3 +111,152 @@ c2=V.T[:,1] > 警告:PCA假定数据集以原点为中心。正如我们将看到的,Scikit-Learn的PCA类负责为您的数据集中心化处理。但是,如果您自己实现PCA(如前面的示例所示),或者如果您使用其他库,不要忘记首先要先对数据做中心化处理。 +### 投影到d维空间 + +一旦确定了所有的主成分,你就可以通过将数据集投影到由前d个主成分构成的超平面上,从而将数据集的维数降至d维。选择这个超平面可以确保投影将保留尽可能多的方差。例如,在图8-2中,3D数据集被投影到由前两个主成分定义的2D平面,保留了大部分数据集的方差。因此,2D投影看起来非常像原始3D数据集。 + +为了将训练集投影到超平面上,可以简单地通过计算训练集矩阵X和Wd的点积,Wd定义为包含前d个主成分的矩阵(即由VT的前d列组成的矩阵),如等式8-2所示。 + +等式 8-2 将训练集投影到d维空间 + +Xd-proj = X · Wd + +下面的Python代码将训练集投影到由前两个主成分定义的超平面上: + +```Python +W2=V.T[:,:2] +X2D=X_centered.dot(W2) +``` + +好了你已经知道这个东西了!你现在已经知道如何给任何一个数据集降维而又能尽可能的保留原数据集的方差了。 + +### 使用Scikit-Learn + +Scikit-Learn的PCA类使用SVD分解来实现,就像我们之前做的那样。以下代码应用PCA将数据集的维度降至两维(请注意,它会自动处理数据的中心化): + +```Python +from sklearn.decomposition import PCA + +pca=PCA(n_components=2) +X2D=pca.fit_transform(X) +``` + +将PCA转化器应用于数据集后,可以使用`components_`访问每一个主成分(注意,它返回以PC作为水平向量的矩阵,因此,如果我们想要获得第一个主成分则可以写成`pca.components_.T[:,0]`)。 + +### 方差解释率(Explained Variance Ratio) + +另一个非常有用的信息是每个主成分的方差解释率,可通过`explained_variance_ratio_`变量获得。它表示位于每个主成分轴上的数据集方差的比例。例如,让我们看一下图8-2中表示的三维数据集前两个分量的方差解释率: + +``` +>>> print(pca.explained_variance_ratio_) +array([0.84248607, 0.14631839]) +``` + +这表明,84.2%的数据集方差位于第一轴,14.6%的方差位于第二轴。第三轴的这一比例不到1.2%,因此可以认为它可能没有包含什么信息。 + +### 选择正确的维度 + +通常我们倾向于选择加起来到方差解释率能够达到足够占比(例如95%)的维度的数量,而不是任意选择要降低到的维度数量。当然,除非您正在为数据可视化而降低维度--在这种情况下,您通常希望将维度降低到2或3。 + +下面的代码在不降维的情况下进行PCA,然后计算出保留训练集方差95%所需的最小维数: + +```Python +pca=PCA() +pac.fit(X) +cumsum=np.cumsum(pca.explained_variance_ratio_) +d=np.argmax(cumsum>=0.95)+1 +``` + +你可以设置`n_components = d`并再次运行PCA。但是,有一个更好的选择:不指定你想要保留的主成分个数,而是将`n_components`设置为0.0到1.0之间的浮点数,表明您希望保留的方差比率: + +```Python +pca=PCA(n_components=0.95) +X_reduced=pca.fit_transform(X) +``` + +另一种选择是画出方差解释率关于维数的函数(简单地绘制`cumsum`;参见图8-8)。曲线中通常会有一个肘部,方差解释率停止快速增长。您可以将其视为数据集的真正的维度。在这种情况下,您可以看到将维度降低到大约100个维度不会失去太多的可解释方差。 + +![]() + +图 8-8 可解释方差关于维数的函数 + +### PCA压缩 + +显然,在降维之后,训练集占用的空间要少得多。例如,尝试将PCA应用于MNIST数据集,同时保留95%的方差。你应该发现每个实例只有150多个特征,而不是原来的784个特征。因此,尽管大部分方差都保留下来,但数据集现在还不到其原始大小的20%!这是一个合理的压缩比率,您可以看到这可以如何极大地加快分类算法(如SVM分类器)的速度。 + +通过应用PCA投影的逆变换,也可以将缩小的数据集解压缩回784维。当然这并不会返回给你最原始的数据,因为投影丢失了一些信息(在5%的方差内),但它可能非常接近原始数据。原始数据和重构数据之间的均方距离(压缩然后解压缩)被称为重构误差(reconstruction error)。例如,下面的代码将MNIST数据集压缩到154维,然后使用`inverse_transform()`方法将其解压缩回784维。图8-9显示了原始训练集(左侧)的几位数字在压缩并解压缩后(右侧)的对应数字。您可以看到有轻微的图像质量降低,但数字仍然大部分完好无损。 + +```Python +pca=PCA(n_components=154) +X_mnist_reduced=pca.fit_transform(X_mnist) +X_mnist_recovered=pca.inverse_transform(X_mnist_reduced) +``` + +![]() + +图 8-9 MNIST保留95方差的压缩 + +逆变换的公式如等式8-3所示 + +等式 8-3 PCA逆变换,回退到原来的数据维度 + +Xrecovered = Xd-proj · WdT + +### 增量PCA(Incremental PCA) + +先前PCA实现的一个问题是它需要在内存中处理整个训练集以便SVD算法运行。幸运的是,我们已经开发了增量PCA(IPCA)算法:您可以将训练集分批,并一次只对一个批量使用IPCA算法。这对大型训练集非常有用,并且可以在线应用PCA(即在新实例到达时即时运行)。 +下面的代码将MNIST数据集分成100个小批量(使用NumPy的`array_split()`函数),并将它们提供给Scikit-Learn的`IncrementalPCA`类,以将MNIST数据集的维度降低到154维(就像以前一样)。请注意,您必须对每个最小批次调用`partial_fit()`方法,而不是对整个训练集使用`fit()`方法: +```Python +from sklearn.decomposition import IncrementalPCA + +n_batches=100 +inc_pca=IncrementalPCA(n_components=154) +for X_batch in np.array_spplit(X_mnist,n_batches): + inc_pca.partial_fit(X_batch) +X_mnist_reduced=inc_pca.transform(X_mnist) +``` + +或者,您可以使用NumPy的`memmap`类,它允许您操作存储在磁盘上二进制文件中的大型数组,就好像它完全在内存中;该类仅在需要时加载内存中所需的数据。由于增量PCA类在任何时间内仅使用数组的一小部分,因此内存使用量仍受到控制。这可以调用通常的`fit()`方法,如下面的代码所示: + +```Python +X_mm=np.memmap(filename,dtype='float32',mode='readonly',shape=(m,n)) +batch_size=m//n_batches +inc_pca=IncrementalPCA(n_components=154,batch_size=batch_size) +inc_pca.fit(X_mm) +``` + +### 随机PCA(Randomized PCA) + +Scikit-Learn提供了另一种执行PCA的选择,称为随机PCA。这是一种随机算法,可以快速找到前d个主成分的近似值。它的计算复杂度是O ( m × d2 ) + O ( d3 ),而不是O ( m × n2 ) + O ( n3 ),所以当d远小于n时,它比之前的算法快得多。 + +```Python +rnd_pca=PCA(n_components=154,svd_solver='randomized') +X_reduced=rnd_pca.fit_transform(X_mnist) +``` + +## 核PCA(Kernel PCA) + +在第5章中,我们讨论了核技巧,一种将实例隐式映射到非常高维空间(称为特征空间)的数学技术,让支持向量机可以应用于非线性分类和回归。回想一下,高维特征空间中的线性决策边界对应于原始空间中的复杂非线性决策边界。 + +事实证明,同样的技巧可以应用于PCA,从而可以执行复杂的非线性投影来降低维度。这就是所谓的核PCA(kPCA)。它通常能够很好地保留投影后的簇,有时甚至可以展开分布近似于扭曲流形的数据集。 + +例如,下面的代码使用Scikit-Learn的`KernelPCA`类来执行带有RBF核的kPCA(有关RBF内核和其他核的更多详细信息,请参阅第5章): + +```Python +from sklearn.decomposition import KernelPCA + +rbf_pca=KernelPCA(n_components=2,kernel='rbf',gamma=0.04) +X_reduced=rbf_pca.fit_transform(X) +``` + +图8-10展示了使用线性核(等同于简单的使用PCA类),RBF核,sigmoid核(逻辑)对瑞士卷降到2维。 + +![]() + +图 8-10 使用不同核的kPCA将瑞士卷降到2维 + + + + + +