一, 概述
KNN(K - 最近邻)算法是相对比较简单的机器学习算法之一, 它主要用于对事物进行分类. 用比较官方的话来说就是: 给定一个训练数据集, 对新的输入实例, 在训练数据集中找到与该实例最邻近的 K 个实例, 这 K 个实例的多数属于某个类, 就把该输入实例分类到这个类中. 为了更好地理解, 通过一个简单的例子说明.
我们有一组自拟的关于电影中镜头的数据:
那么问题来了, 如果有一部电影 X, 它的打戏为 3, 吻戏为 2. 那么这部电影应该属于哪一类?
我们把所有数据通过图表显示出来(圆点代表的是自拟的数据, 也称训练集; 三角形代表的是 X 电影的数据, 称为测试数据):
计算测试数据到训练数据之间的距离, 假设 k 为 3, 那么我们就找到距离中最小的三个点, 假如 3 个点中有 2 个属于动作片, 1 个属于爱情片, 那么把该电影 X 分类为动作片. 这种通过计算距离总结 k 个最邻近的类, 按照 "少数服从多数" 原则分类的算法就为 KNN(K - 近邻)算法.
二, 算法介绍
还是以上面的数据为例, 打戏数为 x, 吻戏数为 y, 通过欧式距离公式计算测试数据到训练数据的距离, 我上中学那会儿不知道这个叫做欧式距离公式, 一直用 "两点间的距离公式" 来称呼这个公式:
. 但是现实中的很多数据都是多维的, 即使如此, 也还是按照这个思路进行计算, 比如如果是三维的话, 就在根号里面再加上 z 轴差的平方, 即
, 以此类推.
知道了这个计算公式, 就可以计算各个距离了. 我们以到最上面的点的距离为例:, 那么从上到下的距离分别是:,,,. 现在我们把 k 定为 3, 那么距离最近的就是后面三个数了, 在这三个数中, 有两个属于动作片, 因此, 电影 X 就分类为动作片.
三, 算法实现
知道了原理, 那就可以用代码实现了, 这里就不再赘述了, 直接上带注释的 Python 代码:
- '''
- trainData - 训练集
- testData - 测试集
- labels - 分类
- '''
- def knn(trainData, testData, labels, k):
- # 计算训练样本的行数
- rowSize = trainData.shape[0]
- # 计算训练样本和测试样本的差值
- diff = np.tile(testData, (rowSize, 1)) - trainData
- # 计算差值的平方和
- sqrDiff = diff ** 2
- sqrDiffSum = sqrDiff.sum(axis=1)
- # 计算距离
- distances = sqrDiffSum ** 0.5
- # 对所得的距离从低到高进行排序
- sortDistance = distances.argsort()
- count = {}
- for i in range(k):
- vote = labels[sortDistance[i]]
- count[vote] = count.get(vote, 0) + 1
- # 对类别出现的频数从高到低进行排序
- sortCount = sorted(count.items(), key=operator.itemgetter(1), reverse=True)
- # 返回出现频数最高的类别
- return sortCount[0][0]
ps:np.tile(testData, (rowSize, 1)) 是将 testData 这个数据扩展为 rowSize 列, 这样能避免运算错误;
sorted(count.items(), key=operator.itemgetter(1), reverse=True) 排序函数, 里面的参数 key=operator.itemgetter(1), reverse=True 表示按照 count 这个字典的值 (value) 从高到低排序, 如果把 1 换成 0, 则是按字典的键 (key) 从高到低排序. 把 True 换成 False 则是从低到高排序.
四, 测试与总结
用 Python 实现了算法之后, 我们用上面的数据进行测试, 看一下结果是否和我们预测的一样为动作片:
- trainData = np.array([[5, 1], [4, 0], [1, 3], [0, 4]])
- labels = ['动作片', '动作片', '爱情片', '爱情片']
- testData = [3, 2]
- X = knn(trainData, testData, labels, 3)
- print(X)
执行这段代码后输出的结果为: 动作片 . 和预测的一样. 当然通过这个算法分类的正确率不可能为 100%, 可以通过增加修改数据测试, 如果有大量多维的数据就更好了.
来源: https://www.cnblogs.com/lyuzt/p/10471617.html