K近邻(K-Nearest Neighbor, KNN)是一种最经典和最简单的有监督学习方法之一。K-近邻算法是最简单的分类器,没有显式的学习过程或训练过程,是懒惰学习(Lazy Learning)。当对数据的分布只有很少或者没有任何先验知识时,K 近邻算法是一个不错的选择。
一般而言,从k = 1 开始,随着的逐渐增大,K近邻算法的分类效果会逐渐提升;在增大到某个值后,随着的进一步增大,K近邻算法的分类效果会逐渐下降。
特征空间中两个实例点之间的距离是二者相似程度的反应
欧氏距离:
曼哈顿距离:
当对测试样本进行分类时,首先通过扫描训练样本集,找到与该测试样本最相似的个训练样本,根据这个样本的类别进行投票确定测试样本的类别。也可以通过个样本与测试样本的相似程度进行加权投票。如果需要以测试样本对应每类的概率的形式输出,可以通过个样本中不同类别的样本数量分布来进行估计。
要确定绿圆属于哪个类别,如果k=3,在其最近的3个样本中红色三角形数量最多,绿圆属于红色三角形类别,如果k=5,在其最近的5个样本中蓝色矩形数量最多,绿圆属于蓝色矩形类别。
为了课堂上GPS签到方便,对学校的一些坐标进行了收集,对于在教学楼区的坐标定义了attendance标签,其他坐标定义了absence标签。(红色为attendance,绿色为absence)
import numpy as np
import matplotlib.pyplot as plt
import math
#训练集
x_train = [[20, 25], [8, 32], [7, 52], [28,43], [8,65], [21,46], [38,35], [35,25], [45,31], [50,40], [53,55], [60,58], [52,15]]
y_train = ['attendance', 'attendance', 'attendance', 'attendance', 'attendance','attendance' ,'absence' ,'absence' ,'absence' ,'absence' ,'absence' ,'absence', 'absence']
# 测试集
x_test = [[35,17], [10,80], [29,49], [35,40]]
#y_test = ['absence','attendance','attendance','absence']
#便于绘图标签
raw_data_y=[1,1,1,1,1,1,0,0,0,0,0,0,0]
X = np.array(x_train)
Y = np.array(raw_data_y)
#利用matplotlib绘制图像
plt.scatter(X[Y==0,0],X[Y==0,1],color='g')
plt.scatter(X[Y==1,0],X[Y==1,1],color='r')
plt.show()
class KNN:
def __init__(self, x_train, x_test, k):
# 保留测试点与所以训练样本的距离
self.distance = np.zeros((len(x_test), len(x_train)))
# 保留预测结果
self.predicted = []
# KNN中k的取值(不懂看上面基本知识点)
self.k = k
# 欧氏距离
def knn_distance(self, x1, x2):
dis = math.sqrt(math.pow((x1[0]-x2[0]),2) + math.pow((x1[1]-x2[1]),2))
return dis
# 计算待测点与样本点的距离
def knn(self, x_test, x_train, y_train):
print(y_train)
for i in range(len(x_test)):
for j in range(len(x_train)):
self.distance[i][j] = self.knn_distance(x_test[i], x_train[j])
self.predicted.append(self.knn_predicted(self.distance[i], y_train))
return self.predicted
def knn_predicted(self, distances, y_train):
#利用numpy的argsort方法获取前K小样本的索引
k_predicted_index = distances.argsort()[:self.k]
#通过索引获得索引对应的y_train序列
topK_y = [y_train[i] for i in k_predicted_index]
from collections import Counter
votes = Counter(topK_y)
predict_y = votes.most_common(1)[0][0]
print(predict_y)
# 设置KNN中的k
k = 3
knn = KNN(x_train, x_test, k)
# 获得测试集的预测结果
pred = knn.knn(x_test, x_train, y_train)
由以上结果可以得到从k = 1 开始,随着的逐渐增大,K近邻算法的分类效果会逐渐提升;在增大到某个值后,随着的进一步增大,K近邻算法的分类效果会逐渐下降。
若k值过小,如果这些数据恰巧是噪声数据,预测就会出错;也就是说,K值选得较小,就会使模型的复杂度增大,发生过拟合。(极端K=1)
若K值较大,这时与训练数据较远(不相似)的训练数据也会对预测产生影响(过拟合),可能时预测产生错误。(极端的K = N)
一般的,K值取一个较小的值,通常采用交叉验证法来求取最优的K值。