使用Numpy实现k-Nearest-Neighbor算法
KNN 算法基本原理
kNN 算法的核心思想是用距离最近的 k 个样本数据的分类来代表目标数据的分类。 用俗话来说就是 “近朱者赤,近墨者黑”,采用距离最近的 k 个样本中占比最高的类别来代表测试数据的类别。
注意 KNN 算法仍然是有监督学习算法的一种
KNN 算法的特点
- 优点:
- 监督学习:可以看到,kNN 算法首先需要一个训练样本集,这个集合中含有分类信息,因此它属于监督学习。
- 通过计算距离来衡量样本之间相似度,算法简单,易于理解和实现。
- 对异常值不敏感
- 缺点:
- 需要设定 k 值,结果会受到 k 值的影响,不同的 k 值,最后得到的分类结果不尽相同。k 一般不超过 20。
- 计算量大,需要计算样本集中每个样本的距离,才能得到 k 个最近的数据样本。
- 训练样本集不平衡导致结果不准确问题。当样本集中主要是某个分类,该分类数量太大,导致近邻的 k 个样本总是该类,而不接近目标分类。
KNN 算法的流程
一般情况下,kNN 有如下流程:
- 收集数据:确定训练样本集合测试数据;
- 计算测试数据和训练样本集中每个样本数据的距离;
- 常用的距离计算公式:
欧式距离计算公式:
曼哈顿距离公式:
- 按照距离递增的顺序排序;
- 选取距离最近的 k 个点(这个 k 一般小于等于 20);
- 确定这 k 个点中分类信息的频率;
- 返回前 k 个点中出现频率最高的分类,作为当前测试数据的分类。
python 算法实现
开发的基本流程如下:
- 收集数据: 提供文本文件
- 准备数据: 使用 Python 解析文本文件
- 分析数据: 使用 Matplotlib 画二维散点图
- 训练算法: 此步骤不适用于 k-近邻算法
- 测试算法: 使用海伦提供的部分数据作为测试样本。
测试样本和非测试样本的区别在于:
测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
- 使用算法: 产生简单的命令行程序,然后海伦可以输入一些特征数据以判断对方是否为自己喜欢的类型。
- KNN 算法分类器函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 定义KNN算法分类器函数
# 函数参数包括: (测试数据, 训练数据, 分类, k值)
def classify(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0] # 读取矩阵有几层数据
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # 将测试数据转化为数值相同的行向量,再与训练集作差
sqDiffMat = diffMat ** 2
sqDistances = sqDiffMat.sum(axis=1) # axis=1 按行相加;axis=0 按列相加
distances = sqDistances ** 0.5 # 计算欧式距离
sortedDistIndicies = distances.argsort() # 排序并返回index,注意此处返回的是索引而不是具体值!
# 选择距离最近的k个值
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # get()相当于将其赴初值0然后加1
# 排序
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # items()返回一个元组,operator.itemgetter()按照value排序
return sortedClassCount[0][0] #返回标签
- 定义生成训练样本集的函数
1
2
3
4
def createDataSet():
group = array([[1, 1.1], [1, 1], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
- 定义主函数运行代码
1
2
3
4
5
6
7
def main():
group, labels = createDataSet()
print(classify([0, 0], group, labels, 3))
if __name__ == '__main__':
main()
完整源代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/user/bin/env python3
# -*- coding: utf-8 -*-
from numpy import *
import operator
# 定义KNN算法分类器函数
# 函数参数包括: (测试数据, 训练数据, 分类, k值)
def classify(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0] # 读取矩阵有几层数据
diffMat = tile(inX, (dataSetSize, 1)) - dataSet # 将测试数据转化为数值相同的行向量,再与训练集作差
sqDiffMat = diffMat ** 2
sqDistances = sqDiffMat.sum(axis=1) # axis=1 按行相加;axis=0 按列相加
distances = sqDistances ** 0.5 # 计算欧式距离
sortedDistIndicies = distances.argsort() # 排序并返回index,注意此处返回的是索引而不是具体值!
# 选择距离最近的k个值
classCount = {}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 # get()相当于将其赴初值0然后加1
# 排序
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True) # items()返回一个元组,operator.itemgetter()按照value排序
return sortedClassCount[0][0] #返回标签
# 定义一个生成"训练样本集"的函数,包含特征和分类信息
def createDataSet():
group = array([[1, 1.1], [1, 1], [0, 0], [0, 0.1]])
labels = ['A', 'A', 'B', 'B']
return group, labels
def main():
group, labels = createDataSet()
print(classify([0, 0], group, labels, 3))
if __name__ == '__main__':
main()
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 希亚的西红柿のBlog!
评论