降维算法

降维算法中的”降维“,指的是降低特征矩阵中特征的数量。降维的目的是为了让算法运算更快,效果更好。对图像来说,维度就是图像中特征向量的数量。

sklearn中的降维算法

sklearn中降维算法都被包括在模块decomposition中

PCA

在降维过程中,我们会减少特征的数量,这意味着删除数据,数据量变少则表示模型可以获取的信息会变少,模型的表现可能会因此受影响。同时,在高维数据中,必然有一些特征是不带有有效的信息的(比如噪音),或者有一些特征带有的信息和其他一些特征是重复的(比如一些特征可能会线性相关)。我们希望能够找出一种办法来帮助我们衡量特征上所带的信息量,让我们在降维的过程中,能够即减少特征的数量,又保留大部分有效信息——将那些带有重复信息的特征合并,并删除那些带无效信息的特征等等——逐渐创造出能够代表原特征矩阵大部分信息的,特征更少的,新特征矩阵。

在特征过程中,我们有说过一种特别的特征选择方法:方差过滤。如果一个特征的方差很小,则意味着这个特征上很可能有大量取值都相同(比如90%都是1,只有10%是0,甚至100%是1),那这一个特征的取值对样本而言就没有区分度,这种特征就不带有有效信息。从方差的这种应用就可以推断出,如果一个特征的方差很大,则说明这个特征上带有大量的信息。因此,在降维中,PCA使用的信息量衡量指标,就是样本方差,又称可解释性方差,方差越大,特征所带的信息量越多。

Var代表一个特征的方差,n代表样本量,xi代表一个特征中的每个样本取值,xhat代表这一列样本的均值。

PCA和特征选择技术都是特征工程的一部分,他们有什么不同?

特征工程中有三种方式:特征提取,特征创造和特征选择。仔细观察上面的降维例子和上周我们讲解过的特征
选择,你发现有什么不同了吗?
特征选择是从已存在的特征中选取携带信息最多的,选完之后的特征依然具有可解释性,我们依然知道这个特征在原数据的哪个位置,代表着原数据上的什么含义。而PCA,是将已存在的特征进行压缩,降维完毕后的特征不是原本的特征矩阵中的任何一个特征,而是通过某些方式组合起来的新特征。通常来说,在新的特征矩阵生成之前,我们无法知晓PCA都建立了怎样的新特征向量,新特征矩阵生成之后也不具有可读性,我们无法判断新特征矩阵的特征是从原数据中的什么特征组合而来,新特征虽然带有原始数据的信息,却已经不是原数据上代表着的含义了。以PCA为代表的降维算法因此是特征创造(feature creation,或feature construction)的一种。

重要参数

n_compontents:n_components是我们降维后需要的维度,即降维后需要保留的特征数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
iris = load_iris()
y = iris.target
X = iris.data
pca = PCA(n_components=2) #实例化
#也可以一步到位,x_dr=pca.fit_transform(X)
pca = pca.fit(X) #拟合模型
X_dr = pca.transform(X) #获取新矩阵
"""可以写三行代码,也可以写成for循环
plt.figure()
plt.scatter(X_dr[y==0, 0], X_dr[y==0, 1], c="red", label=iris.target_names[0])
plt.scatter(X_dr[y==1, 0], X_dr[y==1, 1], c="black", label=iris.target_names[1])
plt.scatter(X_dr[y==2, 0], X_dr[y==2, 1], c="orange", label=iris.target_names[2])
plt.legend()
plt.title('PCA of IRIS dataset')
plt.show()
"""
colors = ['red', 'black', 'orange']
plt.figure()
for i in [0, 1, 2]:
plt.scatter(X_dr[y == i, 0],X_dr[y == i, 1],alpha=.7,c=colors[i],label=iris.target_names[i])
plt.legend()
plt.title('PCA of IRIS dataset')
plt.show()

选择最好的n_components

累积可解释方差贡献率曲线

当参数n_components中不填写任何值,则默认返回min(X.shape)个特征,一般来说,样本量都会大于特征数目,所以什么都不填就相当于转换了新特征空间,但没有减少特征的个数。一般来说,不会使用这种输入方式。但我们却可以使用这种输入方式来画出累计可解释方差贡献率曲线,以此选择最好的n_components的整数取值。累积可解释方差贡献率曲线是一条以降维后保留的特征个数为横坐标,降维后新特征矩阵捕捉到的可解释方差贡献率为纵坐标的曲线,能够帮助我们决定n_components最好的取值。

1
2
3
4
5
6
7
8
9
10
#接上面的代码
import numpy as np
pca_line = PCA().fit(X)
#属性explained_variance_ratio,查看降维后每个新特征向量所占的信息量占原始数据总信息量的百分比
#又叫做可解释方差贡献率
plt.plot([1,2,3,4],np.cumsum(pca_line.explained_variance_ratio_))
plt.xticks([1,2,3,4]) #这是为了限制坐标轴显示为整数
plt.xlabel("number of components after dimension reduction")
plt.ylabel("cumulative explained variance ratio")
plt.show()
最大似然估计自选超参数

除了输入整数,n_components还有哪些选择呢?让PCA用最大似然估计(maximum likelihood estimation)自选超参数的方法,输入“mle”作为n_components的参数输入,就可以调用这种方法。

1
2
3
4
5
pca_mle = PCA(n_components="mle")
pca_mle = pca_mle.fit(X)
X_mle = pca_mle.transform(X)
#从这里看出,mle自动为我们选了几个特征
print(X_mle.shape)
按信息占比选超参数

输入[0,1]之间的浮点数,并且让参数svd_solver ==’full’,表示希望降维后的总解释性方差占比大于n_components指定的百分比,即是说,希望保留百分之多少的信息量。

1
2
3
4
5
pca_f = PCA(n_components=0.97,svd_solver="full")
pca_f = pca_f.fit(X)
X_f = pca_f.transform(X)
#属性explained_variance_ratio,查看降维后每个新特征向量所占的信息量占原始数据总信息量的百分比
print(pca_f.explained_variance_ratio_)

PCA中的SVD

其实上面的svd_solver是奇异值分解器。其实SVD可以跳过数学,不计算协方差矩阵,直接找出一个新特征向量组成的n维向量。也就是说,奇异值分解可以不计算协方差矩阵等等计算冗长的矩阵,就直接求出新特征空间和降维后的特征矩阵。简而言之,SVD在矩阵分解中的过程比PCA简单快速。

重要参数

svd_solver

参数svd_solver是在降维过程中,用来控制矩阵分解的一些细节的参数。有四种模式可选:”auto”, “full”, “arpack”,”randomized”,默认”auto”。

“auto”:基于X.shape和n_components的默认策略来选择分解器:如果输入数据的尺寸大于500x500且要提取的特征数小于数据最小维度min(X.shape)的80%,就启用效率更高的”randomized“方法。否则,精确完整的SVD将被计算,截断将会在矩阵被分解完成后有选择地发生

“full”:从scipy.linalg.svd中调用标准的LAPACK分解器来生成精确完整的SVD,适合数据量比较适中,计算时间充足的情况。

“arpack”:从scipy.sparse.linalg.svds调用ARPACK分解器来运行截断奇异值分解(SVD truncated),分解时就将特征数量降到n_components中输入的数值k,可以加快运算速度,适合特征矩阵很大的时候,但一般用于特征矩阵为稀疏矩阵的情况,此过程包含一定的随机性。

“randomized”,通过Halko等人的随机方法进行随机SVD。在”full”方法中,分解器会根据原始数据和输入的n_components值去计算和寻找符合需求的新特征向量,但是在”randomized”方法中,分解器会先生成多个随机向量,然后一一去检测这些随机向量中是否有任何一个符合我们的分解需求,如果符合,就保留这个随机向量,并基于这个随机向量来构建后续的向量空间。这个方法已经被Halko等人证明,比”full”模式下计算快很多,并且还能够保证模型运行效果。适合特征矩阵巨大,计算量庞大的情况。

random_state

参数random_state在参数svd_solver的值为”arpack” or “randomized”的时候生效,可以控制这两种SVD模式中的随机模式。通常我们就选用”auto“,不必对这个参数纠结太多。

PCA参数、属性和接口

参数列表

属性列表

接口列表

PCA对手写数字数据集的降维

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
data = pd.read_csv(r"digit recognizor.csv")
X = data.iloc[:,1:]
y = data.iloc[:,0]
pca_line = PCA().fit(X)
plt.figure(figsize=[20,5])
plt.plot(np.cumsum(pca_line.explained_variance_ratio_))
plt.xlabel("number of components after dimension reduction")
plt.ylabel("cumulative explained variance ratio")
plt.show()

接着降维后维度的学习曲线,继续缩小最佳维度的范围

1
2
3
4
5
6
7
8
9
score = []
for i in range(1,101,10):
X_dr = PCA(i).fit_transform(X)
once = cross_val_score(RFC(n_estimators=10,random_state=0)
,X_dr,y,cv=5).mean()
score.append(once)
plt.figure(figsize=[20,5])
plt.plot(range(1,101,10),score)
plt.show()

细化学习曲线,找出降维后的最佳维度

1
2
3
4
5
6
7
8
score = []
for i in range(10,25):
X_dr = PCA(i).fit_transform(X)
once = cross_val_score(RFC(n_estimators=10,random_state=0),X_dr,y,cv=5).mean()
score.append(once)
plt.figure(figsize=[20,5])
plt.plot(range(10,25),score)
plt.show()

导入找出的最佳维度进行降维,查看模型效果

1
2
x_dr=PCA(23).fit_transform(X)
print(cross_val_score(RFC(n_estimators=100,random_state=0),x_dr,y,cv=5).mean())
----本文结束,感谢您的阅读。如有错,请指正。----
大哥大嫂过年好!支持我一下呗
0%