KNN算法
k-近邻算法(kNN), 它的⼯作原理是:存在⼀个样本数据集合, 也称作训练样本集, 并且样本集中每个数据都存
在标签, 即我们知道样本集中每⼀数据与所属分类的对应关系。 输⼊没有标签的新数据后, 将新数据的每个特征与样本集中数据对应的特征进⾏⽐较, 然后算法提取样本集中特征最相似数据(最近邻) 的分类标签。 ⼀般
来说, 我们只选择样本数据集中前k个最相似的数据, 这就是k-近邻算法中k的出处, 通常k是不⼤于20的整数。 最后, 选择k个最相似数据中出现次数最多的分类, 作为新数据的分类
?机器学习实战中的例子
使⽤k近邻算法分类爱情⽚和动作⽚。有⼈曾经统计过很多电影的打⽃镜头和接吻镜头, 图2-1显⽰了6部电影的
打⽃和接吻镜头数。 假如有⼀部未看过的电影, 如何确定它是爱情⽚还是动作⽚呢? 我们可以使⽤kNN来解决这个问题。
⾸先我们需要知道这个未知电影存在多少个打⽃镜头和接吻镜头
即使不知道未知电影属于哪种类型, 我们也可以通过某种⽅法计算出来。⾸先计算未知电影与样本集中其他电影的距离
现在我们得到了样本集中所有电影与未知电影的距离, 按照距离递增排序, 可以找到k个距离最近的电影。 假定k=3, 则三个最靠近的电影依次是He’s Not Really into Dudes、 Beautiful Woman和California Man。 k近邻算法按照距离最近的三部电影的类型, 决定未知电影的类型, ⽽这三部电影全是爱情⽚, 因此我们判定未知电影是爱情⽚。
完整的代码(加详细注释)
from numpy import *
import operator
def createDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group, labels
def classify0(inX, dataSet, labels, k):
dataSetSize = dataSet.shape[0]
#dataSet是一个4*2的矩阵,dataSet.shape[0]即dataSet第一维的长度=4,dataSet.shape[1]=2
# >>> dataSetSize
# 4
#❶(以下三⾏) 距离计算
diffMat = tile(inX, (dataSetSize,1)) - dataSet
# tile[[0,0],(4,1)] 将[0,0]拓展成4行,1列
# >>> tile(inX, (dataSetSize,1))
# array([[0, 0],
# [0, 0],
# [0, 0],
# [0, 0]])
# >>> diffMat
# array([[-1. , -1.1],
# [-1. , -1. ],
# [ 0. , 0. ],
# [ 0. , -0.1]])
sqDiffMat = diffMat**2
# diffMat**2, 平方运算
# >>> sqDiffMat
# array([[ 1. , 1.21],
# [ 1. , 1. ],
# [ 0. , 0. ],
# [ 0. , 0.01]])
sqDistances = sqDiffMat.sum(axis=1)
# 我们平时用的sum应该是默认的axis=0 就是普通的相加(列相加)
# 而当加入axis=1以后就是将一个矩阵的每一行向量相加
# >>> sqDistances
# array([ 2.21, 2. , 0. , 0.01])
distances = sqDistances**0.5
# >>> distances
# array([ 1.48660687, 1.41421356, 0. , 0.1 ])
sortedDistIndicies = distances.argsort()
# argsort函数返回的是数组值从小到大的索引值
# >>> sortedDistIndicies
# array([2, 3, 1, 0], dtype=int64)
classCount={}
#❷ (以下两⾏) 选择距离最⼩的k个点
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
# >>> voteIlabel = labels[sortedDistIndicies[0]]
# >>> voteIlabel
# 'B'
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
#?统计距离最近的K个节点中,A和B的数量
sortedClassCount = sorted(classCount.items(),
# ?Python 字典 items() 方法以列表形式(并非直接的列表,若要返回列表值还需调用list函数)返回可遍历的(键, 值) 元组数组。
#❸ 排序
key=operator.itemgetter(1), reverse=True)
# operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子。
# a = [1,2,3]
# >>> b=operator.itemgetter(1) //定义函数b,获取对象的第1个域的值
# >>> b(a)
# 2
return sortedClassCount[0][0]
group,labels = createDataSet()
print(classify0([0,0], group, labels, 3))