您的位置:首页 > 其它

机器学习入门读书笔记三(k-近邻算法 kNN) 中

2016-08-14 16:11 701 查看

使用k-近邻算法改进约会网站的配对效果

背景:我的朋友海伦一直使用在线约会网站寻找适合自己的约会对象。尽管约会网站会推荐不同人选,但她没有从中找到喜欢的人。经过一番总结,她发现曾交往过三种类型的人:

不喜欢的人
魅力一般的人
极具魅力的人

尽管发现了上述规律,但海伦依然无法将约会网站推荐的匹配对象归入恰当的分类。她觉得可以在周一到周五约会那些魅力一般的人,而周末则更喜欢与那些极具魅力的人为伴。海伦希望我们的分类软件可以更好地帮助她将匹配对象划分到确切的分类中。此外海伦还收集了一些约会网站未曾记录的数据信息,她认为这些数据更有助于匹配对象的归类。

步骤

收集数据:提供文本文件。

准备数据:使用python解析文本文件。

分析数据:使用Matplotlib画二维扩散图。

训练算法:此步骤不适用于k-近邻算法。

测试算法:使用海伦提供的部分数据作为测试样本。

使用算法:产生简单的命令行程序。

准备数据:从文本文件中解析数据

数据存储在文本文件datingTestSet2.txt中,每个样本数据占一行,总共1000行。海伦的样本主要包含以下三种特征:(数据在这下载

每年获得的飞行常客里程数
玩视频游戏所耗时间百分比
每周消费的冰淇淋公升数
用于处理文件,在kNN模块中创建file2matrix()函数:

def file2matrix(filename):
fr = open(filename)
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)
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


获取每条数据的前三个特征值构成了3*1000的矩阵,作为训练样本矩阵returnMat,每条数据的最后一个值存储的是所属分类的标签,则这些值构成了1*1000的类标签向量classLabelVector。



reload(kNN)是为了重新加载kNN模块,由此就由文件获取到了样本矩阵和类向量。

分析数据:使用Matplotlib创建散点图





此为样本矩阵第二列和第三列特征值构成的散点图,可以看出此散点图并不能看到任何有用的数据模式信息,所以我们要根据散点的类别对散点进行个性标记,如下:





由于此处用带了numpy的array()函数,所以必须先加入from numpy import array,根据有颜色标记的散点图可以大致看出爱好对于类别的影响。

准备数据:数值归一化

示例数据
 玩游戏耗时百分比飞行里程先好冰淇淋公升数样本分类
10.84000.51
2121340000.93
30200001.12
467320000.12
表中的数据,样本三和样本四之间的距离可以使用下面的方法:



显然,方程中数值最大的属性对计算结果影响过大,严重影响计算结果,这并非我们想要的,所以我们采用的方法是将数值归一化,如将范围处理为0到1或者-1到1之间。下面的公式可以将任意取值范围的特征值转化为0到1区间内的值:



python实现如下:

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%数据去测试分类器,检测分类器的正确率。需要注意的是,这10%的测试数据应该是随机选择的,下面我们在kNN.py中创建函数datingClassTest()来测试分类器效果,获取错误率。
datingClassTest()代码如下:
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



代码中用datingTestSet2.txt中的50%的数据作为测试样本,50%的数据作为训练样本,将推测结果和实际结果进行比较,获取错误率,以下为测试结果:



错误率为6.4%,我们可以通过对训练样本和测试样本的调整,改变精度,也可以通过对k值的调整,改变精度。

使用算法:完善系统

kNN.py中加入函数classifyPerson():
def classifyPerson():
resultList = ['not at all', 'in small doses', 'in large doses']
percentTats = float(raw_input("percentage of time spent playing video games?"))
ffMiles = float(raw_input("frequent flier miles earned per year?"))
iceCream = float(raw_input("liters of ice cream consumed per year?"))
datingDataMat, datingLabels = file2matrix("datingTestSet2.txt")
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = array([ffMiles, percentTats, iceCream])
classifierResult = classify0((inArr - minVals) / ranges, normMat, datingLabels, 3)
print "you will probably like this peron:", resultList[classifierResult - 1]




此时一个简单的分类系统创建完成了!


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息