与以往的代码篇不同,因为这次的非参数模型理论上并不复杂,对参数的理解更为关键,所以我们会着重于将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() 我们构建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() 差别并不明显,但可以注意到下面的红点,在根据距离加权的投票中,它被归为了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 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() 我们可以非常明显的看出,在曼哈顿距离下的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() 可以看出,决策树在特征空间所形成的决策边界均为平直,因为其决策边界是由每个特征的取值交叠而成,就像我们在二维直角坐标系对于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./38b0/877fa6ac3ebfbb29d74f761fea394ee190f3.pdf · 要获得决策树的推断图,需要安装python库 graphviz,直接用pip install graphviz即可安装。 |
|
来自: 昵称11935121 > 《待分类》