邻近算法又叫作K临近算法或者KNN(K-NearestNeighbor),是机器学习中很是重要的一个算法,but它简单得一塌糊涂,其核心思想就是样本的类别由距离其最近的K个邻居投票来决定。如今假设咱们已经有一个已经标记好的数据集,也就是说咱们已经知道了数据集中每一个样本所属于的类别。这个时候咱们拥有一个未标记的数据样本,咱们的任务是预测出来这个数据样本所属于的类别。显然邻近算法是属于监督学习(Supervised Learning)的一种,它的原理是计算这个待标记的数据样本和数据集中每一个样本的距离,取其距离最近的k个样本,那么待标记的数据样本所属于的类别,就由这距离最近的k个样本投票产生。在这个过程当中,有一个动做是标记数据集,这一点在企业中通常是有专门人来负责标记数据的。python
为了更加直观的了解邻近算法,请看下面的例子。有两种水果长得很是像,一个是菠萝,另外一个是凤梨,很长一段时间我都觉得它们是同一种水果。
菠萝与凤梨的核心区别是菠萝的叶子有刺,而凤梨的叶子没有刺。菠萝的凹槽处的颜色是黄色,而凤梨的凹槽处的颜色是绿色。首先咱们把这两种水果抽取出其中的两个特色(凹槽处的颜色、叶子上是否有刺)后,放入一个直角坐标系中吧。以下图:
咱们按照两种水果的特色,已经把它们放在了直角坐标系中,按照咱们所说的算法原理,此时有一个未标记的样本,咱们来预测这个样本究竟是属于哪一种水果。以下图,这个时候来了一个未标记的样本,也就是不知道是什么类别的水果。
在原理中,咱们说过,由其最近的K个邻居来投票决定,这个未标记的水果究竟是什么水果,那么这个时候,咱们把K的值设置为3,以下图:
从图片中,咱们看到,在K的值为3的时候,与未标记样本最近的3个邻居其中2个为菠萝,而1个为凤梨,那么这个时候咱们预测这个未知的水果为菠萝。算法
咱们先来看一下如何用伪代码来实现这个算法,这样咱们在后边的学习中才能更好的写出来这段代码。数组
# 从sklearn库中的数据集对象里导入样本生成器中的make_blobs方法帮助咱们生成数据 from sklearn.datasets.samples_generator import make_blobs # 声明三个直角坐标系中的位置 centers = [[-2, 2], [2, 2], [0, 4]] # 生成数据,其中n_samples是生成数据的个数,centers是中心点,cluster_std是标准差,指明离散程度 x, y = make_blobs(n_samples=60, centers=centers, cluster_std=0.6) # x是生成的数据,y是不一样的数据对应所属的的类别0,1,2 print(x, y)
import matplotlib.pyplot as plt import numpy as np plt.figure(figsize=(16, 10), dpi=144) c = np.array(centers) # x轴,y轴,c颜色 s指定点的大小 plt.scatter(x[:, 0], x[:, 1], c=y, s=100, cmap="cool") # 画出中心点 plt.scatter(c[:, 0], c[:, 1], s=100, marker="^", c="orange") plt.show()
图形显示以下图所示:
图形中显示的三个三角形的点就是中心点,围绕在它们周围的圆点就是咱们随机生成的数据的点。app
# 从sklearn库中导入K邻居分类器:KNeighbosrClassifier from sklearn.neighbors import KNeighborsClassifier # 设定K值 k = 5 # 声明k临近分类器对象 clf = KNeighborsClassifier(n_neighbors=k) # 训练模型 clf.fit(x, y)
# 定义样本数据 x_sample = [[0, 2]] # 使用模型进预测 neighbors = clf.kneighbors(x_sample, return_distance=False) print(neighbors) # 输出值:[[23 39 21 47 29]]
x_sample变量是咱们要进行预测的样本,而后使用clf.kneighbors方法就能够对这个样本进行预测了。关于clf.kneighbors的参数return_distance,它决定了是否返回计算后的距离,默认是True,这里我把它修改为了False,你若是想要看一下值为True是什么样子,能够本身手动修改成True。到这里你能够有一点懵,这怎么就预测完成了呢?输出值表示的是什么意思呢?
输出值表示的是5个通过计算以后的位于x训练集中的索引值,它们并非直接的位置。机器学习
为了可以使预测的结果更加直观,咱们还须要用代码把他们画出来。学习
# 把带预测的样本以及和其最近的5个点标记出来 plt.figure(figsize=(8, 5), dpi=144) # dpi是像素值 plt.scatter(x[:, 0], x[:, 1], c=y, s=100, cmap='cool') # 样本数据 plt.scatter(c[:, 0], c[:, 1], s=100, marker='^', c='k') # 中心点 # 带预测的点 plt.scatter(x_sample[0][0], x_sample[0][1], marker='x', s=100, cmap='cool') # 把预测点与距离最近的5个样本连成线 for i in neighbors[0]: plt.plot([x[i][0], x_sample[0][0]], [x[i][1], x_sample[0][1]], 'k--', linewidth=0.6) plt.show()
显示结果以下图所示:测试
在这一小节咱们将经过一个花卉识别项目的练习来巩固咱们所讲的KNN算法,训练数据集是很是著名的鸢尾花数据集,涉及到的花的种类一共分为三种:
第一种花是山鸢尾,长下面这个样子
第二种花是锦葵,也叫虹膜锦葵
第三种花是变色鸢尾ui
咱们能够经过sklearn库的自带数据集直接引入鸢尾花的数据集,在这个数据集中,咱们能够经过花萼长度,花萼宽度,花瓣长度和花瓣宽度四个属性来预测未标记的鸢尾花属于哪一个类别。rest
# 1 导入鸢尾花数据集 from sklearn.datasets import load_iris # 2 声明一个鸢尾花的类对象 iris = load_iris() # 3 获取鸢尾花的数据 iris_data = iris.data # 4 获取数据对应的种类 iris_target = iris.target print(iris_data) print(iris_target)
查看数据后你会看到iris_data变量里每个元素一共有4个值,这四个值就是分别对应花萼长度、花萼宽度、花瓣长度、花瓣宽度4个属性,iris_target变量对应的就是每个花所属的类别。一共对应的是3个类别,0的意思是山鸢尾,1是虹膜锦葵,2是变色鸢尾。code
from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split # 分割训练集和测试集 from sklearn.neighbors import KNeighborsClassifier iris = load_iris() iris_data = iris.data iris_target = iris.target # 把数据分为训练集和测试集,x表示特征值,y表示目标值,test_size=0.25表示将25%的数据用做测试集 x_train, x_test, y_train, y_test = train_test_split(iris_data, iris_target, test_size=0.25) # 建立KNN算法实例,n_neighbors参数默认为5,后续能够经过网格搜索获取最优参数 knn = KNeighborsClassifier(n_neighbors=5) # 训练测试集数据 knn.fit(x_train, y_train) # 获取预测结果 y_predict = knn.predict(x_test) # 展现预测结果 labels = ['山鸢尾', '虹膜锦葵', '变色鸢尾'] for i in range(len(y_predict)): print('第%d次测试:预测值:%s 真实值:%s' %((i + 1), labels[y_predict[i]], labels[y_test[i]])) print('准确率:', knn.score(x_test, y_test))
k值选取的思路是咱们先来选择一个k值的范围,把这个范围中全部的偏差值都获取到,而后咱们再来选择偏差最小的值做为k值。
from sklearn.datasets import load_iris from sklearn.model_selection import cross_val_score from sklearn.neighbors import KNeighborsClassifier import matplotlib.pyplot as plt # 中文显示 plt.rcParams["font.family"] = 'Arial Unicode MS' # 导入数据集 iris = load_iris() x = iris.data y = iris.target # 限制k的取值范围 k_range = range(1, 31) # 记录每当k值变换一次,它的错误值是多少 k_error = [] for k in k_range: knn = KNeighborsClassifier(n_neighbors=k) # cv参数决定数据集划分比例,这里按照5:1划分训练集和测试集 scores = cross_val_score(knn, x, y, cv=6) print(scores) k_error.append(1 / scores.mean()) # 把结果画成图,直观看出k取什么值偏差最小,x轴为k值,y轴为偏差值 plt.plot(k_range, k_error) plt.xlabel('k值') plt.ylabel('偏差值') plt.show()
图形显示结果以下图所示:
根据这个图形咱们就能够看得出来,k值大概是在12这个位置时,偏差是最小的。这时当咱们把12从新放入到以前的代码中,可能你会发现他的准确率并无提高甚至还有可能降低了,实际上是由于数据量比较小的缘故,并不影响咱们解决问题的方式。
经过前面的练习,相信你已经基本掌握了KNeighborsClassifier的使用方法了,最后,在这里咱们会对这个方法的参数进行更细致的说明和讲解。
# 查看KNeighborsClassifier源代码 NeighborsClassifier( n_neighbors=5, weights="uniform”, algorithm=”auto“, leaf_size=30, p=2, metric="minkowski", metric_params=None, n_jobs=None, **kwargs, )
一样的,最后咱们会有一个小的练习,请点击下方连接下载:
chapter9-1.zip