7. 宝剑还需剑鞘:核心算法外的一些代码实现

k-近邻算法是个挺好的算法,我喜欢,也希望大家喜欢。它简单小巧,如同一柄鱼肠剑,但同样锋利无比。上一篇我们解读了核心的13行代码,由于作者用了一番python的特色函数,所以写的短小精悍。我也会尝试写一个行数更多、跑的更慢,但更容易理解的,这在后文再说,到时候也会就性能等做个对比。现在,我们先来看看,除了核心代码外的一些实现。


先来看一下数据的准备,如何从文本文件里读出数据并转换成numpy数组。我们看下代码:

def file2matrix(filename):

    love_dictionary = {'largeDoses':3, 'smallDoses':2, 'didntLike':1}

    fr = open(filename)

    arrayOLines = fr.readlines()

    numberOfLines = len(arrayOLines)            #get the number of lines in the file

    returnMat = np.zeros((numberOfLines, 3))        #prepare matrix to return

    classLabelVector = []                      #prepare labels return

    index = 0

    for line in arrayOLines:

        line = line.strip()

        listFromLine = line.split('\t')

        returnMat[index, :] = listFromLine[0:3]

        if(listFromLine[-1].isdigit()):

            classLabelVector.append(int(listFromLine[-1]))

        else:

            classLabelVector.append(love_dictionary.get(listFromLine[-1]))

        index += 1

    return returnMat, classLabelVector

如上代码就不一行行的解释了,相信大家看了也很容易懂,无外乎做了如下几步:

1)生成一个love_dictionary的字典,目的是用来解析替换心动标签为数字;

2)打开文本文件,逐行读取数据并存入arrayOLines;

3)生成一个三列的矩阵数组returnMat,用来存储从文本中读取到的样本数据,并生成一个数组classLabelVector用来存储标签;

4)遍历文本中所有的行,以tab作为分割,将样本的特征列存入returnMat,标签存入classLabelVector;

没了。代码行数多,但不代表难理解,只要是学过python文本处理读取处理、python数组处理(如数组-1代表最后一行),就基本可以了。


第二步,我们来看下,使用matplotlib观察数据:

fig = plt.figure()

ax = fig.add_subplot(111)

datingDataMat,datingLabels = kNN.file2matrix('datingTestSet.txt')

# ax.scatter(datingDataMat[:,1], datingDataMat[:,2])

ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))

ax.axis([-2,25,-0.2,2.0])

plt.xlabel('Percentage of Time Spent Playing Video Games')

plt.ylabel('Liters of Ice Cream Consumed Per Week')

plt.show()

这一段其实也没啥好讲的,可以自己敲一敲就明白了。matplotlib是一款挺好的可视化库,只用短短的几行,就能够完成可视化过程,并且还可以生成立体透视(三维效果)。


第三步,是归一化数据:

def autoNorm(dataSet):

    minVals = dataSet.min(0)

    maxVals = dataSet.max(0)

    ranges = maxVals - minVals

    normDataSet = np.zeros(np.shape(dataSet))

    m = dataSet.shape[0]

    normDataSet = dataSet - np.tile(minVals, (m, 1))

    normDataSet = normDataSet/np.tile(ranges, (m, 1))  #element wise divide

    return normDataSet, ranges, minVals

这段代码也比较简单。归一化的思路,就是将数据转换到0-1的区间。如何实现0-1的转换呢?


归一化公式

分母就是ranges, normDataSet = dataSet - np.tile(minVals, (m, 1))这行其实就是将minVals扩展到了整个矩阵大小,然后再拿dataSet去减,等于就是分子。最后再进行除法运算,实现了如上公式(还是不太玩得好这个矩阵扩展+运算的方式,但确实狠简练,虽然看起来会有点晕,原理是简单的)。


第四步,我们来看看测试代码:

def datingClassTest():

    hoRatio = 0.50      #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)

hoRatio是设定了用来作为测试数据的数量,在这里是设置了50%。载入测试数据,并且归一化后,设置了errorCount作为计数。

之后就是跑一遍所有的测试数据,并计算错误率。这里主要就是数组的操作以及函数的调用,就不重点讲了。


第五步,进行约会的预测:

def classifyPerson():

    resultList = ['not at all', 'in small doses', 'in large doses']

    percentTats = float(input( "percentage of time spent playing video games?"))

    ffMiles = float(input("frequent flier miles earned per year?"))

    iceCream = float(input("liters of ice cream consumed per year?"))

    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')

    normMat, ranges, minVals = autoNorm(datingDataMat)

    inArr = np.array([ffMiles, percentTats, iceCream, ])

    classifierResult = classify0((inArr -  minVals)/ranges, normMat, datingLabels, 3)

    print("You will probably like this person: %s" % resultList[classifierResult - 1])

这段代码更简单了吧?无外乎就是让用户输入相应的数字,然后再去调用classify0的函数。哦对了,要先做归一化。最后再去根据预测结果的标签值,去resultList取到文字描述,O了。


上面的代码,再回顾一下,包括五段:

1)数据的准备,即从文本生成数据;

2)matplotlib,用来可视化数据;

3)归一化数据,使数据控制在0-1之间;

4)测试算法模型的有效性,看错误率是否可控;

5)将模型用于实际预测;


核心算法就是那个classify0,就像是宝剑,而核心算法外的代码很多也很重要,它们共同完成了算法的实施搭建,这些代码就像是宝剑的剑鞘,守护着算法的有效实施。

当然,如果你的剑鞘足够的“兼容”,那么就可以与宝剑自由搭配,并非一剑一鞘。这就是模块化,框架化,可组装。玩过keras等框架的都明白这种组装的便利性,就像是插接玩具一样。

所以,咱们学了这些算法后,是否能自己封装一个框架呢?这是后话了。

约会数据很好玩,那么其他数据是否k-近邻算法也很溜呢?这个咱们来验证下。正好书上有另一个应用,就是手写数字数据集的光学识别。我们在下一章实测下k-近邻算法在手写数字识别上的表现。

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

推荐阅读更多精彩内容