一、前言
我的朋友mike一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同的人选,但他并不是喜欢每一个人。经过一番总结,她发现曾交往三种类型的人:
不喜欢的人;
魅力一般的人;
极具魅力的人
尽管发现了上述规律,但mike依然无法将约会网站推荐的匹配对象归入恰当的类别。他觉得可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴。mike希望我们的分类软件可以更好地帮助他将匹配对象划分到明确的分类中。此外mike还收集了一些约会网站未曾记录的数据信息,他认为这些数据更有助于匹配对象的归类。
实施流程:
(1).收集数据:提供文本文件。
(2).准备数据:使用python解析文本文件。
(3).分析数据:使用matplotlib画二维扩散图。
(4).训练算法:此步骤不适用于k-近邻算法。
(5).测试算法:使用mike提供的部分数据作为测试样本。测试样本和非测试样本的区别在于:测试样本是已经完成分类的数据,如果预测分类与实际类别不同,则标记为一个错误。
(6).使用算法:产生简单的命令行程序,然后mike可以输入一些特征数据以判断对方是否为自己喜欢的类型。
二、准备数据
mike收集约会数据已经有了一段时间,他把这些数据存放在文本文件datingTestSet2.txt中,每个样本数据占据一行,总共有1000行。mike的样本主要包含以下3种特征:
(1)每年获得的飞行常客里程数
(2)玩视频游戏所耗时间百分比
(3)每周消费的冰淇淋公升数
在将上述特征数据输入到分类器之前,必须将待处理数据的格式改变为分类器可以接受的格式。
from numpy import *
import operator
import numpy as np
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=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
def file2matrix(filename):
fr=open(filename)
arraryOLines=fr.readlines()
numberOfLines=len(arraryOLines)
returnMat=zeros((numberOfLines,3))
classLabelVector=[]
index=0
for line in arraryOLines:
line=line.strip()
listFromLine=line.split('\t')
returnMat[index,:]=listFromLine[0:3]
classLabelVector.append(int(listFromLine[-1]))
index+=1
return returnMat,classLabelVector
三、分析数据
首先我们使用matplotlib制作原始数据的散点图,在python命令行环境中,输入下列命令:
import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()
输出效果如下,散点图图使用datingDataMat矩阵的第二、第三列数据,分别表示特征值“玩视频游戏所耗时间百分比”和“每周所消费的冰淇淋公升数”,利用变量datingLabels存储的类标签属性,在散点图上绘制了色彩不等、尺寸不同的点。
image.png但是我们很难看到任何有用的信息。我们可以继续尝试用矩阵的第一和第二列属性来展示效果。下图清晰地标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同。
image.png
三、准备数据
image.png在处理这种不同取值范围的特征值时,我们通常采用的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:
newValue=(oldValue-min)/(max-min)
其中min和max分别是数据集中的最小特征值和最大特征值。
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
五、测试算法
机器学习算法一个很重要的工作就是评估算法的正确率,通常我们只提供已有数据的90%作为训练样本来训练分类器,而使用其余的10%数据去测试分类器,检验分类器的正确率。对于分类器来说,错误率就是分类器给出错误结果的次数除以测试数据的总数,完美分类器的错误率为0,而错误率为1.0的分类器不会给出任何正确的分类结果。代码里我们定义一个计数器变量,每次分类器错误地分类数据,计数器就加1,程序执行完成之后计数器的结果除以数据点总数即是错误率。
def datingClassTest():
hoRatio = 0.10 #hold out 10%
datingDataMat,datingLabels = file2matrix('G:/数据/MLiA_SourceCode/machinelearninginaction/Ch02/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)
image.png
分类器处理约会数据集的错误率是5%,这是一个相当不错的结果。我们可以改变函数datingClassTest内变量hoRatio和变量k的值,检测 错误率是否随着变量值得变化而增加。依赖于算法、数据集和程序设置,分类器的输出结果可能有很大的不同。这个例子表明我们可以正确地预测分类,错误率仅仅5%。mike完全可以输入未知对象的属性信息,由分类软件来帮助他判定某一对象的可交往程度:讨厌、一般喜欢、非常喜欢。
六、使用算法
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 fliter miles earned per year?"))
iceCream=float(input("liters of ice cream consumed per year?"))
datingDataMat,datingLabels=file2matrix('G:/数据/MLiA_SourceCode/machinelearninginaction/Ch02/datingTestSet2.txt')
norMat,ranges,minVals=autoNorm(datingDataMat)
inArr=array([ffMiles,percentTats,iceCream])
classifierResult=classify0((inArr-minVals)/ranges,norMat,datingLabels,3)
print("You will probably like this person:" ,resultList[classifierResult-1])
构建约会网站预测函数,通过输入特征值,来预测喜欢的类型,输入示例如下:
image.png
网友评论