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

AI课堂开讲,就差你了!

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

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

读芯术读者交流群,请加小编微信号:zhizhizhuji。等你。

后台回复“周末AI课堂”,查阅相关源代码。

文共1837字,预计学习时长4分钟

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

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

import matplotlib.pyplot as pltimport 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 in zip("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()

我们构建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 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')"% (7, weights))

plt.legend()

plt.show()

差别并不明显,但可以注意到下面的红点,在根据距离加权的投票中,它被归为了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()

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

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

如果大家不擅长证明该问题,那么可以非常简单的画出随着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 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, distance = '%s')"% (7,dist))

plt.legend()

plt.show()

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

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

import numpy as npimport 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 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("DecisionTree")

plt.legend()

plt.show()

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

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

import graphvizfrom 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文件,里面就保存着我们的决策树:

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

读芯君开扒课堂TIPS

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

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

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

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

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

留言 点赞 发个朋友圈我们一起探讨AI落地的最后一公里

作者:唐僧不用海飞丝如需转载,请后台留言,遵守转载规范

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180812A198ZA00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券