机器学习(一)——KNN算法之约会网站匹配效果

【实验目的】

为了熟悉和掌握K近邻算法,改进约会网站的匹配策略。

【实验要求】

用KNN算法改进约会网站的配对效果。

【算法原理】

k近邻法(k-nearest neighbor, k-NN)原理:存在一个样本数据集合,也称作为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一个数据与所属分类的对应关系。输入没有标签的新数据后,将新的数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本最相似数据(最近邻)的分类标签。

【算法流程】

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

2、按照距离递增次序排序;

3、选取与当前点距离最小的k个点;

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

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

【实验背景】

海伦女士一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的任选,但她并不是喜欢每一个人。经过一番总结,她发现自己交往过的人可以进行如下分类:

· 不喜欢的人

· 魅力一般的人

· 极具魅力的人

海伦收集约会数据已经有了一段时间,她把这些数据存放在文本文件datingTestSet.txt中,每个样本数据占据一行,总共有1000行。

海伦收集的样本数据主要包含以下3种特征:

· 每年获得的飞行常客里程数

· 玩视频游戏所消耗时间百分比

· 每周消费的冰淇淋公升数

【实验流程】

①准备数据:数据解析

在将上述特征数据输入到分类器前,必须将待处理的数据的格式改变为分类器可以接收的格式。分类器接收的数据是什么格式的?从上小结已经知道,要将数据分类两部分,即特征矩阵和对应的分类标签向量。在kNN_test02.py文件中创建名为file2matrix的函数,以此来处理输入格式问题。 将datingTestSet.txt放到与kNN_test02.py相同目录下,编写代码如下:

# -*- coding: UTF-8 -*-

import numpy as np

def file2matrix(filename):

 #打开文件

 fr = open(filename)

 #读取文件所有内容

 arrayOLines = fr.readlines()

 #得到文件行数

 numberOfLines = len(arrayOLines)

 #返回的NumPy矩阵,解析完成的数据:numberOfLines行,3列

 returnMat = np.zeros((numberOfLines,3))

 #返回的分类标签向量

 classLabelVector = []

 #行的索引值

 index = 0

 for line in arrayOLines:

 #s.strip(rm),当rm空时,默认删除空白符(包括'\n','\r','\t',' ')

 line = line.strip()

 #使用s.split(str="",num=string,cout(str))将字符串根据'\t'分隔符进行切片。

 listFromLine = line.split('\t')

 #将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵

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

 #根据文本中标记的喜欢的程度进行分类,1代表不喜欢,2代表魅力一般,3代表极具魅力

 if listFromLine[-1] == 'didntLike':

 classLabelVector.append(1)

 elif listFromLine[-1] == 'smallDoses':

 classLabelVector.append(2)

 elif listFromLine[-1] == 'largeDoses':

 classLabelVector.append(3)

 index += 1

 return returnMat, classLabelVector

if __name__ == '__main__':

 #打开的文件名

 filename = "datingTestSet.txt"

 #打开并处理数据

 datingDataMat, datingLabels = file2matrix(filename)

 print(datingDataMat)

 print(datingLabels)

运行上述代码,得到解析过的数据,如图所示:

1.png

②****分析数据:数据可视化

在kNN_test02.py文件中编写名为showdatas的函数,用来将数据可视化。具体代码请见附录。

运行showdatas函数结果如下图所示:

2.png

③****准备数据:数据归一化

我们很容易发现,上面方程中数字差值最大的属性对计算结果的影响最大,也就是说,每年获取的飞行常客里程数对于计算结果的影响将远远大于表2.1中其他两个特征-玩视频游戏所耗时间占比和每周消费冰淇淋公斤数的影响。而产生这种现象的唯一原因,仅仅是因为飞行常客里程数远大于其他特征值。但海伦认为这三种特征是同等重要的,因此作为三个等权重的特征之一,飞行常客里程数并不应该如此严重地影响到计算结果。

在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:

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

其中min和max分别是数据集中的最小特征值和最大特征值。虽然改变数值取值范围增加了分类器的复杂度,但为了得到准确结果,我们必须这样做。在kNN_test02.py文件中编写名为autoNorm的函数,用该函数自动将数据归一化。代码如下:

def autoNorm(dataSet):

 #获得数据的最小值

 minVals = dataSet.min(0)

 maxVals = dataSet.max(0)

 #最大值和最小值的范围

 ranges = maxVals - minVals

 #shape(dataSet)返回dataSet的矩阵行列数

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

 #返回dataSet的行数

 m = dataSet.shape[0]

 #原始值减去最小值

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

 #除以最大和最小值的差,得到归一化数据

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

 #返回归一化数据结果,数据范围,最小值

 return normDataSet, ranges, minVals

运行上述函数,结果如下图所示:

3.png

从上图的运行结果可以看到,我们已经顺利将数据归一化了,并且求出了数据的取值范围和数据的最小值,这两个值是在分类的时候需要用到的,直接先求解出来,也算是对数据预处理了。

④测试算法:验证分类器

机器学习算法一个很重要的工作就是评估算法的正确率,通常我们只提供已有数据的90%作为训练样本来训练分类器,而使用其余的10%数据去测试分类器,检测分类器的正确率。需要注意的是,10%的测试数据应该是随机选择的,由于海伦提供的数据并没有按照特定目的来排序,所以我么你可以随意选择10%数据而不影响其随机性。为了测试分类器效果,在kNN_test02.py文件中创建函数datingClassTest,编写代码如下:

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]

def datingClassTest():

 #打开的文件名

 filename = "datingTestSet.txt"

 #将返回的特征矩阵和分类向量分别存储到datingDataMat和datingLabels中

 datingDataMat, datingLabels = file2matrix(filename)

 #取所有数据的百分之十

 hoRatio = 0.10

 #数据归一化,返回归一化后的矩阵,数据范围,数据最小值

 normMat, ranges, minVals = autoNorm(datingDataMat)

 #获得normMat的行数

 m = normMat.shape[0]

 #百分之十的测试数据的个数

 numTestVecs = int(m * hoRatio)

 #分类错误计数

 errorCount = 0.0

 for i in range(numTestVecs):

 #前numTestVecs个数据作为测试集,后m-numTestVecs个数据作为训练集

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

 datingLabels[numTestVecs:m], 4)

 print("分类结果:%d\t真实类别:%d" % (classifierResult, datingLabels[i]))

 if classifierResult != datingLabels[i]:

 errorCount += 1.0

print("错误率:%f%%" %(errorCount/float(numTestVecs)*100))

运行上述代码,得到结果如下图所示

4.png

从上图验证分类器结果中可以看出,错误率是3%,这是一个想当不错的结果。我们可以改变函数datingClassTest内变量hoRatio和分类器k的值,检测错误率是否随着变量值的变化而增加。依赖于分类算法、数据集和程序设置,分类器的输出结果可能有很大的不同。

【实验结果】

我们将上述所提及的各个函数都连接起来在程序中,这样我们就构建了完整可用的系统。具体代码请参考附录。

在cmd中,运行程序,并输入数据(12,44000,0.5),预测结果是”你可能有些喜欢这个人”,也就是这个人魅力一般。一共有三个档次:讨厌、有些喜欢、非常喜欢,对应着不喜欢的人、魅力一般的人、极具魅力的人。结果如下图所示。

5.png

【实验总结】

1、在实验的过程中,主要遇到了以下几个问题

(1)不懂KNN算法的原理。

解决:通过百度搜索有关KNN的博文进行阅读与学习。

(2)不懂处理原始的数据材料。

解决:运用python的numpy的包将待处理的数据的格式改变为分类器可以接收的格式,同时将数据进行可视化处理。

(3)某单一数据对实验结果影响非常大。

解决:对数据进行归一化处理。

2、自己在考虑本实验时的想法及实现情况。

答:整个实验的结果表现良好,对实验进行交叉验证,错误率为3%。在实验的过程遇到了很多函数包缺失导致的报错,这时候一定要彻底弄明白错误出现的原因,同时要将解决这个问题的过程以博文的形式记录下来。

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

推荐阅读更多精彩内容