KNN前导知识
KNN(K-最近邻分类器,K-Nearest Neighbor)是一种较为简单的经典分类算法。
算法主要思路
对于输入的每一张测试图像,与分类器中储存的每一张训练图像分别计算一次距离,这个距离可以是L1 distance(曼哈顿距离)或者是L2 distance(欧式距离)等。
假设分类器中储存了 j 张训练图像,则对于每一张测试图像,总共会产生 j 个距离(对应每一张训练图像)。将这 j 个距离从小到大排序,并取最小的前 K 个距离,认为这 K 张训练图像与输入的测试图像最相似。然后对这 K 张图像的所属类别进行计数(可能有两张是狗,三张是猫),取出现次数最多的类别作为这张测试图像的类别(即出现三次的猫)。
L1 distance(曼哈顿距离)
L 1 − d i s t a n c e = ∣ x 1 − x 1 ∣ + ∣ y 1 − y 1 ∣ L1-distance=\left | x_{1} - x_{1} \right | +\left | y_{1} - y_{1} \right | L1−distance=∣x1−x1∣+∣y1−y1∣
L2 distance(欧氏距离)
L 2 − d i s t a n c e = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 L2-distance=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2} L2−distance=(x1−x2)2+(y1−y2)2
K值的选定
K值过小容易导致模型过拟合,而K值过大可能导致模型的近似误差增大。因此可以通过尝试多组K值来选定最适合当前问题的K值。
代码实现
compute_distances_no_loops()
该函数最关键的一步是对于欧式距离计算的拆分与简化,拆分步骤如下所示:
d
i
s
t
a
n
c
e
(
t
e
s
t
[
i
]
,
t
r
a
i
n
[
j
]
)
=
∑
k
(
t
e
s
t
[
i
]
[
k
]
−
t
r
a
i
n
[
j
]
[
k
]
)
2
distance(test[i],train[j]) = \sqrt{\sum_{k}^{} (test[i][k]-train[j][k])^{2} }
distance(test[i],train[j])=k∑(test[i][k]−train[j][k])2
=
∑
k
t
e
s
t
[
i
]
[
k
]
2
+
∑
k
t
r
a
i
n
[
j
]
[
k
]
2
−
2
×
t
e
s
t
[
i
]
[
k
]
×
t
r
a
i
n
[
j
]
[
k
]
=\sqrt{\sum_{k}^{}test[i][k]^{2}+\sum_{k}^{}train[j][k]^{2}-2\times test[i][k]\times train[j][k]}
=k∑test[i][k]2+k∑train[j][k]2−2×test[i][k]×train[j][k]
其中,test[i]表示测试集中的第i张图像,test[i][k]表示测试集中第i张图像的第k个像素点(在之前已经将所有像素点伸展为一行)。
我们再将test和train看为一个整体,则可以进一步简化公式为:
d
i
s
t
a
n
c
e
(
t
e
s
t
,
t
r
a
i
n
)
=
(
∑
k
t
e
s
t
[
:
,
k
]
)
2
+
(
∑
k
t
r
a
i
n
[
:
,
k
]
)
2
−
2
×
t
e
s
t
×
t
r
a
i
n
distance(test,train)=\sqrt{(\sum_{k}^{}test[:,k])^{2}+(\sum_{k}^{}train[:,k])^{2}-2\times test\times train}
distance(test,train)=(k∑test[:,k])2+(k∑train[:,k])2−2×test×train
可能你会迷惑两个不同大小的矩阵怎么实现相加,这就是Python的强大之处,后部分的代码会详细讲解,因此实现代码如下所示:
test_square = np.expand_dims(np.square(X).sum(axis = 1), axis = 1)
train_square = np.expand_dims(np.square(self.X_train).sum(axis = 1), axis = 0)
dists = np.sqrt(test + train - 2 * test.dot(train.T))
np.sum()的操作会把test和train分别变为长度为500和长度为5000的列表,而接下去的np.expand_dims()操作又分别将他们变为500×1和1×5000的列向量和行向量。在Python中,将这两个向量相加的操作是将列向量扩充到500×5000,将行向量也扩充到500×5000,再进行相加。此时就实现了所有distance的同时计算(可以自己动手画个向量扩充相加一下试试)