lizhengxing 2021-09-07 09:25
k-NN 是一种监督学习算法,全称 K-Nearest Neighbor,中文称之为 K近邻算法。
k-NN 是一种分类算法。(例如:我们可以用k-NN来预测某人是否有患糖尿病的风险。)
注:k-NN 不是只能用于分类,它也可以用来回归,这一点我将放到后面讲。
下面我将通过一个小例子,带大家直观了解一下 k-NN 算法是如何工作的:
如图所示,我们想预测蓝色圆点属于哪个类别(即:是红方块?还是绿三角?)
注意:在这个例子中,其实有个前提,即图中的红方块和绿三角不是毫无规律胡乱分布的,它们的分布是有一定内在联系的,只不过我们不知道是一种怎样的联系,所以我们能期望通过 k-NN 这种机器学习算法帮我们找到这种内在的联系。
分析:
首先,预测蓝色圆点所属的类别(是红方块还是绿三角),是典型的分类问题,所以可以选用 k-NN 算法来帮助我们完成这个任务。
然后,k-NN 是一个监督学习算法,我们需要收集训练数据供 k-NN 算法学习,期望它能自动学习到数据中存在的某种内在的联系(或知识)。在这个任务中,我们的训练数据就是图中那些已知的、分布在不同位置上的红方块和绿三角。
最后,当我们拿到一个蓝色圆点,我们知道它所处位置,但不知道它所属的类别。k-NN 要做的是,利用它从训练数据中学习到的某种内在联系(或知识)来推断这个蓝色圆点所属的类别。
k:
k-NN 的 k,就是k个最近的邻居的意思。k-NN 的思想很朴素,当 k-NN 要对一个未知元素类别进行推断时,它会找从训练数据中找出距离这个未知元素最近的 k 个邻居,而这个未知元素所属的类别,将由这 k 个邻居投票决定(少数服从多数)。
如果 k=1(如下图),此时找到蓝圆点的 1 个最近的邻居是绿三角,所以 k-NN 的推断结果是绿三角。
如果 k=3(如下图),此时蓝圆点最近的3个邻居是2个绿三角和1个红方块,所以 k-NN 的推断结果还是绿三角。
如果 k=5(如下图),此时蓝圆点最近的5个邻居是2个绿三角和3个红方块,所以 k-NN 的推断结果是红方块。
如果 k=7(如下图),此时蓝圆点最近的7个邻居是4个绿三角和3个红方块,所以 k-NN 的推断结果又是绿三角。
以上就是 k-NN 算法的工作原理,有没有很简单😄 。
注:可能大家注意到了,k 的选择可能会影响到推断结果,那么我们该如何选择 k 值?这个问题我也把它放到后面来讲。
前面我们用一个“虚拟”的例子,初步了解了 k-NN 机器学习算法的工作原理。
下面我再通过一个“真实”案例(Pima Indians Diabetes Database),从应用角度认识一下 k-NN 算法。
数据集介绍:
Pima Indians Diabetes Database 数据集来自 University of California,研究对象是亚利桑那凤凰城附近的皮马印第安人。该数据集共有 768 条数据,每条数据包含 8 个医学预测变量和 1 个结果变量:
数据集中,糖尿病患者(Outcome=1)有268例;未患糖尿病(Outcome=0)的人数为50。
目标
我们的目标是为这个数据集构建一个机器学习模型,这个模型可以用来预测患者是否患有糖尿病。
工具
我们将在 Kaggle 平台中的 Python 环境下,使用 sklearn 机器学习库,完成模型的构建。
实战
可以看到,这个模型在测试数据集上的准确率是 72.7%。
可以看出,预测是准确的。
完整代码
k-NN 算法的核心是找出与待推断样本距离最近的 k 个邻居。
那么距离如何度量?
其实有很多距离度量方法,常用的有以下几种:
本文简要介绍以下几种。
欧式距离也称欧几里得距离,是最常见的距离度量,衡量的是多维空间中两个点之间的绝对距离 。
曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离。对于一个具有正南正北、正东正西方向规则布局的城镇街道,从一点到达另一点的距离正是在南北方向上旅行的距离加上在东西方向上旅行的距离,因此,曼哈顿距离又称为出租车距离。
闵可夫斯基距离 (Minkowski Distance),也被称为 闵氏距离。闵可夫斯基距离是欧几里得和曼哈顿距离度量的广义形式。
从前面“k-NN思想”中可以看出,k 的选择会影响算法的预测结果。那么我们该如何选择合适的 k 值?
我们用 “k-NN实战”中的例子来观察一下,不同 k 值对 k-NN 算法准确度的影响。
下面的程序将统计出 k 值从 1 到训练数据量变化时,k-NN 算法的准确度变化。
import pandas as pd
data = pd.read_csv('/kaggle/input/pima-indians-diabetes-database/diabetes.csv')
X = data.iloc[:, 0:8]
Y = data.iloc[:, -1]
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3)
import numpy as np
neighbors = np.arange(1,len(Y_train))
train_accuracy =np.empty(len(neighbors))
test_accuracy = np.empty(len(neighbors))
print(pd.DataFrame(Y_train).groupby('Outcome').value_counts())
from sklearn.neighbors import KNeighborsClassifier
for i,k in enumerate(neighbors):
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train, Y_train)
train_accuracy[i] = knn.score(X_train, Y_train)
test_accuracy[i] = knn.score(X_test, Y_test)
import matplotlib.pyplot as plt
plt.title('k-NN Varying number of neighbors')
plt.plot(neighbors, test_accuracy, label='Testing Accuracy')
plt.plot(neighbors, train_accuracy, label='Training accuracy')
plt.legend()
plt.xlabel('Number of neighbors')
plt.ylabel('Accuracy')
plt.show()
从图中可以看出:
一般规则:
实际操作:
import pandas as pd
data = pd.read_csv('/kaggle/input/pima-indians-diabetes-database/diabetes.csv')
X = data.iloc[:, 0:8]
Y = data.iloc[:, -1]
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV
parameters = {'n_neighbors': [1,3,5,7,9,11,13,15]}
knn = KNeighborsClassifier()
clf = GridSearchCV(knn, parameters, cv=5)
clf.fit(X,Y)
print("最终最佳准确率: %.2f" % clf.best_score_)
print("最终的最佳K值: ", clf.best_params_)
k-NN 算法已在各种应用中得到运用,主要是在分类中,例如:
优势:
缺点: