KNN的原理就是当预测一个新的值x的时候,根据它距离最近的K个点是什么类别来判断x属于哪个类别。
knn三要素
训练集少且种类少的时候算法有效,训练集大的时候要使用KD树和球树的方法建立模型。
距离度量
距离衡量的方法有多种,目的都是搜索最近邻,最常用的是欧氏距离。
k值的选择
k值决定了最后确定类别时所参考的样本数量,k值过大则训练误差增大,选取的临近点中包含错误种类的可能性增大,导致结果不准确;k值过小则泛化误差增大,模型容易受到噪声干扰,容易过度拟合。因此k值的选取非常重要,一般先选取一个很小的值,再使用交叉检验确定最优的k值,一般都低于训练样本的平方根。
分类决策规则
1.多数表决法
多数表决法类似于投票的过程,也就是在 K 个邻居中选择类别最多的种类作为测试样本的类别。
2.加权表决法
根据距离的远近,对近邻的投票进行加权,距离越近则权重越大,通过权重计算结果最大值的类为测试样本的类别。
看的资料里面都是关于下面这道题如果K=3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
如果K=5,绿色圆点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。
然后就是关于距离运算公式,如
然后就是步骤:
就是找个随便分为几部分给定k值,根据求出的距离选定距离最近的k个样本`"""
“”"
import numpy as np
from matplotlib import pyplot as plt
#计算距离公式
def d_man(x, y):
d = np.sum(np.abs(x - y))#曼哈顿距离公式
return d
def d_euc(x, y):
d = np.sqrt(np.sum(np.square(x - y)))#欧式距离公式
return d
#sorted函数按照key值进行排序,key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较
#reverse参数接受False 或者True 表示是否逆序;class_count.items()返回可遍历的(键, 值) 元组数组。
import operator
def majority_voting(class_count):
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)#itemgetter(a)获得第_a_个值,默认从小到大
return sorted_class_count
#生成示例数据
def create_data():
features = np.array(
[[2.88, 3.05], [3.1, 2.45], [3.05, 2.8], [2.9, 2.7], [2.75, 3.4],
[3.23, 2.9], [3.2, 3.75], [3.5, 2.9], [3.65, 3.6], [3.35, 3.3]]) #np.array构建二维数组且无需指针
labels = [‘A’, ‘A’, ‘A’, ‘A’, ‘A’, ‘B’, ‘B’, ‘B’, ‘B’, ‘B’]
return features, labels #返回features,labels
def knn_classify(test_data, train_data, labels, k):
distances = np.array([]) # 创建一个空的数组存放距离
for each_data in train_data: # 使用欧式距离计算数据相似度
d = d_euc(test_data, each_data)
distances = np.append(distances, d) #append() 用于在列表末尾添加新的对象。
print(f"距离相似度distances={distances}")
sorted_distance_index = distances.argsort() # 获取按距离大小排序后的索引(argsort提取索引)
sorted_distance = np.sort(distances)
print(f"查看sorted_distance_index{sorted_distance_index}")
print(f"查看sorted_distance{sorted_distance}")
r = (sorted_distance[k]+sorted_distance[k-1])/2 # 计算圆的半径
#选择距离最近的k个值
class_count = {}
for i in range(k):
vote_label = labels[sorted_distance_index[i]] #根据索引找到距离对应的类别
class_count[vote_label] = class_count.get(vote_label, 0) + 1
#排序
final_label = majority_voting(class_count)
return final_label, r #返回值
#生成训练样本
features, labels =create_data()
test_data = np.array([3.18, 3.15])
final_label, r = knn_classify(test_data, features, labels, 5)
print(final_label)
print®
#可视化
#极坐标方式表示圆
def circle(r, a, b): # 为了画出圆,这里采用极坐标的方式对圆进行表示 :x=rcosθ,y=rsinθ。
theta = np.arange(0, 2*np.pi, 0.01)
x = a+r * np.cos(theta)
y = b+r * np.sin(theta)
return x, y
k_circle_x, k_circle_y = circle(r, 3.18, 3.15)
plt.figure(figsize=(5, 5))
plt.xlim((2.4, 3.8)) #x轴范围
plt.ylim((2.4, 3.8)) #y轴范围
x_feature = list(map(lambda x: x[0], features)) # 返回每个数据的x特征值
y_feature = list(map(lambda y: y[1], features))
plt.scatter(x_feature[:5], y_feature[:5], c=“b”) # 在画布上绘画出"A"类标签的数据点
plt.scatter(x_feature[5:], y_feature[5:], c=“g”)
plt.scatter([3.18], [3.15], c=“r”, marker=“x”) # 待测试点的坐标为 [3.18,3.15]
plt.plot(k_circle_x, k_circle_y)
`