目录
目录
三、参考书籍
一、理论知识
1、什么是KNN?
K—最近邻近算法(K- Nearest Neighbor, KNN):假设在一平面(图1)内,存在两种已知的样本数据(训练数据)类型,我们把蓝色的方块定义为A类样本数据,把橙色的菱形定义为B类样本数据。然而,在图1中,我们可以发现还存在一个红色的圆形(待预测的数据),我们怎么样才能知道它到底是属于A类(蓝色方块)还是B类(橙色菱形)呢?
KNN算法可以很好的解决这个问题,其核心思想就是可以通过选择周围的k个“邻居”,在k个最邻近的样本数据中选择所占比例最高的类别赋予预测数据。
具体来说,假设k=3(虚线圆圈),A类数据所占比例为1/3,B类数据所占比例为2/3,所以红色的圆形被赋予为B类;假设k=8(实线圆圈),A类数据所占比例为5/8,B类数据所占比例为3/8,所以红色的圆形被赋予为A类。
|
图1 KNN算法 |
2、KNN算法的计算逻辑
从上面的例子,我们可以简单的总结KNN算法的计算逻辑:
- 计算训练数据与测试数据中每一个样本的距离(因为开始时,我们不知道哪些训练数据会成为最近的邻居,只有在计算出所有可能的距离之后,才能确定哪些是最近的k个邻居);
- 选取距离测试数据最近的k个训练数据样本,作为“邻居”;
- 选择所占比例最高的类别赋予测试数据。
因此,可以发现有两个因素可以直接决定KNN算法的准确性:
- k值(“邻居”数量)的选择
- 训练数据和测试数据中样本之间的距离
3、距离度量(重点)
在这里,对于k值(“邻居”数量)的选择先不展开赘述,主要探讨如何计算训练数据和测试数据中样本之间的距离。
3.1 曼哈顿距离(Manhattan Distance)
对于一个二维平面,假设有两个点和
。这两点之间的曼哈顿距离为:
曼哈顿距离也可以用在多维空间中,假设有两个点和
:
这种距离度量的核心思想是,它测量在各个坐标轴方向上的绝对差之和。
3.2 欧式距离(Euclidean Metric)
还是假设二维平面内有两个点和
,那么这两点之间的欧式距离为:
欧式距离也可以用在多维空间中,假设有两个点和
:
欧式距离测量的是点到点之间“直线”最短距离。
二、分类器构建(代码实现)
1、显示训练数据
在一个二维坐标轴上显示训练数据集,其中用红色星号(*)表示A类数据,对应的标签为A;用绿色加号(+)表示B类数据,对应的标签为B(图2)。
代码如下:
show_dataset.py
import numpy as np
import matplotlib.pyplot as plt
# 训练数据及其对应的标签
group = np.array([[1.0, 2.0], [1.2, 0.1], [0.1, 1.4], [0.3, 3.5], [1.1, 1.0], [0.5, 1.5]])
labels = np.array(['A', 'A', 'B', 'B', 'A', 'B'])
#A类数据用红色星号表示;B类数据用绿色加号表示
plt.scatter(group[labels == 'A', 0], group[labels == 'A', 1], color='r', marker='*')
plt.scatter(group[labels == 'B', 0], group[labels == 'B', 1], color='g', marker='+')
plt.show()
|
图2 训练数据显示 |
2、创建KNN分类器
定义createDataSet函数用于创建测试数据及对应的标签(A/B),再定义kNN_classify函数选择使用曼哈顿距离或者欧式距离作为距离度量。
代码如下:
classify.py
import numpy as np
import operator
def createDataSet():
# 创建测试数据及对应的标签
group = np.array([[1.0, 2.0], [1.2, 0.1], [0.1, 1.4], [0.3, 3.5], [1.1, 1.0], [0.5, 1.5]])
labels = np.array(['A', 'A', 'B', 'B', 'A', 'B'])
return group, labels
def kNN_classify(k,dis,X_train,x_train,Y_test):
assert dis == 'E' or dis == 'M' #确保函数的调用者必须选择这两种距离度量中的一种,否则函数将无法正确执行
# E代表欧氏距离,M代表曼哈顿距离
num_test = Y_test.shape[0] # 测试样本的数量
labellist = []
if dis == 'E':
for i in range (num_test):
distances = np.sqrt(np.sum(((X_train - np.tile(Y_test[i], (X_train.shape[0],1))) ** 2), axis=1))
nearest_k = np.argsort(distances)
topK = nearest_k[:k]
classCount = {}
for i in topK:
classCount[x_train[i]] = classCount.get(x_train[i], 0) + 1
sortedClasssCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
labellist.append(sortedClasssCount[0][0])
return np.array(labellist)
elif dis == 'M':
for i in range(num_test):
distances = np.sum(np.abs(X_train - np.tile(Y_test[i], (X_train.shape[0], 1))), axis=1)
nearest_k = np.argsort(distances)
topK = nearest_k[:k]
classCount = {}
for i in topK:
classCount[x_train[i]] = classCount.get(x_train[i], 0) + 1
sortedClasssCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
labellist.append(sortedClasssCount[0][0])
return np.array(labellist)
3、测试数据
在建立了KNN分类器之后,可以输入任意的测试数据,测试该被赋予A类还是B类,这下列代码中,选取k=6,距离度量用曼哈顿距离(M)。测试数据用蓝色表示,若被赋予A类,则显示为蓝色星号(*);若被赋予B类,则显示为蓝色加号(+)。
test_KNN.py
import numpy as np
import matplotlib.pyplot as plt
from classify import createDataSet,kNN_classify
if __name__ == '__main__':
group,labels = createDataSet()
#加载测试数据,可修改
test_points = np.array([[0.75,1.75],[0.4,2.0]])
y_test_pred = kNN_classify(6,'M',group,labels,test_points)
plt.scatter(group[labels == 'A', 0], group[labels == 'A', 1], color='r', marker='*')
plt.scatter(group[labels == 'B', 0], group[labels == 'B', 1], color='g', marker='+')
for i, test_point in enumerate(test_points):
if y_test_pred[i] == 'A':
plt.scatter(test_point[0], test_point[1], color='b', marker='*')
else:
plt.scatter(test_point[0], test_point[1], color='b', marker='+')
plt.show()
print(y_test_pred)
![]() |
图3 测试数据显示 |
三、参考资料
[1]魏溪含, 涂铭, & 张修鹏. (2020). 深度学习与图像识别: 原理与实践. 北京: 机械工业出版社。