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

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

收收心,上课时间到啦。

我们在上周的《线性降维方法(代码篇)》中对IRIS数据和WINE数据利用了PCA和LDA这两种线性降维方法,似乎取得了一定的效果,一方面体现在低维空间不同类的样本分的足够开,另一方面体现在经过降维后,分类器的表现更好了。

而非线性降维的一个重要前提就是,数据的分布本身就不是高维的,而是一个嵌在高维空间的低维流形,而这样的低维我们可能只需要将其展开,而不需要将其变换。比如,地球表面近似为一个球面,球面上的我们对球面的感受不会是三维的,而是二维的,但却不得不用三维的语言去描述它而已。如果我们想研究它的内在结构,可能只需要将其展开为二维。我们将其展开的过程,就是降维。

我们在IRIS和WINE的数据里很难发现这样的结构,一方面因为实际数据中完美的流形并不存在,另一方面因为,我们最多只能在三维空间可视化,而特征数一旦巨大,我们通过特征的组合去观察每一个三维空间的数据结构,将是不可能的任务。

但我们可以通过非线性降维的方法,来逆推整个结构,如果我们的非线性降维取得了比线性降维的更好的效果,那么很可能本身的数据就是一个低维流形。

我们可以构造一个简单的样例数据,来可视化一个二维流形:

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

from sklearn import datasets

X, c = datasets.samples_generator.make_s_curve(1000, random_state=2018)

ax = Axes3D(plt.figure())

ax.scatter(X[:,0],X[:,1],X[:,2],c=c,cmap=plt.cm.hsv)

plt.title('Sample')

plt.show()

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

从这个角度看,平平无奇,但我们换个角度来看它:

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

对于这样一个S形,其实就是嵌在三维空间的二维流形,我们如果要从三维降到二维,非线性降维只是将其展开,会尽可能保持流形的内在结构,而数据分布本身近似为流形,内在结构就非常重要。

以PCA和ISOMAP为例,我们分别对样例数据做降维:

from sklearn.decomposition import PCA

X_PCA=PCA(2).fit(X).transform(X)

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

from sklearn.manifold import Isomap

X_ISO=Isomap(10,2).fit(X).transform(X)

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

PCA的降维结果是一个S形,其实近似于一个嵌在二维空间的一维流形。很多初学者或者不理解降维的意义的同学,反而会以为PCA处理之后,样例数据保持了S形,就是一个好的处理。

其实呢,这样的看法是错误的。因为对于这样一个三维空间的二维流形,因为流形本身就是二维的,我们只需要将其“展开”和“铺平”,这样才最大程度上保留了信息,PCA这种线性的降维方式只是选取了一个投影空间,大量的样本在低维空间没有得到表达。

举个不太恰当的例子,如果我们把国家作为我们的数据点,那么这些数据点就分布地球表面,也就是一个嵌在三维空间的二维流形上。如果我们为球面寻找一个低维空间,PCA会把球面映射到一个圆(损失大量信息),而ISOMAP会映射成一张世界地图。(事实上,要想达到这一效果,对地球表面的数据分布做更多的假设,但道理相同)

我们可以换另外一组数据来取得相似的效果:

n_points = 1000

X, color = datasets.samples_generator.make_swiss_roll(n_points,

random_state=2018)

X_PCA=PCA(2).fit(X).transform(X)

X_ISO=Isomap(10,2).fit(X).transform(X)

ax = Axes3D(plt.figure())

ax.scatter(X[:,0],X[:,1],X[:,2],\

c=color,cmap=plt.cm.hsv)

ax.set_title('Sample')

bx=plt.figure()

plt.scatter(X_PCA[:,0],X_PCA[:,1],c=color,cmap=plt.cm.hsv)

plt.title('PCA of Swiss Roll')

cx=plt.figure()

plt.scatter(X_ISO[:,0],X_ISO[:,1],c=color,cmap=plt.cm.hsv)

plt.title('ISOMAP of Swiss Roll')

plt.show()

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

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

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

我们尝试用更多的方法如MDS和LLE(locally linear embedding,局部线性嵌入),对swiss roll数据进行降维:

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

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

值得注意的是,MDS(多维缩放)本质上还是一个线性算法,虽然它的初衷是在低维空间保持高维空间的距离,但仍然把欧几里得距离作为度量,所以从图中来看,MDS的效果几乎与PCA的一致。而LLE是利用了流形的局部等价于欧氏空间,每一个点都可以被周围的点进行线性表示(这也是线性空间的性质),降到低维空间后,要保持拟合系数的不变。

接下来,我们把非线性降维方法用到实际的数据中,我们在WINE数据上,对线性降维和非线性降维方法进行对比:以低维空间的维度作为超参数,仍然选取k-近邻作为分类器,通过观察测试集上表现来对降维效果有定性的认识。

import numpy as np

from sklearn import datasets

from sklearn.model_selection import cross_validate

from sklearn.manifold import Isomap,MDS

from sklearn.manifold import locally_linear_embedding as LLE

from sklearn.decomposition import PCA

from sklearn.preprocessing import StandardScaler

from sklearn.neighbors import KNeighborsClassifier as KNC

import seaborn as sns

import matplotlib.pyplot as plt

data=datasets.load_wine()

X=StandardScaler().fit(data['data']).transform(data['data'])

y=data['target']

def dim_reductor(n,X):

reductor=dict(PCA=PCA(n).fit(X).transform(X),\

ISOMAP=Isomap(10,n).fit(X).transform(X),\

MDS=MDS(n).fit_transform(X),\

LLE=LLE(X,10,n)[0])

return(reductor)

mse_mat=np.zeros((4,X.shape[1]))

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

reductor=dim_reductor(n,X)

test_mse=[]

for name, method in reductor.items():

X_new=reductor[name]

clf=KNC()

clf_dict=cross_validate(clf,X_new,y,\

cv=5,scoring='accuracy')

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

mse_mat[:,n-1]=test_mse

sns.set(style='darkgrid')

for idex,name in enumerate(reductor.keys()):

plt.plot(range(1,X.shape[1]+1),mse_mat[idex],label=name)

plt.xlabel('dimensions')

plt.ylabel('accuracy')

plt.legend()

plt.show()

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

我们发现,无论在哪一个维度,LLE的表现均是最差的,而且LLE并不会随着维度波动,而是一直在上升。而其他三种降维方法,MDS在维度为3的时候表现最好,PCA在维度为5的时候表现最好,ISOMAP在维度为6的时候表现最好。这能否说明,WINE数据并没有明显的流形结构,或者ISOMAP的结果告诉我们,WINE数据其实可能是一个嵌在13维空间的6维流形,这些我们无从得知。从工程上来说,我们可能需要将各类流形学习用进去,直到降低合适维度可以得到我们需要的性能。

这些算法看起来并没有太大的差异,我们也可以看到MDS,ISOMAP,PCA三种方法交缠在一起,难分高下,那么我们大胆地来试一种虽然不属于流形学习,但却属于非线性降维——加了kernel的PCA:

from sklearn.decomposition import KernelPCA

def dim_reductor(n,X):

...

KPCA=KernelPCA(n,'rbf').fit_transform(X)#添加到前文的dim_reductor函数中

...

......

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

我们惊奇地发现,Kernel PCA的曲线几乎一直在其他曲线的上方!这说明,在几乎所有的维度上,Kernel PCA的表现要好于其他的降维算法(针对WINE数据),维度等于2时,我们还可以比较各类降维的算法的表现:

sns.barplot(mse_mat[:,1],list(reductor.keys()))

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

那么为什么PCA加了Kernel,性能就要比原始的PCA算法更好呢?以及,Kernel到底是什么?为什么会加了Kernel就使得PCA从一个线性算法变成了非线性?下周我们再见吧,《机器学习的核技巧(kernel trick)》会为大家来解答。

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

读芯君开扒

课堂TIPS

•当数据处在一个高维空间的低维流形时,我们就可以方便的使用内禀坐标,即流形中的坐标就可以很好的描述数据,流形学习的出发点就在于此。

•流形学习除了ISOMAP和LLE,常见的流形学习方法还有 Hessian Eigenmapping,t-SNE, Laplacian Eigenmaps ,Local tangent space alignment。但流形学习需要克服最大的问题在于,流形的局部空间等价于欧氏空间,而在局部往往就要进行密采样的操作,而这一条件往往得不到满足。

•特征选择和降维本身虽然并不相同,但也并不矛盾,我们在实际工程中,可以先做特征选择,再做降维,对于不同的数据,可能会有不同的效果。但可以预见的是,当存在多余特征的时候,高维空间的点会变得更加稀疏,密采样会遇到更大的困难,先做特征选择去除掉多余特征是非常有必要的。

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


分享到:


相關文章: