「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

大家好呀,本周第二节课开始。

在前几周的时间里,我们讨论的过拟合、特征选择代码篇中,利用的数据都是关于典型的回归问题。但在降维过程中,为了方便做可视化,采用的数据是分类的数据,从而可以在特征空间里,直接观察不同类别标记样本的离散程度,来定性地认识降维方法的效果。

我们会通过对特征空间做可视化来阐述降维的主要意义。降维会缩减特征空间的维数,新的特征将是原始特征的线性组合(线性降维),降维不仅使得模型的复杂度降低,还可以提高模型的可解释性。比如对数据进行分类的任务,经过降维,在新的特征空间中,分类很可能更容易进行。

我们选用两个典型的分类数据:

1.sklearn的IRIS数据,它有150个样本,4个特征(sepal length,sepal width ,petal length ,petal width ),总共分为三类(Setosa ,Versicolor,Virginica)。

2.sklearn的wine数据,它有178个样本,13个特征(Alcohol ,Malic acid ,Ash等),总共分为三类。

对于 IRIS,我们选取其中的三个特征,可以在特征空间中看到数据的分布:

from mpl_toolkits.mplot3d import Axes3D

from sklearn import datasets

data=datasets.load_iris()

X=data['data']

y=data['target']

ax = Axes3D(plt.figure())

for c,i,target_name in zip('rgb',[0,1,2],data.target_names):

ax.scatter(X[y==i ,0], X[y==i, 1], X[y==i,2], c=c, label=target_name)

ax.set_xlabel(data.feature_names[0])

ax.set_ylabel(data.feature_names[1])

ax.set_zlabel(data.feature_names[2])

ax.set_title("Iris")

plt.legend()

plt.show()

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

图为在三维空间中,三类样本的分布

Versicolor和Virginica这两类交叠在一起,Setosa与这两类都离得特别远,我们在sepal length和sepal width所张成的二维特征空间可以将这组数据表示为:

for c, i, target_name in zip("rgb", [0, 1, 2], target_names):

plt.scatter(X[y == i, 0], X[y == i, 1], c=c, label=target_name)

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

我们用不同的颜色表示不同的类别,可以看出,Versicolor和Virginica这两类仍然纠缠在一起,并没有区分开,这也是特征选择局限性的体现,因为特征选择不改变原始特征,只是从中挑选子集,我们会在后面看到降维的好处。同时,Setosa却仍然与这两类都离得特别远,特征空间上只需要一条直线就可以非常好的区分Setosa和其余两类,我们把这种情况叫做线性可分。这就是我们利用分类数据的好处,我们直接可以在特征空间上看到分类的效果。

如果我们对IRIS用PCA来降维,可以看到:

from sklearn.decomposition import PCA

pca = PCA(n_components=2)

X_p =pca.fit(X).transform(X)

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

降到三维

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

降到二维

可以看出,经过降维,Versicolor和Virginica两类几乎分开,我们就可以说PCA取得了较好的效果,如果我们再继续将PCA处理过的数据继续利用SVM或者贝叶斯分类器去学习,那么运算量将非常大大降低。

对于wine,我同样可以选取其中的三个特征,来得到特征空间的分布:

data=datasets.load_wine()

......

for c,i,target_name in zip('>o*',[0,1,2],target_names):

ax.scatter(X[y==i ,0], X[y==i, 1], X[y==i,2], marker=c, label=target_name)

......

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

为与IRIS区分,三类样本的数据点格式分别为圆形,三角形,雪花。

毫无疑问,我们均可以通过上述方式得到与IRIS一样的分布图,但是在对Wine数据的二维特征空间的观察,并且与做PCA之后的对比图发现,PCA几乎没起到任何效果:

降维前:

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

降维后:

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

这是为什么呢?是PCA的方法不管用了么?可能有的同学已经开始换降维方法,并且认为PCA不适用于这样的数据。

其实,当我们碰到这样的问题时,千万不要急着换降维方法,因为使用PCA的降维技术有一个重要的前提,就是数据要经过标准化。因为我们在对数据的协方差矩阵做特征值分解(奇异值分解)的时候,就默认了数据已经经过了标准化,换而言之,只有数据经过了标准化,低维空间的协方差矩阵才会是:

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

所以我们要先对数据标准化,然后才可以用PCA,直接利用PCA的后果就会很糟糕,数据标准化的处理就是将每个特征对应的数据变成标准的高斯分布:

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

其中,

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

是特征均值,

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

是特征的标准差,在程序上,我们可以对每一列做这样的处理,但在sklearn里面,我们可以通过如下方式来对数据做标准化:

from sklearn.preprocessing import StandardScaler

X=StandardScaler().fit(X).transform(X)

我们把Wine数据做标准化处理,再利用PCA可以得到:

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

经过数据标准化,PCA取得了很好的效果!

接下来,我们把低维空间的维度作为超参数,通过观察测试集上的泛化误差,来看降维对于降低泛化误差的作用。对于 wine数据,我们采用k近邻(K-neighbor)作为分类器,准确率作为性能指标,5折交叉验证,得到泛化误差与维度的关系:

from sklearn.neighbors import KNeighborsClassifieras KNC

from sklearn.model_selectionimport cross_validate

......

test_mse=[]

train_mse=[]

for n in range(1,X.shape[1]):

pca=PCA(n_components=n)

X_new=pca.fit(X).transform(X)

knc=KNC()

scorer='accuracy'

knc_dict=cross_validate(knc,X_new,y,cv=5,scoring=scorer)

test_mse.append(lr_dict['test_score'].mean())

train_mse.append(lr_dict['train_score'].mean())

......

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

从图中可以看出,维度为5和2的时候,测试集的泛化误差最低(体现为高准确率),训练误差一直比测试误差小(体现为训练曲线一直在测试曲线上方),也正是拟合能力和泛化能力的比较。可以说明我们用PCA的方法降低了测试误差。

除此之外,我们还可以引入LDA这样一种有监督的降维技术,因为多利用了目标的信息,所以可以预想到它要比PCA表现的更好:

from sklearn.discriminant_analysis importLinearDiscriminantAnalysis as LDA

lda = LDA(n_components=2)

X_r =lda.fit(X,y).transform(X)

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

可以看出,对于IRIS数据,PCA和LDA均无明显的差别。

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

但对于Wine数据,LDA寻找到的低维空间非常明显的优于PCA,三类样本全部分开,且同类样本之间更为密集。

最后,我们利用wine数据,通过k近邻学习器,在维数等于2的时候,比较LDA和PCA的准确率:

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

可以发现,LDA因为是有监督的降维方式,利用了更多的信息,在这组数据上,用到了k近邻的方法,也取得了更好的效果。事实上,我们做降维的目的就在于,既要削减模型的变量,又要保留尽可能多的信息。即便放在整个机器学习来看,有监督的学习一般而言要更加准确。

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

读芯君开扒

课堂TIPS

•学习器之所以用k近邻作为分类器,因为从降维缓解了维数灾难,使得采样变得更加容易,k近邻算法恰恰就需要对周围的样本进行采样。但采样变得容易并不代表采样的效果会变好,所以我们也是用k近邻分类器来做试验。

•如果你不想用sklearn,毕竟用了sklearn实在是太简单了。那么根据PCA和LDA的算法,我们最终的步骤是对一个矩阵做特征值或者奇异值分解,那么你可以采用numpy的linalg.eig 或者linalg.svd函数。

•除了PCA和LDA,还有很多的线性降维技术,比如FA(Factor Analysis),ICA(Independent Component Analysis),对于不同的场景有着不同的优劣。比如,PCA处理的是高斯分布,而ICA处理的则是非高斯分布,而且ICA也不一一定就是线性的,这与它的估计方法有关。

「周末AI课堂」线性降维方法(代码篇)机器学习你会遇到的“坑”

作者:唐僧不用海飞丝

如需转载,请后台留言,遵守转载规范

相关推荐