分享

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

 昵称11935121 2018-08-13

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

与以往的代码篇不同,因为这次的非参数模型理论上并不复杂,对参数的理解更为关键,所以我们会着重于将K近邻的几个重要的超参数做出详细的解释,并与我们的图像一一对应起来。首先,我们会对用K近邻分类器对IRIS数据进行分类,采取简单投票法和距离的加权平均投票法观察分类的效果,同时,我们不同的距离度量和不同的K近邻进一步的观察它们对决策边界的影响。最后我们利用决策树来对整个iris数据进行处理,并充分利用决策树良好的可解释性,来画出整个树。

我们的数据仍然是喜闻乐见的IRIS数据:

import matplotlib.pyplot as plt

import seaborn as sns

from sklearn import datasets

iris=datasets.load_iris()

X = iris.data[:, :2]

y = iris.target

sns.set(style='darkgrid')

for c,i,names inzip('rgb',[0,1,2],iris.target_names):

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

plt.title('IRIS')

plt.legend()

plt.show()

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

我们构建K近邻分类器,选取neighbors为7,最好选择奇数,因为我们不希望出现票数相同的情况,而这两种投票方法,对应着我们的少数服从多数原则,和相似度高的权重大原则,来构建相应的决策边界:

......

from sklearn import neighbors, datasets

def make_meshgrid(x, y, h=.02):

x_min, x_max = x.min() -1, x.max() +1

y_min, y_max = y.min() -1, y.max() +1

xx, yy =np.meshgrid(np.arange(x_min, x_max, h),

np.arange(y_min,y_max, h))

return(xx, yy)

xx,yy=make_meshgrid(X[:,0],X[:,1])

for weights in ['uniform', 'distance']:

clf = neighbors.KNeighborsClassifier(7, weights=weights)

clf.fit(X, y)

Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

Z = Z.reshape(xx.shape)

plt.figure()

plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu,alpha=0.8)

for c,i,names inzip('rgb',[0,1,2],iris.target_names):

plt.scatter(X[y==i,0],X[y==i,1],c=c,label=names,edgecolor='k')

plt.title('3-Class classification (k = %i, weights = '%s')'% (7, weights))

plt.legend()

plt.show()

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

差别并不明显,但可以注意到下面的红点,在根据距离加权的投票中,它被归为了setosa,而在简单的少数服从多数的投票中,它被归为了versicolor,大概看来不同的平均方式会对我们分类器产生影响。接下来,我们查看随着K的变化,决策边界会怎样变化:

......

for k in [1,27]:

clf = neighbors.KNeighborsClassifier(k, weights='distance')

clf.fit(X, y)

Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

Z = Z.reshape(xx.shape)

plt.figure()

plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu,alpha=0.8)

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

plt.scatter(X[y==i,0],X[y==i,1],c=c,label=names,edgecolor='k')

plt.title('3-Class classification (k = %i, weights = '%s')'% (k,'distance'))

plt.legend()

plt.show()

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

从图中可以看出,随着K的增大,决策边界会变得越来越光滑,边界的光滑程度会反映出一定的泛化能力,因为样本C的判别都要利用更大的样本集合D,样本集合D内的每个样本反过来也会利用样本C的信息,这样就相当于对大量的样本做了平均化,决策边界自然也就会变得更加光滑。接下来我们来验证不同的距离度量对决策边界的影响,我们在上文中所使用的距离是闵科夫斯基距离(Minkowski distance):

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

当p=2时,变为大家喜闻乐见的欧几里得距离(Euclidean distance),而p=1时,就变为曼哈顿距离(Manhattan distance).我们可以证明,当p趋于无穷的时候,我们就得到了切比雪夫距离(Chebyshev distance):

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

如果大家不擅长证明该问题,那么可以非常简单的画出随着p增大,在欧几里得空间下的“单位圆”,会发现最后圆的形状最后会变成一个正方形,正对应着切比雪夫距离的定义。

我们分别选取曼哈顿距离、切比雪夫距离,在K=7的时候观察相应的决策边界:

......

for dist in ['manhattan','chebyshev']:

clf = neighbors.KNeighborsClassifier(7, weights='distance',metric=dist)

clf.fit(X, y)

Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])

Z = Z.reshape(xx.shape)

plt.figure()

plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu,alpha=0.8)

for c,i,names inzip('rgb',[0,1,2],iris.target_names):

plt.scatter(X[y==i,0],X[y==i,1],c=c,label=names,edgecolor='k')

plt.title('3-Class classification (k = %i, distance = '%s')'% (7,dist))

plt.legend()

plt.show()

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

我们可以非常明显的看出,在曼哈顿距离下的K近邻算法的决策边界会变得非常直,几乎在沿着坐标轴移动,这就是曼哈顿距离的定义。而切比雪夫距离几乎与欧几里得距离一致,说明在计算k近邻的点时,往往由x或y的某一项占据主导地位,这里面隐含着我们的样本特征值可能是离散的,事实上,IRIS数据特征的取值就是离散化的。

如果我们用决策树算法来适应iris数据,仍然可以选取其中两个特征所张成的特征空间中的决策边界:

import numpy as np

import matplotlib.pyplot as plt

from sklearn import datasets

from sklearn.tree import DecisionTreeClassifieras DTC

iris = datasets.load_iris()

X = iris.data[:, :2]

y = iris.target

def make_meshgrid(x, y, h=.02):

x_min, x_max = x.min() -1, x.max() +1

y_min, y_max = y.min() -1, y.max() +1

xx, yy =np.meshgrid(np.arange(x_min, x_max, h),

np.arange(y_min,y_max, h))

return(xx, yy)

xx,yy=make_meshgrid(X[:,0],X[:,1])

clf =DTC(criterion='entropy')

clf.fit(X, y)

Z =clf.predict(np.c_[xx.ravel(), yy.ravel()])

Z = Z.reshape(xx.shape)

plt.figure()

plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu,alpha=0.6)

for c,i,names inzip('rgb',[0,1,2],iris.target_names):

plt.scatter(X[y==i,0],X[y==i,1],c=c,label=names,edgecolor='k')

plt.title('DecisionTree')

plt.legend()

plt.show()

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

可以看出,决策树在特征空间所形成的决策边界均为平直,因为其决策边界是由每个特征的取值交叠而成,就像我们在二维直角坐标系对于x和y进行取值。同时,我们在这幅图中可以看到过拟合的迹象,因为决策边界可以很好的把每一个样本包括在内,如果我们确定这样的过拟合,可以做简单的交叉验证(请读者自行编码)。

但更重要的是,我们要获得树状图,来直观的看到整个推断流程:

import graphviz

from sklearn import datasets

from sklearn.tree import DecisionTreeClassifieras DTC

from sklearn import tree

iris = datasets.load_iris()

X = iris.data

y = iris.target

clf=DTC(criterion='entropy')

clf.fit(X,y)

dot_data=tree.export_graphviz(clf,out_file=None,

feature_names=iris.feature_names,

class_names=iris.target_names,

filled=True, rounded=True,

special_characters=True)

graph=graphviz.Source(dot_data)

graph.render('IRIS')

我们会在当前目录下得到一个名为‘IRIS’的pdf文件,里面就保存着我们的决策树:

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

即便我们可以确定决策树存在着过拟合,可我们要对决策树具体要做怎样的修改才能降低这种过拟合呢,敬请期待下一篇专栏。

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

读芯君开扒

课堂TIPS

· 在利用K近邻处理数据时,我们可以把K,distance作为超参数处理,观察模型在测试集上的表现,来获得能够适应数据的最佳选择,因为这一工作在前面文章的大量使用,此文就不做相关展示。

· 有一个非常重要的问题,即K近邻算法中明明出现了参数K,它为什么还是一个非参数算法呢?原因仍然在于,所谓的K并不是模型学得的,也不是需要优化的,而是我们事先指定好的,这就是超参数和参数的区别。

· 我们会在很多地方看到懒惰学习的叫法,而K近邻一般都会作为其代表,但事实上,决策树也可以是懒惰的,具体请看这篇论文:

https://pdfs./38b0/877fa6ac3ebfbb29d74f761fea394ee190f3.pdf

· 要获得决策树的推断图,需要安装python库 graphviz,直接用pip install graphviz即可安装。

「周末AI课堂」非参模型初步(代码篇)机器学习你会遇到的“坑”

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多