第8章 降维
写在前面
参考书
《机器学习实战——基于Scikit-Learn和TensorFlow》
工具
python3.5.1,Jupyter Notebook, Pycharm
数据降维的两种主要方法
- 投影
- 流形学习
- 流形假设:也称为流形假说,认为大多数现实世界的高维度数据集存在一个低维度的流形来重新表示。这个假设通常是凭经验观察的。
- 流形假设通常还伴随着一个隐含的假设:如果能用低维空间的流形表示,手头的任务(例如分类或者回归)将变得更简单。
PCA
-
主成分分析(PCA)是迄今为止最流行的降维算法。它先是识别出最接近数据的超平面,然后将数据投影其上。
-
比较原始数据集与其轴上的投影之间的均方距离,使这个均方距离最小的轴使最合理的选择。这也正是PCA背后的简单思想。
-
奇异值分解(SVD)
import numpy as np X = np.random.random((50, 2)) X_centered = X - X.mean(axis=0) U, s, V = np.linalg.svd(X_centered) c1 = V.T[:, 0] c2 = V.T[:, 1] W2 = V.T[:, :1] W2D = X_centered.dot(W2)
-
PCA实战
from sklearn.decomposition import PCA pca = PCA(n_components=1) X2D = pca.fit_transform(X)
-
components_:访问主成分(它包含的主成分使水平向量)。举例来说,第一个主成分即等于
pca.components_.T[:, 0]
-
explained_variance_ratio_:方差解释率。它表示每个主成分轴对整个数据集方差的贡献度。
-
inverse_transform():将压缩后的数据解压缩回到原来的shape。原始数据和重建数据(压缩之后解压缩)之间的均方距离成为重建误差。
-
-
选择正确数量的维度:
- 设置n_components=d,若d是整数,则设置为降维后的维度数;若d是小数,则表示希望保留的方差比。
- 还可以将解释方差绘制关于维度数量的函数(绘制np.cumsum即可)。曲线通常都会有一个拐点,说明方差停止快速增长。你可以将其视为数据集的本征维数。
-
增量PCA(IPCA)
-
增量主成分分析
-
可以将训练集分成一个个小批量,一次给IPCA
import numpy as np from sklearn.decomposition import IncrementalPCA from sklearn.datasets import fetch_mldata n_batches = 100 mnist = fetch_mldata('MNIST original') X_mnist = mnist["data"] inc_pca = IncrementalPCA(n_components=154) for X_batch in np.array_split(X_mnist, n_batches): inc_pca.partial_fit(X_batch) X_mnist_reduced = inc_pca.transform(X_mnist)
-
还可以使用Numpy的memmap类,它允许你巧妙地操控一个存储在磁盘二进制文件的大型数组,就好似它也完全在内存里一样,而这个类(memmap)仅在需要时加载内存中需要的数据。
-
内存映射,当需要存取一个很大的文件里面的小部分的数据的时候,读入整个文件显然是非常的浪费资源的。于是要使用到内存映射的方法。
-
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
- 这是一个随机算法,可以快速找到前d个主成分的近似值。
- 它的计算复杂度是$O(m imes d^2) + O(d^3)$,而不是$O(m imes n^2) + O(n^3)$。
- 所以当d远小于n时,它比前面提到的算法要快得多。
- 使用时,设置PCA中的参数svd_solver=“randomized”
核主成分分析(kPCA)
-
将核技巧应用于PCA,使复杂的非线性投影降维成为可能。
-
它擅长在投影后保留实例的集群,有时甚至也能展开近似于一个扭曲流形的数据集。
from sklearn.decomposition import KernelPCA rbf_pca = KernelPCA(n_components=2, kernel='rbf', gamma=0.04) X_reduced = rbf_pca.fit_transform(X)
选择核函数核调整超参数
-
使用网格搜索,kPCA搭配分类器(逻辑回归等),来找到使任务性能最佳的核和超参数。
from sklearn.model_selection import GridSearchCV from sklearn.linear_model import LogisticRegression from sklearn.decomposition import KernelPCA from sklearn.pipeline import Pipeline import numpy as np clf = Pipeline([ ("kpca", KernelPCA(n_components=2)), ("log_reg", LogisticRegression()) ]) param_grid = [{ "kpca__gamma": np.linspace(0.03, 0.05, 10), "kpca__kernel": ["rbf", "sigmoid"] }] grid_search = GridSearchCV(clf, param_grid, cv=3) grid_search.fit(X, y)
-
重建原像
-
还有一种完全不受监督的方法,就是选择重建误差最低的核和超参数。
-
如果我们对一个已经降维的实例进行线性PCA逆转换,重建的点将存在于特征空间,而不是原始空间中。而这里特征空间是无限维度的,所以我们无法计算出重建点,因此也无法计算出真实的重建误差。
-
我们可以在原始空间中找到一个点,使其映射接近于重建点。这被称为重建原像。
-
一旦有了这个原像,你就可以测量它到原始实例的平方距离。最后,便可以选择使这个重建原像误差最小化的核和超参数。
-
执行重建的方法:训练一个监督式回归模型,以投影后的实例作为训练集,并以原始实例作为目标。(设置KernelPCA中的fit_inverse_transform=True)
rbf_pca = KernelPCA(n_components=2, kernel="rbf", gamma=0.0433, fit_inverse_transform=True) X_reduced = rbf_pca.fit_transform(X) X_preimage = rbf_pca.inverse_transform(X_reduced)
计算重建原像误差:
from sklearn.metrics import mean_squared_error mean_squared_error(X, X_preimage)
-
现在,你可以使用交叉验证的网格搜索,来寻找使这个原像重建误差最小的核和超参数。
-
局部线性嵌入(LLE,Locally Linear Embedding)
-
局部线性嵌入使另一种非常强大的非线性降维(NLDR)技术,不像之前的算法依赖于投影,它是一种流形学习技术。
-
LLE首先测量每个算法如何与其最近的邻居线性相关,然后为训练集寻找一个能最大程度保留这些局部关系的低维表示。
-
这使得它特别擅长展开弯曲的流形,特别使没有太多噪声时。
from sklearn.manifold import LocallyLinearEmbedding lle = LocallyLinearEmbedding(n_components=2, n_neighbors=10) X_reduced = lle.fit_transform(X)
-
计算复杂度:
- 寻找k个最近邻为:$O(m log(m)n log(k))$
- 优化权重为:$O(mnk^3)$
- 构建低维表示:$O(dm^2)$
- 很不幸,最后一个表达式里的$m^2$说明这个算法很难扩展应用到大型数据集。
其他降维技巧
- 多维缩放(MDS):保持实例之间的距离,降低维度。
- 等度量映射(Isomap):将每个实例与其最近的邻居连接起来,创建链接图形,然后保留实例之间的这个测地距离,降低维度。图中两个节点之间的测地距离是两个节点之间最短路径上的节点数。
- t-分布随机近邻嵌入(t-SNE,T-distributed Stochastic Neighbor Embedding):在降低维度时,试图让相近的实例彼此靠近,不相似的实例彼此远离。它主要用于可视化,尤其是将高维空间中的实例集群可视化。
- 线性判别式分析(Linear Discriminant Analysis,LDA):实际上是一种分类算法,但是在训练过程中,它会学习类别之间最有区别的轴,而这个轴正好可以用来定义投影数据的超平面。这样做的好处在于投影上的类别之间会尽可能的分开,所以在运行其他分类算法——比如SVM分类器之前,LDA是一个不错的降维手段。
练习摘抄
-
降低数据集维度的主要动机是什么?有什么主要弊端?
降维的主要动机是:
- 为了加速后续的训练算法(在某些情况下,也可能是为了消除噪声和冗余特征,使训练算法性能更好)。
- 为了将数据可视化,并从中获得洞悉,了解重要的特征。
- 只是为了节省空间(压缩)
主要的弊端使:
- 丢失部分信息,可能后续训练算法的性能降低
- 可能使计算密集型的
- 为机器学习流水线增条了些许复杂度
- 转换后的特征往往难以解释
-
什么是维度的诅咒?
维度的诅咒是指寻多在低维空间中不存在的问题,在高维空间中发生。在机器学习领域,一个常见的现象是随机抽样的高维向量通常非常稀疏,提升了过度拟合的风险,同时也使得在没有充足训练数据的情况下,要识别数据中的模式非常困难。
-
一旦数据集被降维,是否还有可能逆转?如果有,怎么做?如果没有,为什么?
一旦使用我们讨论的任意算法减少了数据集的维度,几乎不可能再将操作完美的逆转,因为在降维过程中必然丢失了一部分信息。虽然有一些算法(例如PCA)拥有简单的逆转换过程,可以重建出与原始数据集相似的数据集,但是也有一些算法不能实现逆转(例如t-SNE)。
-
PCA可以用来给高度非线性数据集降维么?
对大多数数据集来说,PCA可以用来进行显著降维,即便是高度非线性的数据集,因为它至少可以消除无用的维度。但是如果不存在无用的维度(例如瑞士卷),那么使用PCA降维将会损失太多信息。你希望的是将瑞士卷展开,而不是将其压扁。
-
常规PCA,增量PCA,随机PCA及核PCA各适用于何种情况?
- 常规PCA是默认选择,但是它仅适用于内存足够处理训练集的时候。
- 增量PCA对于内存无法支持的大型数据集非常有用,当时它比常规PCA要来得慢一些,所以如果内存能够支持,还是应该使用常规PCA。当你需要随时应用PCA来处理每次新增的实例时,增量PCA对于在线任务同样有用。
- 当你想大大降低维度数量,并且内存足够支持数据集时,使用随机PCA非常有效。它比常规PCA快得多。
- 最后对于非线性数据集,使用核化PCA行之有效。
-
如何在你的数据集上评估降维算法的性能?
- 直观来说,如果降维算法能够消除许多维度并且不会丢失太多信息,那么这就算是一个好的降维算法。
- 进行衡量的方法之一是应用逆转换然后测量重建误差。
- 然而并不是所有的降维算法都提供了逆转换。还有一种选择,如果你将降维当作一个预处理过程,用在其他机器学习算法(比如随机森林分类器)之前,那么可以通过简单的测量第二个算法的性能来进行评估。如果降维过程没有损失太多信息,那么第二个算法的性能应该跟使用原始数据集一样好。
-
链接两个不同的降维算法有意义吗?
链接两个不同的降维算法绝对是有意义的。常见的例子是使用PCA快速去除大量无用的维度,然后应用另一种更慢的降维算法,如LLE。这样两步走的策略产生的结果可能与仅使 用LLE相同,但是时间要短得多。
我的CSDN:https://blog.csdn.net/qq_21579045
我的博客园:https://www.cnblogs.com/lyjun/
我的Github:https://github.com/TinyHandsome
纸上得来终觉浅,绝知此事要躬行~
欢迎大家过来OB~
by 李英俊小朋友