一、k-近邻算法介绍
1、概念
K-Nearest Neighbor算法又叫KNN算法,属于监督学习算法的一种,是机器学习里的一个经典算法。简单地说,k-近邻算法是采用测量不同特征值之间的距离方法进行分类。
2、工作原理
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据吼,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
简单地说就是,预测样本与特征空间中的k个样本最相似(距离最近),预测样本属于这k个样本中的最多类别。
例:电影分类问题
电影名称 | 类别 | 与未知电影的距离 |
---|---|---|
《交作业》 | 恐怖片 | 1.22 |
《2022》 | 剧情片 | 6.78 |
《机器学习》 | 恐怖片 | 11.26 |
《李白》 | 剧情片 | 42.6 |
《福建》 | 剧情片 | 82.65 |
《一棵树》 | 剧情片 | 73.99 |
《镜子》 | 恐怖片 | 23.87 |
《水龙头》 | 剧情片 | 112.39 |
《未知电影》 | ? |
取k为3,可得三个距离未知电影最近的电影依次是:《交作业》、《2022》、《机器学习》。三部电影中,有一部电影属于剧情片,有两部电影属于恐怖片,样本类别最多的为恐怖片,因此判断未知电影属于恐怖片。
3、优缺点
- 优点:精度高、对异常值不敏感、无数据输入假定。
- 缺点:计算复杂度高、空间复杂度高
- 适用数据范围:数值型和标称型
4、一般流程
- 收集数据:可以使用任何方法。
- 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
- 分析数据:可以使用任何方法。
- 训练算法:k-近邻算法不需要。
- 测试算法:计算错误率。
- 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
5、实现流程
- 选好k值
- 分别计算特征空间中的点与待测点之间的距离,使用欧式距离公式:
- 按距离递增次序排序
- 选取与当前点距离最小的k个点
- 统计k个点所在类别出现的频率
- 频率最高的类别即为待测点的预测分类
6、k值大小的影响
- k值过大:预测标签比较稳定,但可能过于平滑(例如:样本集中一共有100个样本,k值选择100,那么不管是哪个预测标签结果都是一样的)
- k值过小:预测标签容易受到样本影响
7、要求
1.近邻点要有相同相近的类别。
2.特征维度的尺度(范围)要具备一致性。
二、代码实现`
1、先导入模块和数据
from numpy import *
import operator
def createDataSet():
group = array([[3,104],[2,100],[1,81],[101,10],[99,5],[98,2],[18,90]])
labels = ['爱情片','爱情片','爱情片','动作片','动作片','动作片','未知']
return group,labels
2、为每组数据分类,生成一个分类器
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize, 1))- dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis = 1)
distances = sqDistances**0.5 #开方,计算距离
sortedDistIndicices = distances.argsort() #返回distances中的元素从小到大排序后的索引
classCount = {} #定义一个记录类别次数的字典
for i in range(k):
voteIlabel = labels[sortedDistIndicices[i]] #前k个类别
classCount[voteIlabel] = classCount.get(voteIlabel,0 ) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0] #返回次数最多的类别
3、 测试结果
if __name__=="__main__":
#训练集
group,labels = createDataSet()
print(group)
print(labels)
#测试集
test = [100,20]
test_class = classify0(test, group, labels, 3)
print(test_class)
4、结果
[[ 3 104]
[ 2 100]
[ 1 81]
[101 10]
[ 99 5]
[ 98 2]
[ 18 90]]
['爱情片', '爱情片', '爱情片', '动作片', '动作片', '动作片', '未知']
动作片