KNN算法

k-近邻算法(kNN), 它的⼯作原理是:存在⼀个样本数据集合, 也称作训练样本集, 并且样本集中每个数据都存
在标签, 即我们知道样本集中每⼀数据与所属分类的对应关系。 输⼊没有标签的新数据后, 将新数据的每个特征与样本集中数据对应的特征进⾏⽐较, 然后算法提取样本集中特征最相似数据(最近邻) 的分类标签。 ⼀般
来说, 我们只选择样本数据集中前k个最相似的数据, 这就是k-近邻算法中k的出处, 通常k是不⼤于20的整数。 最后, 选择k个最相似数据中出现次数最多的分类, 作为新数据的分类

?机器学习实战中的例子

使⽤k近邻算法分类爱情⽚和动作⽚。有⼈曾经统计过很多电影的打⽃镜头和接吻镜头, 图2-1显⽰了6部电影的
打⽃和接吻镜头数。 假如有⼀部未看过的电影, 如何确定它是爱情⽚还是动作⽚呢? 我们可以使⽤kNN来解决这个问题。

⾸先我们需要知道这个未知电影存在多少个打⽃镜头和接吻镜头

KNN算法中的fit函数 knn算法中的k_python


KNN算法中的fit函数 knn算法中的k_机器学习_02


即使不知道未知电影属于哪种类型, 我们也可以通过某种⽅法计算出来。⾸先计算未知电影与样本集中其他电影的距离

KNN算法中的fit函数 knn算法中的k_数据_03

现在我们得到了样本集中所有电影与未知电影的距离, 按照距离递增排序, 可以找到k个距离最近的电影。 假定k=3, 则三个最靠近的电影依次是He’s Not Really into Dudes、 Beautiful Woman和California Man。 k近邻算法按照距离最近的三部电影的类型, 决定未知电影的类型, ⽽这三部电影全是爱情⽚, 因此我们判定未知电影是爱情⽚。

KNN算法中的fit函数 knn算法中的k_python_04

完整的代码(加详细注释)

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))