算法描述
给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的k个实例,这k个实例的多数属于某个类,就把该输入实例分为这个类。
三个基本要素
1.距离度量
两个实例之间的距离可以用
L
p
L_p
Lp范数来定义,其中p可以选择。
L
P
L_P
LP范数的定义为:
这里面的
x
i
x_i
xi和
x
j
x_j
xj代表两个实例,这两个实例都有n个分量。
比较常用的是p=2,此时称为欧氏距离,即:
例如
x
i
=
(
1
,
2
,
3
)
x_i=(1,2,3)
xi=(1,2,3),
x
j
=
(
4
,
5
,
6
)
x_j=(4,5,6)
xj=(4,5,6),则这两个实例之间的欧氏距离为:
d
i
s
t
a
n
c
e
=
(
∣
1
−
4
∣
2
+
∣
2
−
5
∣
2
+
∣
3
−
6
∣
2
)
1
/
2
distance=(|1-4|^2+|2-5|^2+|3-6|^2)^{1/2}
distance=(∣1−4∣2+∣2−5∣2+∣3−6∣2)1/2
2.k值选择
k选的小的话近似误差会减小,但估计误差会增大。
k选的大的话近似误差会增大,估计误差会减小。
比如k选1的话,对一个点进行分类的时候就只找到与它距离最近的1个点就行,所找到的点的类别就是这个点的类别。但在实际情况下会有噪声点,这时k=1就很容易分错了。如下图所示,○是一类,×是另一类,此时放入一个△,直观上觉得它属于○这一类的概率大一些,但是由于噪声的存在,如果k=1的话因为离△最近的是一个×,这时就会把△分到×类,如果k=3的话就会把△分到○类。
另一个例子如下:
在这个例子中如果k=1或k=2的话是可以正确地把△分在○类里面的,如果k取一个特别大的值的话△就会被错误地分到×中去。
3.分类决策规则
一般都是用多数表决,即离输入实例最近的k个实例属于哪个类别的实例数量最多那么输入实例就属于哪个类别。
代码
import numpy as np
import operator
class Knn:
def __init__(self, point, samples, labels, k):
self.point = point
self.samples = samples
self.labels = labels
self.k = k
def distance(self, lp):
"""计算要进行分类的点与样本之间的距离(lp范数)"""
samples_len = len(self.samples)
subtract = np.tile(self.point, (samples_len, 1)) - self.samples
absolute_value = abs(subtract)
p_power = absolute_value ** lp
sum_value = p_power.sum(axis=1)
p_norm = sum_value ** (1/lp)
return p_norm
def classification(self, distances):
small_to_large_index = distances.argsort() # argsort函数返回的是数组值从小到大的索引值
class_count = {}
for i in range(self.k):
near_label = self.labels[small_to_large_index[i]]
# 统计前k个中标签的数目
# 也就是说最后这个字典中存的是A类的有多少个,B类的有多少个
# 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值
class_count[near_label] = class_count.get(near_label, 0) + 1
# reverse=True代表逆序排列
# key=operator.itemgetter(1)定义函数key为获取对象的序号为1的值,也就是比较value,如果括号里为0就是比较key
# sorted是个排序函数
# class_count.items()为字典里面的内容
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
return sorted_class_count[0][0]
samples_out = [[1, 2], [3, 4], [5, 6], [7, 8]]
labels_out = ['A', 'A', 'B', 'B']
knn = Knn([0, 0], samples_out, labels_out, 3)
distance_out = knn.distance(2)
classification_result = knn.classification(distance_out)
print(classification_result)
结果为:
A