机器学习之K近邻算法

什么是K近邻算法

众所周知,电影可以按照题材分类,然而题材本身是如何定义?同一题材的电影有哪些公共特征?这是电影分类的时候必须要考虑的。而K近邻算法就是解决这个问题的。K近邻算法通过分析电影中的特征,比如打斗场景、亲吻次数等来划分测试的影片跟哪个题材相关。

K近邻算法概述

k近邻算法就是采用测量不同的特征值之间的距离方法进行分类。它的优点是精度高、对异常值不敏感、无数据输入假定。它的缺点是计算复杂度高、空间复杂度高、仅适用于数值型和标称型数据。

K近邻算法的一般流程

(1)收集数据:数据还要数值型或者是标称型数据
(2)准备数据:将数据转化成距离计算所需要的数值
(3)分析数据:使用K近邻算法对数据进行分析
(4)测试算法:计算该算法的错误率
(5)使用算法:输入想要测试的数据,运行K近邻算法,得出结果

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

这两个东西有什么用呢?这四组值加上四组标签一一对应在x,y轴上的话就是


坐标

这时候输入一个坐标,例如(1,1)这个点,计算这个点与这四个点的欧氏距离,得出与A标签的点距离近,所以(1,1)这个点就属于类型A。这就是K近邻算法。算法伪代码如下:

对未知类别属性的数据集中的点依次执行以下操作:
1.计算已知类别数据集中的点与当前点之间的距离
2.按照距离递增次序排序 
3.选取与当前点距离最小的k个点
4.确定前k个点所在类别的出现频率
5.返回前k个点出现频率最高的类别作为当前点的预测分类

程序代码如下所示:

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
    sortedDistIndicies = distances.argsort()     
    classCount={}          
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    sortedClassCount = sorted(classCount.items(), key=lambda v: v[1], reverse=True)
    return sortedClassCount[0][0]

其中函数的输入有四个,inX是输入向量,也就是要分类的对象。dataSet是训练样本集。labels是训练样本集对应的标签。最后的参数k表示选择最近邻的数目。其中计算两个点之间的距离用的是欧氏距离,公式如下:


计算欧式距离

如果不是二维空间,而是多维空间,那么计算距离公式为:


四维空间计算公式

计算完所有距离之后,可以对数据按照从小到大的次序排列。然后确定前k个距离最小元素所在的分类,返回出现频率最高的元素标签。
运行上述程序,输出的结果应该是B。

测试K近邻算法

对于测试分类器,我们可以用已知的数据来进行测试,首先将已知数据使用K近邻算法进行分类,然后将已知数据的标签与测试结果作对比,来得到我们的误差率。我们使用《机器学习实战》这本书上海伦对约会网站上的哪类人感兴趣的数据集来进行测试。算法伪代码如下:
1.准备数据:使用python解析文件数据
2.分析数据:使用matplotlib画出二维扩散图
3.测试数据:使用文件中部分数据集作为测试样本进行测试
4.得出结果:将样本测得的标签与实际标签作对比,记录错误标签的数目

def file2matrix(filename):#准备数据
    fr = open(filename,'r',encoding='UTF-8')
    numberOfLines = len(fr.readlines())         #get the number of lines in the file
    returnMat = zeros((numberOfLines,3))        #prepare matrix to return
    classLabelVector = []                       #prepare labels return   
    fr = open(filename,'r',encoding='UTF-8')

    index = 0
    for line in fr.readlines():
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index +=1
    return returnMat,classLabelVector

#画出散点图
fig = plt.figure()
ax = fig.add_subplot(111)
datingDataMat,datingLabels = kNN.file2matrix('EXTRAS/datingTestSet2.txt')
ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 35, 1.0*array(datingLabels))
ax.axis([-2,100000,-0.2,25])
plt.xlabel('Percentage of Time Spent Playing Video Games')
plt.ylabel('Liters of Ice Cream Consumed Per Week')
plt.show()

    
def autoNorm(dataSet):  #数据归一化
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet = normDataSet/tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals
   
def datingClassTest():      #测试误差率
    hoRatio = 0.5     #hold out 10%
    datingDataMat,datingLabels = file2matrix('./datingTestSet2.txt')       #load data setfrom file
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]
    numTestVecs = int(m*hoRatio)
    errorCount = 0.0
    for i in range(numTestVecs):
        classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print ("the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0
    print( "the total error rate is: %f" % (errorCount/float(numTestVecs)))
    print ('errorCount')

其中散点图如下所示:


二维散点图

图中清晰地表示了这两个类别对结果的影响。这时候从图中就可以看出,x,y轴的度量单位差异较大,所以对于结果来说,x轴的数据所占的权重较大,这明显是不符合常规的。所以我们在这儿需要将特征值进行归一化处理,将每个特征都归一化有助于平均所有特征的权重。归一化代码如上图所示。最后测试k近邻算法,随机抽取前50%数据来测试,结果得出误差率为6.4%,这个结果还比较不错。这个例子表明我们可以正确地预测分类,现在可以调用k近邻算法来对输入的特征值进行分类,从而确定结果是属于哪一类!
预测函数代码如下:


def classifyPersion():
    resultlist =['not at all','in small doses','in large doses']
    percenttats = float(input("percentage of time spent playing video game:"))
    ffmile = float(input('frequent filer miles earned per year:'))
    icecream = float(input('liters of ice cream consumed per year:'))
    datingDateMat,datingLabels = file2matrix('EXTRAS/datingTestSet2.txt')
    normMat,ranges,minVals = autoNorm(datingDateMat)
    inArr = array ([ffmile,percenttats,icecream])
    classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3)
    print("You will probably like this person: ",resultlist[classifierResult-1])

现在运行这段代码,并输入测试人的信息,就能得出对这个人感兴趣的程度,如下图所示:


运行结果

现在只要输入某个人的这三项特征,就能得出对他感不感兴趣,极大地提高了配对速率。

了解更多请关注作者微信公众号:

一技破万法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容