本文为参考<<Machine Learning in Action>>所写成。
1.原理:不再赘述
2.k近邻算法的一般流程
(1)收集数据
(2)准备数据:最好是结构化的数据格式
(3)分析数据
(4)训练算法:注意!该步骤不适用于k近邻算法。(注:k近邻是基于实例的算法,不需要训练)
(5)测试算法:计算错误率
(6)使用算法
3.具体实现
3.1准备:使用python导入数据
首先,创建名为knn.py的python模块。在这一部分,编写一个导入数据的通用函数。如下:
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
3.2实施knn算法
这一部分实现的功能为使用knn算法进行分类,伪代码如下:
对未知类别属性的数据集中的每个点依次执行以下操作:
(1)计算已知类别数据集中的点与当前点之间的距离;
(2)按照距离递增次序排序;
(3)选取与当前点距离最小的k个点;
(4)确定前k个点所在类别的出现频率;
(5)返回前k个点出现频率最高的类别作为当前点的预测分类。
基于上述伪代码实现的分类算法如下:
'''
@abstract:knn的分类函数
@input: inX为用于分类的输入向量;dataSet为输入的训练样本集;
labels为标签向量;k为knn中的k
@output:inX对应的类别标签
'''
def classify0(inX, dataSet, labels, k):
#shape是numpy.core.fromnumeric中的函数,其功能是读取矩阵的长度
#其输入可以是一个整数,代表维度,如下即为计算矩阵第一维的长度
#也可以是一个矩阵,返回则为该元组的长度的元组
dataSetSize = dataSet.shape[0] #dataSet第一维的长度与labels长度相同
#tile是numpy.lib.shape_base中的函数,其功能是重复某个数组
#tile(a,(b,c))参数:a是要重复的数组,b是重复的维度,c是对每个维度再出现的次数
#如下的功能是将inX重复生成[dataSetSize,len(inX)]的二维矩阵
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2 #矩阵每个位置单独平方
#矩阵内部求和,axis内为求和基准(axis=0则为按列求和,axis=1则为按行求和)
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5 #矩阵每个位置单独开方
#以上,距离计算完成,使用的是欧氏距离
sortedDistIndices = distances.argsort() #排序,返回的是由小到大的序号
classCount = {}
for i in range(k): #选取
voteIlabel = labels[sortedDistIndices[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
#类别投票数目排序,选取最高得票的类别
sortedClassCount = sorted(classCount.iteritems(),
key=operator.itemgetter(1),reverse=True)
return sortedClassCount[0][0]
3.3测试分类器
分类器的错误率----分类器给出错误结果的次数除以测试执行的总数。错误率是常用的评估方法,主要用于评估分类器在某个数据集上的执行效果。
4.示例:使用k近邻算法改进约会网站的配对效果
4.1准备数据:从文本中解析数据
datingTestSet.txt,每一行包含【每年获得的飞行常客里程数,玩视频游戏所耗时间百分比,每周消费的冰淇淋公升数】,共1000行。接下来在knn.py中创建一个函数来处理输入格式问题。代码如下:
'''
@abstract: 读取文件,并整理成所需(矩阵)格式
@input: filename为要读取的文件名;num为训练数据的属性个数
'''
def file2matrix(filename,num=3):
fr = open(filename)
arrayOLines = fr.readlines()
#得到文件行数
numberOfLines = len(arrayOLines)
#创建返回的numpy矩阵
returnMat = zeros((numberOfLines,num)) #numberOfLines个长度为3的全零矩阵
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
listFromLine = line.split('\t')
returnMat[index,:] = listFromLine[0:num] #第index行
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat, classLabelVector
4.2分析数据:使用matplotlib创建散点图
直接浏览文本文件的方式并不友好,一般会采用图形化的方式直观的展现数据。
'''
@abstract:使用matplotlib绘制散点图
@input:filename文件名;i为文件的第i列作为横轴,j为文件的第j列作为纵轴
@output:散点图
'''
def draw_scatter(filename='datingTestSet.txt', i=1, j=2):
fig = plt.figure()
ax = fig.add_subplot(111)
datingDataMat,datingLabels = file2matrix(filename)
ax.scatter(datingDataMat[:,i],datingDataMat[:,j],
15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()
绘制结果如下图所示,图中点的大小及颜色受类别影响。
4.3准备数据:归一化数值
采用min-max归一化对维度进行去量纲,对应的在knn.py中增加一个autoNorm()函数。
'''
@abstract:对数据进行min-max归一化
@input:dataSet为需要归一化的数据集,矩阵格式
'''
def autoNorm(dataSet):
#numpy中的min(0)/max(0)函数相应的为求每一列的最小/大值
#min(1)/max(1)则为每一行 返回值均为数组
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))
#numpy中"/"代表的具体的特征值相除,矩阵除法的用法为linalg.solve(matA,matB)
normDataSet = normDataSet/tile(ranges,(m,1))
return normDataSet, ranges, minVals
4.4测试算法
分类器正确率是十分重要的,最简单直接的测试方法是 随机分出一部分数据来做测试。
'''
@abstract:测试算法准确率的方法
@input: hoRatio为用于测试的数据的比例
@output: 错误率(输出结果不一致的数目/总测试数目)
'''
def datingClassTest(hoRatio=0.10):
datingDataMat, datingLabels = file2matrix('datingTestSet.txt')
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio) #用于测试的样本数,前百分之十
errorCount = 0.0
for i in range(numTestVecs):
#knn是基于实例的方法,不需要训练。
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],
datingLabels[numTestVecs:m],3)
print "the classifier came back with: %d,the real anwser is: %d"\
% (classifierResult, datingLabels[i])
if (classifierResult != datingLabels[i]): errorCount += 1.0
print "the total errorRate is: %f" % (errorCount/float(numTestVecs))
注:以上为参考<<机器学习实战>>一书第二章k近邻算法,第二节【使用k近邻算法改进约会网站的配对效果】所写成。完整代码
[knn.py]已上传。