第二章 K-近邻算法 及 约会网站配对
来源:互联网 发布:mac safari缓存文件 编辑:程序博客网 时间:2024/05/18 01:32
2.1 K-近邻算法概述
K-近邻算法应该就是一个分类算法。采用测量不同特征值之间的距离方法进行分类。
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度高、空间复杂度高。
适用范围:数值型和标称型。
书中举了一个电影分类的例子,通过一些镜头来判断这是爱情片还是动作片爱情动作片。
K-近邻算法的一般流程
- 收集数据:可以使用任何方法。
- 准备数据:距离计算所需要的数值,最好是结构化的数据格式。
- 分析数据:可以使用任何方法。
- 训练算法:此步骤不合适K-近邻算法。
- 测试算法:计算错误率。
- 使用算法:首先需要输入样本数据和结构化的输出结果,然后运行K-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
================================================================================
接下来是准备工作,使用 Python 导入数据。推荐手打,不要复制粘贴。
kNN.py
注意我用的文件可以从 http://www.ituring.com.cn/book/1021 下载,而且根据勘误应该用 datingTestSet2.txt
#-*- coding:utf-8 -*-from numpy import * # 科学计算包import operator # 运算符模块def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) labels = ['A','A','B','B'] return group, labels
>>> import kNN>>> group,labels = kNN.createDataSet()>>> group>>> labels
验证下与书一样就可以了。结果如下图:
==========================================================================
接下来正式的 kNN 算法,需要说明的是,几个输入参数是什么。
inX 是用于分类的输入向量,dataSet 是输入的训练样本,标签向量为 labels , 参数 k 表示的是用于选择的最近邻居的数目,其中标签向量的元素数目和矩阵 dataSet 的行数相同 。
代码如下:
#-*- coding:utf-8 -*-from numpy import * # 科学计算包import operator # 运算符模块def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) labels = ['A','A','B','B'] return group, labelsdef classify0(inX, dataSet, labels, k): # 距离计算 dataSetSize = dataSet.shape[0] # .shape 读取矩阵的长度 diffMat = tile(inX,(dataSetSize,1)) - dataSet # tile(A,n),功能是将数组A重复n次,构成一个新的数组 sqDiffMat = diffMat ** 2 # **就是乘方 sqDistances = sqDiffMat.sum(axis = 1) distances = sqDistances ** 0.5 sortedDistIndicies = distances.argsort() # argsort函数返回的是数组值从小到大的索引值 classCount = {} # 选择距离最小的 K 个点 for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #dict.get(key, default=None) key在字典中查找,在key不存在的情况下返回值None。 # 排序 sorted 函数详见 http://www.cnblogs.com/sysu-blackbear/p/3283993.html sortedClassCount = sorted(classCount.iteritems(), # iteritems以迭代器对象,返回键值对 key = operator.itemgetter(1), reverse = True) # itemgetter(1) 使用元组的第二个元素对列表排序 # itemgetter(0) 使用元组的第一个元素对列表排序 return sortedClassCount[0][0]
第一部分的距离计算就是欧氏距离,没什么好说的。
然后,确定前 k 个距离最小元素所在的主要分类,输入 k 总是正整数。
最后,把 classCount 字典分解为元组列表,然后用 itemgetter 方法,按照第二个元素的次序对元组排序。
==========================================================================================
跑一遍试试:
可以看出 [0,0] 分类结果是 B
==========================================================================================
2.2 示例:使用K-近邻算法改进约会网站配对效果
2.2.1准备数据
样本主要包含以下三种特征:
1.每年获得的飞行常客里程数
2.玩视频游戏所花费时间百分比
3.每周消费冰激凌公升数
在 kNN.py 中创建一个 file2matrix 函数处理输入格式问题。
增加一部分代码,并且在本文一开始的地方下载所需要的数据文件。
#-*- coding:utf-8 -*-from numpy import * # 科学计算包import operator # 运算符模块def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) labels = ['A','A','B','B'] return group, labelsdef classify0(inX, dataSet, labels, k): # 距离计算 dataSetSize = dataSet.shape[0] # .shape 读取矩阵的长度 diffMat = tile(inX,(dataSetSize,1)) - dataSet # tile(A,n),功能是将数组A重复n次,构成一个新的数组 sqDiffMat = diffMat ** 2 # **就是乘方 sqDistances = sqDiffMat.sum(axis = 1) distances = sqDistances ** 0.5 sortedDistIndicies = distances.argsort() # argsort函数返回的是数组值从小到大的索引值 classCount = {} # 选择距离最小的 K 个点 for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #dict.get(key, default=None) key在字典中查找,在key不存在的情况下返回值None。 # 排序 sorted 函数详见 http://www.cnblogs.com/sysu-blackbear/p/3283993.html sortedClassCount = sorted(classCount.iteritems(), # iteritems以迭代器对象,返回键值对 key = operator.itemgetter(1), reverse = True) # itemgetter(1) 使用元组的第二个元素对列表排序 # itemgetter(0) 使用元组的第一个元素对列表排序 return sortedClassCount[0][0]def file2matrix(filename): fr = open(filename) arrayOLines = fr.readlines() numberOfLines = len(arrayOLines) # 文件的行数 returnMat = zeros((numberOfLines, 3)) # 创建返回的 NumPy 矩阵 # 创建给定类型的矩阵,并初始化为0。zeros((A,B)),创建一个A行,B列的0矩阵 classLabelVector = [] index = 0 for line in arrayOLines: # 解析文件数据列表 line = line.strip() # strip() 方法用于移除字符串头尾指定的字符(这里是截掉回车字符) listFromLine = line.split('\t') # tab 字符 returnMat[index,:] = listFromLine[0:3] classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat,classLabelVector
为了方便起见,我再写了一个 use-kNN.py 文件,不用在命令行里面一个一个输入了,文件如下:
import kNNgroup,labels = kNN.createDataSet()print groupprint '**********'print labelsprint '**********'print kNN.classify0([0,0],group,labels,3)print '**********'reload(kNN)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')print datingDataMatprint '**********'print datingLabels[0:20]
结果如下:
以上就是从文本文件导入数据并且转化为想要的格式。不过结果和书上例子不太一样。
========================================================================================================
2.2.2 分析数据
我先建立一个 plot.py 用于画图,代码如下:
import matplotlibimport matplotlib.pyplot as pltimport kNNfig = plt.figure()ax = fig.add_subplot(111)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')ax.scatter(datingDataMat[:,1], datingDataMat[:,2])plt.show()
那么就可以画出图了:
上图存在的问题是,没有用颜色来标记不同样本分类。于是在执行的时候可以加点代码。
# -*- coding:utf-8 -*-import matplotlibimport matplotlib.pyplot as pltimport kNNimport usekNNfrom numpy import * # 没导入会报错fig = plt.figure()ax = fig.add_subplot(111)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))# datingDataMat[:,1], datingDataMat[:,2] 应该指的是二三列?# ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))plt.show()
结果如下:
稍微改动一下,完善一下,加个xy标签,改动一下读取的数据列:
# -*- coding:utf-8 -*-import matplotlibimport matplotlib.pyplot as pltimport kNNimport usekNNfrom numpy import * # 没导入会报错fig = plt.figure()ax = fig.add_subplot(111)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*array(datingLabels), 15.0*array(datingLabels))# datingDataMat[:,1], datingDataMat[:,2] 应该指的是二三列?# ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))plt.xlabel('Air Miles')plt.ylabel('Video Games')plt.show()
得到如下图:
============================================================================
2.2.3 归一化数值
原始数据文件里面,飞行常客里程数远大于其他两者,这导致其影响程度也远大于其他两者,而我们希望三者是具有同样权重的,因此需要归一化处理。
通常我们将其取值范围处理为0到1或者-1到1之间,使用的公式如下:
newValue = (oldValue-min) / (max-min)
我们要在 kNN.py 程序里面加上一个归一化的函数,为了简短起见,就只写这一段。
def autoNorm(dataSet): minVals = dataSet.min(0) # 每列最小变量,参数 0 使得函数可以从列中选取最小值 maxVals = dataSet.max(0) # 每列最大变量 ranges = maxVals - minVals normDataSet = zeros(shape(dataSet)) # 照着 dataSet 的样子做一个 0 矩阵 m= dataSet.shape[0] # shape[0] 指的是矩阵第一维长度 normDataSet = dataSet - tile(minVals, (m,1)) # tile(A,n),功能是将数组A重复n次,构成一个新的数组 normDataSet = normDataSet/tile(ranges, (m,1)) return normDataSet, ranges, minVals
特征值矩阵有 1000 *3 个值,而 minVals 和 range 的值都为 1*3 ,为此我们使用 tile() 函数将变量内容复制成输入举证同样大小的矩阵。另外这里的 / 是具体特征值相除,而 NumPy 的矩阵除法是 linalg.solve(matA,matB) 。
现在执行 autoNorm 试一试,我们在 usekNN.py 里面加一点
# usekNN.pyimport kNNgroup,labels = kNN.createDataSet()print groupprint '**********'print labelsprint '**********'print kNN.classify0([0,0],group,labels,3)print '**********'reload(kNN)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')print datingDataMatprint '**********'print datingLabels[0:20]print '**********'reload(kNN)normMat, ranges, minVals = kNN.autoNorm(datingDataMat)print normMatprint '**********'print rangesprint '**********'print minVals
运行结果就不发了,反正正常...
=====================================================================================
2.2.4 测试算法
这里主要是测试分类器效果,因此要写测试代码:
def datingClassTest(): hoRatio = 0.10 datingDataMat, datingLabels = file2matrix('datingTestSet2.txt') 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)) # 写出正确率
接下来在 usekNN.py 里面加上
reload(kNN)kNN.datingClassTest()
这样运行就知道错误率了,我运行出来的错误率是 5% ,并不算高。
=====================================================================================
2.2.5 使用算法
通过该程序可以在约会网站上面找到某个人输入他的信息,程序会给出预测。
kNN.py 添加代码如下:
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 person: ",\ resultList[classifierResult - 1]
然后 usekNN.py 添加执行:
print '**********'reload(kNN)kNN.classifyPerson()
结果:
===============================================================================================================
最后给一遍完整代码,总共三个文件。
kNN.py:
#-*- coding:utf-8 -*-from numpy import * # 科学计算包import operator # 运算符模块def createDataSet(): group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) labels = ['A','A','B','B'] return group, labelsdef classify0(inX, dataSet, labels, k): # 距离计算 dataSetSize = dataSet.shape[0] # .shape 读取矩阵的长度 diffMat = tile(inX,(dataSetSize,1)) - dataSet # tile(A,n),功能是将数组A重复n次,构成一个新的数组 sqDiffMat = diffMat ** 2 # **就是乘方 sqDistances = sqDiffMat.sum(axis = 1) distances = sqDistances ** 0.5 sortedDistIndicies = distances.argsort() # argsort函数返回的是数组值从小到大的索引值 classCount = {} # 选择距离最小的 K 个点 for i in range(k): voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #dict.get(key, default=None) key在字典中查找,在key不存在的情况下返回值None。 # 排序 sorted 函数详见 http://www.cnblogs.com/sysu-blackbear/p/3283993.html sortedClassCount = sorted(classCount.iteritems(), # iteritems以迭代器对象,返回键值对 key = operator.itemgetter(1), reverse = True) # itemgetter(1) 使用元组的第二个元素对列表排序 # itemgetter(0) 使用元组的第一个元素对列表排序 return sortedClassCount[0][0]def file2matrix(filename): fr = open(filename) arrayOLines = fr.readlines() numberOfLines = len(arrayOLines) # 文件的行数 returnMat = zeros((numberOfLines, 3)) # 创建返回的 NumPy 矩阵 # 创建给定类型的矩阵,并初始化为0。zeros((A,B)),创建一个A行,B列的0矩阵 classLabelVector = [] index = 0 for line in arrayOLines: # 解析文件数据列表 line = line.strip() # strip() 方法用于移除字符串头尾指定的字符(这里是截掉回车字符) listFromLine = line.split('\t') # tab 字符 returnMat[index,:] = listFromLine[0:3] classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat,classLabelVectordef autoNorm(dataSet): minVals = dataSet.min(0) # 每列最小变量,参数 0 使得函数可以从列中选取最小值 maxVals = dataSet.max(0) # 每列最大变量 ranges = maxVals - minVals normDataSet = zeros(shape(dataSet)) # 照着 dataSet 的样子做一个 0 矩阵 m= dataSet.shape[0] # shape[0] 指的是矩阵第一维长度 normDataSet = dataSet - tile(minVals, (m,1)) # tile(A,n),功能是将数组A重复n次,构成一个新的数组 normDataSet = normDataSet/tile(ranges, (m,1)) return normDataSet, ranges, minValsdef datingClassTest(): hoRatio = 0.10 datingDataMat, datingLabels = file2matrix('datingTestSet2.txt') 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)) # 写出正确率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 person: ",\ resultList[classifierResult - 1]
usekNN.py:
# usekNN.pyimport kNNgroup,labels = kNN.createDataSet()print groupprint '**********'print labelsprint '**********'print kNN.classify0([0,0],group,labels,3)print '**********'reload(kNN)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')print datingDataMatprint '**********'print datingLabels[0:20]print '**********'reload(kNN)normMat, ranges, minVals = kNN.autoNorm(datingDataMat)print normMatprint '**********'print rangesprint '**********'print minValsprint '**********'reload(kNN)kNN.datingClassTest()print '**********'reload(kNN)kNN.classifyPerson()
plot.py:
# -*- coding:utf-8 -*-import matplotlibimport matplotlib.pyplot as pltimport kNNimport usekNNfrom numpy import * # 没导入会报错fig = plt.figure()ax = fig.add_subplot(111)datingDataMat,datingLabels = kNN.file2matrix('datingTestSet2.txt')ax.scatter(datingDataMat[:,0], datingDataMat[:,1], 15.0*array(datingLabels), 15.0*array(datingLabels))# datingDataMat[:,1], datingDataMat[:,2] 应该指的是二三列?# ax.scatter(datingDataMat[:,1], datingDataMat[:,2], 15.0*array(datingLabels), 15.0*array(datingLabels))plt.xlabel('Air Miles')plt.ylabel('Video Games')plt.show()
- 第二章 K-近邻算法 及 约会网站配对
- 《机器学习实战》第二章 2.2用k-近邻算法改进约会网站的配对效果
- K-近邻算法改进约会网站的配对效果
- k-近邻算法改进约会网站的配对效果
- K近邻算法(二)--约会网站配对
- 机器学习实践-k近邻算法-约会网站配对源码
- 使用k-近邻算法改进约会网站的配对效果。
- 机器学习之k近邻算法——5、约会网站的配对开发流程
- 机器学习 & python 使用k-近邻算法改进约会网站的配对效果
- k-近邻算法(KNN)--2改进约会网站的配对效果---by香蕉麦乐迪
- 读懂《机器学习实战》代码—K-近邻算法改进约会网站配对效果
- 学习笔记:使用k-近邻算法改进约会网站的配对效果
- 【机器学习实战02】使用k-近邻算法改进约会网站的配对效果
- 机器学习实战—k近邻算法(kNN)02-改进约会网站的配对效果
- 机器学习实战——K-近邻算法【2:改进约会网站配对效果】
- 机器学习—使用k-近邻算法改进约会网站的配对效果
- 『机器学习实战』使用 k-近邻算法改进约会网站的配对效果
- 机器学习实战笔记-K近邻算法2(改进约会网站的配对效果)
- Bootstrap(1)
- 快速教你使用CSDN-markdown编辑器
- ViewPager和PageAdapter,FragmentPageAdapter,FragmentStatePageFragment
- POJ-1426-Find The Multiple
- HTTPS SSL证书
- 第二章 K-近邻算法 及 约会网站配对
- Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法
- 各种进度条的介绍
- Tweak工程
- iOS 银行卡号识别
- Java:反射构造的调用
- realloc,malloc,calloc的区别
- 针对于WebStorm工具开发React工程详细配置
- unity3D-游戏/AR/VR在线就业班 C#入门抽象类学习笔记