查看原文
其他

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

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


AI课堂开讲,就差你了!


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


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


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

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





与以往的代码篇不同,因为这次的非参数模型理论上并不复杂,对参数的理解更为关键,所以我们会着重于将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 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 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 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 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文件,里面就保存着我们的决策树:




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


读芯君开扒


课堂TIPS


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


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


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

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


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


留言 点赞 发个朋友圈

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


作者:唐僧不用海飞丝


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


推荐文章阅读


【周末AI课堂 | 第十五讲】非参模型初步(理论篇)

【周末AI课堂 | 第十四讲】基于贝叶斯推断的回归模型(代码篇)

【周末AI课堂 | 第十三讲】基于贝叶斯推断的回归模型(理论篇)

【周末AI课堂 | 第十二讲】基于贝叶斯推断的分类模型(代码篇)

【周末AI课堂 | 第十一讲】基于贝叶斯推断的分类模型(理论篇)

【周末AI课堂 | 第十讲】核技巧(代码篇)

【周末AI课堂 | 第九讲】核技巧(理论篇)

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

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

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

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

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

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

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

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


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

读芯君爱你

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

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