前言
KNN是机器学习的经典算法之一。其算法的设计符合人的感官知觉,并没有太多的数学理论。感觉完完全全是凭借直觉做出来的。笔者认为这个算法可能算是机器学习里面最简单的了。本文不做理论的严谨解释,仅作简单介绍和相应的代码实现。
原理
目标:
我们的目标当燃是为了分类,当有一个新数据来之后,我们需要根据原始的训练数据,去计算出新数据属于哪一类的概率。
方案:
所以?如何计算属于哪一类?当燃是把这个用距离!就直接计算这个新的数据点到原始数据各个点的距离。然后选择距离最近的前K个。最后看看这前K个里面哪个类别的数量多,我们就权当这个新数据点属于哪一类。就这么简单。
因此,如何计算新数据点到各个数据点的距离?有三种比较常用的点之间的距离公式:
①欧氏距离:
d
=
(
x
o
l
d
1
−
x
n
e
w
1
)
2
+
(
x
o
l
d
2
−
x
n
e
w
2
)
2
+
⋯
d=\sqrt{(x_{old}^1-x_{new}^1)^2+(x_{old}^2-x_{new}^2)^2+\cdots}
d=(xold1−xnew1)2+(xold2−xnew2)2+⋯
其中
x
o
l
d
1
x_{old}^1
xold1的old代表旧的数据,1则代表旧数据的第一个维度。以此类推。
②曼哈顿距离:
d
=
∣
x
o
l
d
1
−
x
n
e
w
1
∣
+
∣
x
o
l
d
2
−
x
n
e
w
2
∣
+
⋯
d=|x_{old}^1-x_{new}^1|+|x_{old}^2-x_{new}^2|+\cdots
d=∣xold1−xnew1∣+∣xold2−xnew2∣+⋯
就是相同维度相减然后取绝对值相加就可以啦!
③余弦距离:
d
=
x
o
l
d
x
n
e
w
∣
x
o
l
d
∣
∣
x
n
e
w
∣
d=\frac{x_{old}x_{new}}{|x_{old}||x_{new}|}
d=∣xold∣∣xnew∣xoldxnew
分式上面是向量求内积,下面是向量取模
还有什么马氏距离,兰氏距离、切比雪夫距离等等牛马距离。感兴趣的读者自行查阅,此处不做过多介绍。
具体而言,使用哪一种算法,要依据所要解决的问题而定。实际情况具体分析。
代码实现
以欧氏距离为例。先看一下原始数据:
然后就是预测出来的结果:
可以看到预测结果基本上和靠近的原始数据的类别基本一致。当燃了,这也是因为两类数据距离较远的缘故。
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
import imageio
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.ion()
class KNN():
def __init__(self,x,y):
self.x=x
self.y=y
def predict(self,pre_x,k=10):
#建立一个空的用于存储结果的数组
pre_result=np.array([])
for i in pre_x:#循环每一个需要预测的数据
#每一个数据对应维度都减去pre_x
result=self.x-i
#计算平方和然后开方,也就是L2范数
distance=np.linalg.norm(result,ord=2,axis=1)
#获取前k个最小值对应的索引
min_distance_index=np.argsort(distance)[:k]
#获取对应的y的标签
y=self.y[min_distance_index]
#计算等于0的标签量
y0=np.sum(y==0)
#计算等于1的标签数量
y1=np.sum(y==1)
#将结果储存起来
if y1>y0:
pre_result =np.insert(pre_result,obj=pre_result.size,values=1)
else:
pre_result=np.insert(pre_result,obj=pre_result.size,values=0)
return pre_result
def plot_figure(x,y,pre_x,result):
'''
:param x: 原始数据x
:param y: 原始数据对应的标签类别
:param pre_x: 预测数据x
:param result: 预测结果
:return:
'''
images=[]
map_color={0:"r",1:"g"}
color_initial=[map_color[i] for i in y.squeeze()]
pre_color=[map_color[i] for i in result]
plt.scatter(x[:,0],x[:,1],c=color_initial)
plt.title("进行预测数据的分类结果")
for index,i in enumerate(pre_x):
plt.scatter(i[0], i[1], c=pre_color[index])
plt.savefig("1.png")
images.append(imageio.v3.imread("1.png"))
plt.pause(0.01)
imageio.mimsave("pic.gif",images,duration=0.1)
def main():
#生成第一类数据和对应的标签
x1=stats.norm.rvs(1,2,(100,2))
y1=np.zeros((x1.shape[0],1))
#生成第二类数据和对应的标签
x2=stats.norm.rvs(10,2,(100,2))
y2=np.ones((x2.shape[0],1))
#合并数据
x=np.concatenate([x1,x2],axis=0)
y=np.concatenate([y1,y2],axis=0)
#生成用于预测的数据
x3=stats.norm.rvs(1,2,(30,2))
x4=stats.norm.rvs(10,2,(30,2))
pre_x=np.concatenate([x3,x4],axis=0)
np.random.shuffle(pre_x)
model=KNN(x,y)
result=model.predict(pre_x,10)
plot_figure(x,y,pre_x,result)
if __name__ == '__main__':
main()
结束语
以上就是KNN的简单的原理介绍和代码实现啦。过程并不严谨,如有问题,还望读者能够指出。阿里嘎多!