阅读书籍为《Hands-On Machine Learning with Scikit-Learn & TensorFlow》王静源等翻译的中文译版《机器学习实战,基于 Scikit-Learn 和 TensorFlow》
本文中所有图片均来自于书籍相关部分截图。
关于维度
- 维度:数据的特征数,比如有两个特征,就是二维;
- 维度之灾:数据集特征过多,模型训练速度过慢难以忍受;
- 降维的作用:提高特征数目较多数据集的训练速度;
- 降维的劣势:降低模型工作性能;
- 降维的优势:除了提升速度,对于2维3维的数据更易可视化,发现数据分布的端倪。
投影降维法
去除原始数据集中影响较小的特征,以达到降维的目的。
- 找出最接近数据分布的超平面
去除N维数据中影响不大的X(若干)个特征。 - 投影
将原始数据集投影在剩下特征定义成的(N-X)维的超平面上。
以下介绍的两种不同方法均致力于怎样寻找出最重要的特征,放弃不重要的特征。
主成分分析PCA
主成分分析法使用SVD奇异值分析获得的降序的成分矩阵:
-
SVD奇异值分解:
将原始数据集拆分三个子集,第三个分出来的子集就是我们求解的降序成分矩阵(C1最主要,Cn最次要):
代码实现如下:import numpy as np from sklearn.datasets import load_iris iris = load_iris() X = iris["data"] X_centered = X - X.mean(axis=0) U, s, V = np.linalg.svd(X_centered) c1 = V.T[:, 0] c2 = V.T[:, 1]
-
低维投影 计算好主成分后,如何低维投影:
这里W矩阵为前d个重要成分组成的主成分矩阵:
代码实现如下:w2 = V.T[:, :2] X2D = X_centered.dot(w2)
-
使用sklearn实现PCA:
from sklearn.decomposition import PCA //n_components=2 指定保留前两重要成分 pca = PCA(n_components=2) X2D = pca.fit_transform(X)
结果与上述SVD结果一致:
在上述的注释中可见直接将目标维度指定为2,那么一般我们如何获取目标维度?
PCA函数提供方差解释率explained_variance_ratio_属性表示各特征的重要性。
这是鸢尾花数据集四个特征分别的方差解释率,可见前两个特征已经占据了97%。所以选目标维度为2:
一般情况下:我们选择95%为判断标准,选择方差解释率之和大于等于95%的最小个数为目标维度。
sklearn获得目标维度://方式1: cumsum = np.cumsum(pca.explained_variance_ratio_) d = np.argmax(cumsum >= 0.95) + 1
//方式2:将n_components指定为[0.0-1.0]内的浮点数表示希望获取的精度 //然后再使用转换函数就会直接获得处理好的目标维度数据 pca = PCA(n_components=0.95) X_new = pca.fit_transform(X)
增量PCA
-
我们在前面的章节已经了解过增量的含义:每次只加载一部分数据进行计算。
-
由于SVD的算法依赖与整个数据的计算,当需要计算超过计算机处理范围的数据集时,便无法正常工作。
-
此时除了增量形式的分批次加载数据之外,还需要一个可以适应部分数据计算的算法。
-
sklearn针对这个问题提供了增量PCA(IPCA)算法处理大型数据集:
import numpy as np from sklearn.decomposition import IncrementalPCA n_batches = 100 inc_pca = IncrementalPCA(n_components=154) for X_batch in np.array(X, n_batches): inc_pca.partial_fit(X_batch) X_new = inc_pca.transform(X)
随机PCV
-
除了增量PCA之外,sklearn还提供了更快的随机PCA:
当进入新数据集时,先分析前d个主成分的近似值。这样时间复杂度就从:O(mnn)+O(nnn)降低到O(mdd)+O(ddd)
rnd_pca = PCA(n_components=154, svd_solver="randomized") X_new = rnd_pca.transform(X)
核主成分分析KPCV
-
·
关于核,我们在第五章已经有了稍微的了解:通过巧妙的数学计算避免维度爆炸而直接得出结果
同样的,核技巧也可以使用在主成分分析上用来降维,使得非线性投影降维 成为可能。这就是核主成分分析(kernel PCA)。from sklearn.decomposition import KernelPCA K_pca = KernelPCA(n_components=2, kernel="rbf", gamma=0.04) X_new = K_pca.transform(X)
下图展示了不同核对数据进行2D降维投影
选择核函数核调整超参数:
由于KPCA是无监督学习算法,而我们降维是为监督学习做准备,所以可以使用网格搜索来找到最佳的核和最佳超参数。下面我们将展示一段代码:先建立一个KPCA流水线将数据降到二维,再建立一个流水线进行逻辑回归分类。逻辑回归分类时利用网格搜索为KPCA找到最佳的核核超参数gamma值。import numpy as np from sklearn.decomposition import PCA from sklearn.decomposition import KernelPCA from sklearn.model_selection import GridSearchCV from sklearn.linear_model import LogisticRegression from sklearn.pipeline import Pipeline clf = Pipeline([ ("kpca", KernelPCA(n_components=2)), ("log_reg", LogisticRegression()) ]) parm_grid = [{ "kpca_gamma": np.linspace(0.03, 0.05, 1.0), "kpca_kernel":["rbf", "sigmoid"] }] grid_se = GridSearchCV(clf, parm_grid, cv=3) grid_se.fit(X, y)
流形学习降维法
流形:是指低维的图像在高维空间内扭变,弯曲的图像。比如著名的瑞士卷数据集,是一个2维流形图像在三位空间内卷曲形成。
流形学习降维的主要思想:将在高维内卷曲扭变的图形展开以达到降维的目的。
由于流形图像的特点,如果依赖于投影降维的话会使得数据集损失大量数据,对原始数据集造成破坏,如下, 我们期望得到右图数据,但简单投影却使得数据集发生了严重错误:
目前非线性降维技术(NLDR)中很强大的一个算法就是局部线性嵌入(LLE):
LLE
-
,
局部线性嵌入区别与投影法降维的地方在:拿到数据后,算法首先计算每个实例与其最近邻居之间的线性关系,然后为训练集寻找一个最大程度保留这些局部的线性关系的低维表示。此算法特别适用于解开噪声较小的弯曲流形图像。
代码实现如下:from sklearn.manifold import LocallyLinearEmbedding //n_components=2目标维度2, n_neighbors=10计算当前实例与十个最近邻居之间的线性关系。 lle = LocallyLinearEmbedding(n_components=2, n_neighbors=10) X_new = lle.fit_transform(X)
用LLE展开瑞士卷的效果如下,虽然不是我们最终期望的样子,但是相较于投影法降维的结果而言,数据的前后顺序没有发生严重错误,展开的幅度也比较完整:
LLE工作原理如下:- 识别出据当前实例最近的 n_neighbors=10个邻居;
- 尝试建立邻居数+1个数据点的线性关系,也就是找出一个权重矩阵让实例与这些邻居的距离平方和最小:
- 如果某个实例不是当前实例的最近K个邻居之一,权重值置0.
- 找出最近K个邻居之后求距离平方和。
- 权重矩阵对局部线性关系编码;
- 尽量保留局部线性关系,然后降维;
LLE中,找邻居的时间复杂度为O(mlog(m)nlog(k)), 优化权重为O(mnkkk), 构建低维表示为O(dm*m)。可见构建低维表示的复杂度中有一个平方。这就意味着,这个算法很难应用在大型数据集上。
其他降维法
除了以上的降维方法外,还有其他一些比较流行的降维方法:
- 多维放缩法(MDS):保持实例间距离,降低维度:
- 等度量映射法(Isomap):将每个实例与其最近的邻居连接起来,创建连接图形,然后保留实例之间的测地距离(两个节点之间最短路径上的节点数)降低维度。
- t-分布随机近邻嵌入法(t-SNE) :试图让相似的实例彼此靠近,不相似的实例彼此远离。主要用于可视化,尤其是将高维空间中的实例集群可视化。
- 线性判别(LDA),这是一种分类算法,训练过程中算法学习类别之间最有区别的轴,这个轴用来定义投影的超平面。这样做的好处在于投影上的类别会尽可能分开,所以一般用在其他分类算法之前是一个很不错的选择。