K最近邻算法python实现

K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。

更多:K最近邻算法

3.1 K最近邻算法的原理

K最近邻算法的原理,正如我们本章标题所说——近朱者赤, 近墨者黑。想象一下我们的数据集里面有一半是“朱”(图中浅色的点),另一半是“墨”(图中深色的点)。现在有了一个新的数据点,颜色未知,我们怎么判断它属于哪一个分 类呢?如图3-1所示。

对于K最近邻算法来说,这个问题就很简单:新数据点离谁最近,就和谁属于同一类,从图3-1中我们可以看出,新数据点距离它8点钟方向的浅色数据点最近,那么理所应当地,这个新数据点应该属于浅色分类了,如图3-2所示。

看起来,K最近邻算法真是够简单的,这么轻松就完成了分类的工作。别急,我们还没说完。刚才只是举的最简单的例子,选的最近邻数等于1。但如果我们在模型训练过程中让最近邻数等于1的话,那么非常可能会犯了“一叶障目,不见泰山”的错误,试想一下,万一和新数据点最近的数据恰好是一个测定错误的点呢?

所以需要我们增加最近邻的数量,例如把最近邻数增加到3,然后让新数据点的分类和3个当中最多的数据点所处的分类保持一致,如图3-3所示。

从图3-3中我们看到,当我们令新数据点的最近邻数等于3的时候,也就是找出离新数据点最近的3个点,这时我们发现与新数据点距离最近的3个点中,有2个是深色, 而只有1个是浅色。这样一来,K最近邻算法就会把新数据点放进深色的分类当中。

以上就是K最近邻算法在分类任务中的基本原理,实际上K这个字母的含义就是最近邻的个数。在scikit-learn中,K最近邻算法的K值是通过n_neighbors 参数来调节的,默认值是5。

【注意】K最近算法也可以用于回归,原理和其用于分类是相同的。当我们使用K最近邻回归计算某个数据点的预测值时,模型会选择离该数据点最近的若干个训练数据集中的点,并且将它们的y值取平均值,并把该平均值作为新数据点的预测值。

3.2 K最近邻算法的用法

在这一小节中,我们会向大家展示K最近邻算法在分类和回归任务当中的应用,请大家准备好Jupyter notebook,和我们一起进行实验吧。

3.2.1 K 最近邻算法在分类任务中的应用

在scikit-learn中,内置了若千个玩具数据集(Toy Datasets) ,还有一-些API让我们可以自已动手生成一些数据集。接下来我们会使用生成数据集的方式来进行展示,请大家在Jupyter notebook中输入代码如下:

#ai8py.com
# 导入数据集生成器
from sklearn.datasets import make_blobs
# 导入KNN分类器
from sklearn.neighbors import KNeighborsClassifier
# 导入画图工具
import matplotlib.pyplot as plt
# 导入数据集拆分工具
from sklearn.model_selection import train_test_split
# 生成样本数为200,分类为2的数据集
data=make_blobs(n_samples=200,centers=2,random_state=8)
X,y=data
# 将生成的数据集进行可视化
plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.spring,edgecolor='k')
plt.show()

在这段代码中,我们使用了scikit-learn 的make_ blobs 函数来生成-一个样本数量为200,分类数量为2的数据集,并将其赋值给X和y,然后我们用matplotlib将数据用图形表示出来,运行代码,会得到如图3-4所示的结果。

图 3-4 使用make_blobs 生成的数据集

【结果分析】从图3-4中可以看出,make_blobs生成的数据集一共有两类,其中一类用深色表示,而另外一类用浅色表示。读者朋友可能有点疑惑:这不是已经进行好分类了吗?我们还需要K最近邻算法做什么呢?

这确实是初学者非常容易提出的问题,答案是这样的一我们这 里生成的数据集,可以看作机器学习的训练数据集,是已知的数据。我们就是基于这些数据用算法进行模型的训练,然后再对新的未知数据进行分类或者回归。

下面我们就使用K最近邻算法来拟合这些数据,输入代码如下:

import numpy as np
clf=KNeighborsClassifier()
clf.fit(X,y)

# 下面的代码用于画图
x_min,x_max=X[:,0].min()-1,X[:,0].max()+1
y_min,y_max=X[:,1].min()-1,X[:,1].max()+1
xx,yy=np.meshgrid(np.arange(x_min,x_max,.02),np.arange(y_min,y_max,.02))

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

plt.pcolormesh(xx,yy,Z,cmap=plt.cm.Pastel1)
plt.scatter(X[:,0],X[:,1],c=y,cmap=plt.cm.spring,edgecolors='k')
plt.xlim(xx.min(),xx.max())
plt.ylim(yy.min(),yy.max())
plt.title("Classifier:KNN")

plt.show()

运行代码,会得到如图3-5所示的结果。

图 3-5 使用K最近邻算法创建的分类模型

【结果分析】从图3-5中我们可以看到,K最近邻算法基于数据集创建了一个分类模型,就是图中粉色区域和灰色区域组成的部分。那么如果有新的数据输入的话,模型就会自动将新数据分到对应的分类中。

例如,我们假设有一个数据点,它的两个特征值分别是6.75和4.82,我们来试验下模型能不能将它放到正确的分类中,首先我们可以在上面那段代码中,plt.show() 之前加一行代码如下:

# 新的数据点用五星表示出来
plt.scatter(6.75,4.82,marker="*",c="red",s=200)

再次运行代码,会得到结果如图3-6所示。

图 3-6 新的数据点所在的位置

【结果分析】图3-6中五角星就代表了新的数据点所在的位置,可以看到K最近邻算法将它放在了下方的区域,和浅色的数据点归为了一类。

下面我们再验证一下,输入代码如下:

# 对新数据点分类进行判断
print('\n\n\n') #这一行代码主要是为了让截图好看一些
print("代码运行结果:")
print("====================")
print("新数据点的分类是:",clf.predict([[6.75,4.82]]))
print("====================")
print('\n\n\n') #这一行代码主要是为了让截图好看一些

运行代码,我们将得到结果如图3-7所示

图3-7 分类器对新数据点的分类判断

【结果分析】看起来,K最近邻算法的工作成果还是很不错的,不过这可能是因为我们这次的任务有点太简单了。下面我们给它增加一- 点难度一处理多元分类任务。

发表评论

邮箱地址不会被公开。 必填项已用*标注