《机器学习》k-近邻算法

(看了Jack-Cui这个大哥的文章,想做个总结)***其中的例子/代码也是这个大哥的。
(本人是个菜鸡,有错请指教,不喜勿喷,谢谢合作)这是我的学习笔记,以此记录学习内容,算是一种垃圾的自我修养吧,废话不说,开始。
我们提出了k近邻算法,算法的核心思想是,即是给定一个训练数据集TrainSet,对新的输入实例TestSet,在训练数据集TrainSet中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该输入实例分类到这个类中.
例子:爱情片和动作片
算法步骤:
(1).计算已知数据集与TestSet的距离
(2).按照这些距离从小到大排序
(3).根据上个步骤(2)取前K个点
(4).确定前K个点的类别所占的比例
(5).最后将TextSet归纳为占最大比例的那一类
这个例子摘抄于Jack-Cui作者:(电影名字稍作改动)

电影名称 打斗镜头 接吻镜头 电影类型
前任N 1 101 爱情片
波多野XX 5 89 爱情片
倚天屠狗记 108 5 动作片
浪客剑心 115 8 动作片
表1.1就是我们已有的数据集合,也就是训练样本集。这个数据集有两个特征,即打斗镜头数和接吻镜头数。除此之外,我们也知道每个电影的所属类型,即分类标签。用肉眼粗略地观察,接吻镜头多的,是爱情片。打斗镜头多的,是动作片。以我们多年的看片经验,这个分类还算合理。如果现在给我一部电影,你告诉我这个电影打斗镜头数和接吻镜头数。不告诉我这个电影类型,我可以根据你给我的信息进行判断,这个电影是属于爱情片还是动作片。而k-近邻算法也可以像我们人一样做到这一点,不同的地方在于,我们的经验更"牛逼",而k-邻近算法是靠已有的数据。比如,你告诉我这个电影打斗镜头数为2,接吻镜头数为102,我的经验会告诉你这个是爱情片,k-近邻算法也会告诉你这个是爱情片。你又告诉我另一个电影打斗镜头数为49,接吻镜头数为51,我"邪恶"的经验可能会告诉你,这有可能是个"爱情动作片",画面太美,我不敢想象。 (如果说,你不知道"爱情动作片"是什么?请评论留言与我联系,我需要你这样像我一样纯洁的朋友。) 但是k-近邻算法不会告诉你这些,因为在它的眼里,电影类型只有爱情片和动作片,它会提取样本集中特征最相似数据(最邻近)的分类标签,得到的结果可能是爱情片,也可能是动作片,但绝不会是"爱情动作片"。当然,这些取决于数据集的大小以及最近邻的判断标准等因素。
# -*- coding: UTF-8 -*-
import numpy as np

"""
函数说明:创建数据集

"""
def createDataSet():
    #四组二维特征
    group = np.array([[1,101],[5,89],[108,5],[115,8]])
    #四组特征的标签
    labels = ['爱情片','爱情片','动作片','动作片']
    return group, labels
if __name__ == '__main__':
    #创建数据集
    group, labels = createDataSet()
    #打印数据集
    print(group)
    print(labels)

根据两点距离公式,计算距离,选择距离最小的前k个点,并返回分类结果。

# -*- coding: UTF-8 -*-
import numpy as np
import operator

"""
函数说明:kNN算法,分类器

Parameters:
    inX - 用于分类的数据(测试集)
    dataSet - 用于训练的数据(训练集)
    labes - 分类标签
    k - kNN算法参数,选择距离最小的k个点
Returns:
    sortedClassCount[0][0] - 分类结果
#作者:Jack-Cui 

"""
def classify0(inX, dataSet, labels, k):
    #numpy函数shape[0]返回dataSet的行数
    dataSetSize = dataSet.shape[0]
    #在列向量方向上重复inX共1次(横向),行向量方向上重复inX共dataSetSize次(纵向)
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    #二维特征相减后平方
    sqDiffMat = diffMat**2
    #sum()所有元素相加,sum(0)列相加,sum(1)行相加
    sqDistances = sqDiffMat.sum(axis=1)
    #开方,计算出距离
    distances = sqDistances**0.5
    #返回distances中元素从小到大排序后的索引值
    sortedDistIndices = distances.argsort()
    #定一个记录类别次数的字典
    classCount = {}
    for i in range(k):
        #取出前k个元素的类别
        voteIlabel = labels[sortedDistIndices[i]]
        #dict.get(key,default=None),字典的get()方法,返回指定键的值,如果值不在字典中返回默认值。
        #计算类别次数
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    #python3中用items()替换python2中的iteritems()
    #key=operator.itemgetter(1)根据字典的值进行排序
    #key=operator.itemgetter(0)根据字典的键进行排序
    #reverse降序排序字典
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    #返回次数最多的类别,即所要分类的类别
    return sortedClassCount[0][0]

这个例子是二维的,如果遇到高维怎么办,请参照欧氏距离(也称欧几里德度量)
也会有人问分类器是否准确,答案是否定的,分类器只是概率上的问题,影响分类器的因素还有很多,不同算法在不同数据集(TrainSet)上的结果可能各不相同。
这就是我大致的理解。
例子与代码借用作者:Jack-Cui
原文链接

发布了2 篇原创文章 · 获赞 1 · 访问量 398

猜你喜欢

转载自blog.csdn.net/ssssdww/article/details/103394057