查看原文
其他

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

唐僧不用海飞丝 读芯术 2019-12-26


AI课堂开讲,就差你了!


很多人说,看了再多的文章,可是没有人手把手地教授,还是很难真正地入门AI。为了将AI知识体系以最简单的方式呈现给你,从这个星期开始,芯君邀请AI专业人士开设“周末学习课堂”——每周就AI学习中的一个重点问题进行深度分析,课程会分为理论篇和代码篇,理论与实操,一个都不能少!


来,退出让你废寝忘食的游戏页面,取消只有胡吃海塞的周末聚会吧。未来你与同龄人的差异,也许就从每周末的这堂AI课开启了!


读芯术读者交流群,请加小编微信号:zhizhizhuji。等你。后台回复“周末AI课堂”,查阅相关源代码


全文共2202字,预计学习时长6分钟





收收心,上课时间到啦。


我们在上周的《线性降维方法(代码篇)》中对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()



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



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


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

from sklearn.decomposition import PCA

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



from sklearn.manifold import Isomap

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



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()





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




值得注意的是,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()



我们发现,无论在哪一个维度,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函数中
...
......



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

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



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


读芯君开扒


课堂TIPS


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


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


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


留言 点赞 发个朋友圈

我们一起探讨AI落地的最后一公里


作者:唐僧不用海飞丝


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


推荐文章阅读

【周末AI课堂 | 第七讲】非线性降维方法(理论篇)

【周末AI课堂 | 第六讲】线性降维方法(代码篇)

【周末AI课堂 | 第五讲】线性降维方法(理论篇)

【周末AI课堂 | 第四讲】如何进行特征选择(代码篇)

【周末AI课堂 | 第三讲】如何进行特征选择(理论篇)

【周末AI课堂 | 第二讲】过拟合问题(代码篇)

【周末AI课堂 | 第一讲】过拟合问题(理论篇)


长按识别二维码可添加关注

读芯君爱你

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存