通俗易懂适合初学者的机器学习实战(1):k- Nearest Neighbor (k个最近的邻居)KNN算法

k- Nearest Neighbor (k个最接近的邻居)算法

首发于:知乎@Ai酱初学者机器学习专栏https://zhuanlan.zhihu.com/p/66360783

任何机器学习都是假定一种数学模型可以用于当前这个数据解决问题 。而任何数学模型都有参数,其中不同数据参数的取值是不一样的。那么我们学习任何机器学习第一件事。那就是要确定它使用的是数学模型是什么。第二件事就是看这个数学模型有哪些参数需要根据数据来确定。

kNN算法到底是什么?它未知参数k到底是什么?

kNN很简单。那就是“人以类聚,物以群分”。假设,现在有一个人你不知道她什么性格。然后,为了分类出她是什么性格。你首先找她身边和她最相似的k个朋友。如果她的最相似的k个朋友,大部分都很文艺范。那么,你可以把目标对象分类为文艺青年。这就是kNN的原理
从名字就看得出来。遍历训练集带标签的已知数据。计算所有带标签数据和新数据之间的相似度。找到前k个相似度最大的数据,看他们的分类标签出现的次数。假如这k个数据出现的分类标签次数最多的是A类,那么算法就认为新数据它是属于A类

由于我们要找k个最相似的已知带标签的样本。那么我们怎么知道已知标签的样本和未知标签的样本之间是否相似呢?

问题来了,如何用数学量化两个样本之间的相似度?

有很多数学指标可以量化两个样本之间的相似度。最简单的,两个点他们距离越接近不就越相似嘛(两点间距离公式 ( x 1 + x 2 ) 2 + ( y 1 + y 2 ) 2 \sqrt{(x_1 + x_2)^2 + (y_1 + y_2)^2} (x1+x2)2+(y1+y2)2 )。
然后还有,两个向量他们之间夹角越小不就这两个向量方向越接近么(求两个向量之间夹角的cos函数。 c o s ( θ ) = a ⃗ ⋅ b ⃗ ∣ a ⃗ ∣ ∣ b ⃗ ∣ cos(\theta)=\frac {\vec a \cdot \vec b}{|\vec a||\vec b|} cos(θ)=a b a b )?

现在我们知道怎么量化相似度。剩下就是遇到一个新数据我想对它进行分类,那就遍历训练集带标签的已知数据。计算所有带标签数据和新数据之间的相似度。找到前k个相似度最大的数据,看他们的分类标签出现的次数。假如这k个数据出现的分类标签次数最多的是A类,那么算法就认为新数据它是属于A类。

编程实践:

from numpy import *
# 弄带标签的数据
data = array([[1.0, 1.1],[1.0, 1.0],[0,0],[0, 0.1]])
labels = ['A','A','B','B']# data各元素的类别标签

newdata = array([1.0, 0.9])
'''
:newdata 来了一个新样本数据,
现在问题是要knn根据已有的数据data和标签lables判断它属于哪个类.
'''
# 设定knn的参数。
# 只根据k个最相似的样本,统计他们的标签哪个分类出现次数最多就认为新数据属于这个类。
k = 3 

# 1. 计算已知的所有样本与新数据的相似度
    # 相似度:用两点间的距离来量化样本间的相似度.(距离越大越不相似))
    # sum()中参数axis=1,表示按行把每行所有列累加起来
distance = sqrt(sum((data-newdata)**2, axis=1))
print('各样本与新数据之间的距离为:',distance)
各样本与新数据之间的距离为: [0.2        0.1        1.3453624  1.28062485]
# 2. 找到相似度较大的前k个已知样本的下标序号

# 2.1 先把距离从小到到排序(),
#     并取出对应样本的序号(方便取他们的标签)
sorted_index = distance.argsort()
print('距离低到高对应已知样本data中的下标为:',sorted_index)

# 2.2 找对应下标的标签,并统计各标签出现次数
label_frequence = {}
for i in range(k):# 只统计前k个最相似的样本它们标签出现的次数
    tmp_index = sorted_index[i]
    tmp_label = labels[tmp_index]
    # 当前这个标签出现次数+1。
    # .get(tmp_label,0)后面那个0指的是假设当前字典{}没有这个索引就返回0
    label_frequence[tmp_label] = label_frequence.get(tmp_label,0) + 1

print('距离前k=%d小的样本对应标签出现频率:'% k,label_frequence)
距离低到高对应已知样本data中的下标为: [1 0 3 2]
距离前k=3小的样本对应标签出现频率: {'A': 2, 'B': 1}
# 3. 算法把出现频率最高的那个标签认为是新数据的所属分类
label_frequence_list = label_frequence.items() #把字典变为list
print('label_frequence变成列表后为:',label_frequence_list)
# 从高到低排序,按照label_frequence_list元素中的第2个值排序
label_frequence_sorted =sorted(label_frequence_list , key=lambda x:x[1], reverse=True)
print('新数据所属标签为',label_frequence_sorted[0][0])

label_frequence变成列表后为: dict_items([('A', 2), ('B', 1)])
新数据所属标签为 A
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值