【实现】利用KNN约会分类

代码来自于《机器学习实战》

问题背景

小红经常在约会网站寻找适合自己的约会对象。经过自己的总结,发现曾经交往过三种类型的人:

不喜欢的人

魅力一般的人

极具魅力的人

发现了上述规律,小红还是无法将约会网站推荐的匹配对象归到恰当的类别。她希望在周一到周五约会那些魅力一般的人,周末想那些极具魅力的人为伴(世界一直围绕着小红在转啊转……)。我们怎么帮助她?

1. 数据处理

数据保存在datingTestSet2.txt中,每个样本占据一行,共有1000行(哇,人才)。样本主要包含以下3个特征:

每月工资

玩游戏所消耗时间百分比

每周消费的冰淇淋公升数

《【实现】利用KNN约会分类》 些许样例示意图

A 处理数据:将文本中的数据变成分类器能接受的格式。

导入需要的工具包

from numpy import *

定义函数file2Matrix:将文本数据转换成矩阵形式

def file2Matrix(filename):

    fr= open(filename)

    arrayOLines= fr.readlines()#直接将数据全部读取进来,形成列表,每一行为一个元素

    numberOfLines= len(arrayOLines)#行数

    returnMatrix= zeros((numberOfLines,3))

    classLabelVector= []

    index= 0

    for linein arrayOLines:

        line= line.strip()

        listFromLine= line.split(‘\t’)

        returnMatrix[index,:] = listFromLine[0:3]#赋值方式很厉害!

        classLabelVector.append(listFromLine[-1])

        index+= 1

    return returnMatrix,classLabelVector

B 数据归一化处理

数据中特征“每月工资”,取值范围太大,计算距离时,产生的影响过大。但我们认为3个特征的重要性是一样的。所以,有必要进行数据归一化处理。将数据归一化到 0~1 之间。

公式

newValue = (oldValue-min)/(max-min)

定义归一化函数autoNorm;返回归一化的数据,每个特征的最小值以及范围(方便对新数据进行归一化处理)。

def autoNorm(dataSet):

    minVals= dataSet.min(0)#a.min() :全部的最小值;;a.min(axis=0):每列中的最小值;a.min(axis=1):每行中的最小值

    maxVals= dataSet.max(0)

    ranges= maxVals- minVals

    m= dataSet.shape[0]#行数

    normDataSet= dataSet- tile(minVals,(m,1))#(m,n)重复次数:行方向上重复m次,列方向上重复1次

    normDataSet= normDataSet/tile(ranges,(m,1))

    return normDataSet,ranges, minVals

其中,调用的函数

dataSet.min(0)

dataSet:python numpy array类型

array.min():求数组中的最小值

array.min(axis=0):对数组中的每列求最小值

array.min(axis=1):对数组中的每行求最小值

numpy.tile(A, reps):

Construct an array by repeating A the number of times given by reps.通过重复A ,reps次构建一个新的数组。

tile(minVals, (m, 1)):重复minVals 构造一个m*1的copy

2. 分类算法KNN

伪代码:

对未知类别属性的数据集中的每个点依次执行以下操作:

(1)计算已知类别数据集中的点与当前点之间的距离;

(2)按照距离递增次序排序;

(3)选取与当前点距离最近的k个点;

(4)确定前k个点所在类别的出现频率;

(5)返回前k个点出现频率最高的类别作为当前点的预测分类。

其实是计算两个数据的相似性:有距离相似性度量和角度相似性度量【knn算法介绍】。

这里采用距离相似性度量,欧式距离。

《【实现】利用KNN约会分类》 欧式距离计算公式

分类器算法实现:

def classify0(inX, dataSet, labels, k):

    dataSetSize= dataSet.shape[0]

    diffMat= tile(inX,(dataSetSize,1)) – dataSet

    sqDiffMat= diffMat** 2

    sqDiffMat= sqDiffMat.sum(axis=1)#按列求和

    distances= sqDiffMat** 0.5

    sortedDistIndicies= distances.argsort()#argsort函数返回的是数组值从小到大的索引值

    classCount= {}

    for iin range(k):

        voteLabel= labels[sortedDistIndicies[i]]

        classCount[voteLabel] = classCount.get(voteLabel,0) + 1#在字典classCount中通过 键 查找相应的值,如果字典中没有键,值为0;有获取其值;最后加1

    sortedClassCount= sorted(classCount.items(),key=lambda a:a[1],reverse=True)#根据出现次数排序,降序排序

    return sortedClassCount[0][0]#返回概率最大(出现次数最多的键,即类别)

其中,调用函数:

numpy.argsort:

Returns the indices that would sort an array. 返回数组排序后的下标(默认升序排序)。

eg:[10, 1, 51]

调用函数,返回的是:[1, 0, 2]  ;1是数据1的下标。

3. 测试算法

数据指标:误分率。

计算方法: 错误分类的记录数/测试数据的总数;

def datingClassTest():

    “””

    使用测试数据测试分类器效果

    :return: 误分率”””

    hoRatio= 0.10#测试数据所占的比例—将数据集按照1:9的比例划分,1是测试集;9是训练集

    datingDataMat,datingLabels= file2Matrix(‘datingTestSet2.txt’)

    normMat,ranges,minVals= autoNorm(datingDataMat)

    m= normMat.shape[0]#数据集总数

    numTestVecs= int(m*hoRatio)#测试集数目

    errorCount= 0

    for i  in range(numTestVecs):

        classifierResult= classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)

        print (“the classifier came back with: %s,the real answer is: %s”  % (classifierResult, datingLabels[i]))

        if (classifierResult!= datingLabels[i]):

            errorCount+= 1

    print (“the total error rate is: %f” %(errorCount/float(numTestVecs)))

运行结果:

《【实现】利用KNN约会分类》 测试算法运行结果

错误率:5%

4. 使用算法

重头戏:使用knn分类算法,方便小红约会哦!

def classifyPerson1():

    resultList= [“不喜欢”,”魅力一般”,”极具魅力(韩国欧巴)”]

    percentTats= float(raw_input(\

“花费在游戏、视频上的时间百分比?”))#raw_input:读取控制台输入数据,赋值给变量,等效于C++里的cin>>a;

    ffMiles= float(raw_input(“每月工资有多少?”))

    iceCream= float(raw_input(“每年消耗的冰淇淋有多少升?”))

    datingDataMat,datingLabels= file2Matrix(“datingTestSet2.txt”)

    normMat,ranges,minVals= autoNorm(datingDataMat)

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

    classifierResult= classify0((inArr-minVals)/ranges,normMat,datingLabels,k=3)#对输入数据进行归一化,然后再分类

    print (“你将约会的人很可能是: %s” % resultList[int(classifierResult)-1])

应用:

《【实现】利用KNN约会分类》 小红将约会韩国欧巴(安排在周末)

《【实现】利用KNN约会分类》 小红遇到不喜欢的类型(pass)

5. 小结

A。 矩阵运算—-能加快运算速度;

B。knn算法分类数据简单有效,不用进行训练,是基于实例的学习,使用的数据必须接近实际数据的训练样本数据;必须保存所有数据,如果数据集过大,需要耗费巨大的存储空间;必须对数据中的所有样例点进行计算距离值,非常耗时(即使使用矩阵进行运算)。

C。人生苦短,我用Python!

完整代码及数据集:github

    原文作者:七八音
    原文地址: https://www.jianshu.com/p/0f9194850e85#comments
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞