Machine Learning in Action 之 kNN

k临近算法(kNN)采用测量不同特征值之间的距离方法进行分类,也是一种非常直观的方法。本文主要记录了使用kNN算法改进约会网站的例子。
任务一:分类算法classify0 
就是使用距离公式计算特征值之间的距离,选择最邻近的k个点,通过统计这k个点的结果来得出样本的预测值。
def classify0 (inX,dataset,labels,k) :
#shape 返回行列数,shape[0]是行数,有多少元组
datasetsize = dataset.shape[ 0 ]
#tile 复制inX,使其与dataset一样大小
diffmat = tile(inX,(datasetsize, 1 )) - dataset
#**表示乘方
sqdiffmat = diffmat ** 2
#按行将计算结果求和
sqdistances = sqdiffmat.sum(axis= 1 )
distances = sqdistances ** 0.5
#使用argsort排序,返回索引值
sortedDistIndicies = distances.argsort()
#用于计数,计算结果
classcount = {}
for i in range(k) :
voteIlabel = labels[sortedDistIndicies[i]]
classcount[voteIlabel] = classcount.get(voteIlabel, 0 )+ 1
#按照第二个元素降序排列
sortedClasscount = sorted(classcount.iteritems(),key=operator.itemgetter( 1 ),reverse= True )
#返回出现次数最多的那一个label的值
return sortedClasscount[ 0 ][ 0 ]
 
1、get()方法语法:
dict . get ( key , default = None )
key -- 字典中要查找的键。
default -- 如果指定键的值不存在时,返回该默认值值。
2、 sorted 语法:
sorted ( iterable [, cmp [, key [, reverse ]]])
参数说明:
iterable -- 可迭代对象。
cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
3、 python字典的iteritems方法作用
与items方法相比作用大致相同,只是它的返回值不是列表,而是一个迭代器。
dict iteritems()操作方法
>>> f = x.iteritems()
>>> f
<dictionary-itemiterator object at 0xb74d5e3c>
>>> type(f)
<type 'dictionary-itemiterator'>    #字典项的迭代器
>>> list(f)
[('url', ' www.iplaypy.com' ;), ('title', 'python web site')]
字典.iteritems()方法在需要迭代结果的时候使用最适合,而且它的工作效率非常的高。
4、 tile函数用法

>>> numpy.tile([ 0 , 0 ], 5 ) #在列方向上重复[0,0]5次,默认行1次   
array([ 0 0 0 0 0 0 0 0 0 0 ])  
>>> numpy.tile([ 0 , 0 ],( 1 , 1 )) #在列方向上重复[0,0]1次,行1次   
array([[ 0 0 ]])  
>>> numpy.tile([ 0 , 0 ],( 2 , 1 )) #在列方向上重复[0,0]1次,行2次   
array([[ 0 0 ],  
       [ 0 0 ]])  
>>> numpy.tile([ 0 , 0 ],( 3 , 1 ))  
array([[ 0 0 ],  
       [ 0 0 ],  
       [ 0 0 ]])  
5、 argsort函数
任务二:读入数据
注意这里书上写错了,应该读入的是datingTestSet2.txt而不是datingTestSet.txt 
def file2matrix (filename) :
fr = open(filename)
#打开文件,按行读入
arrayOLines = fr.readlines()
#获得文件行数
numberOfLines = len(arrayOLines)
#创建m行n列的零矩阵
returnMat = zeros((numberOfLines, 3 ))
classLabelVector = []
index = 0
for line in arrayOLines:
line = line.strip()
#删除行前面的空格
listFromLine = line.split( '\t' )
#根据分隔符划分
returnMat[index,:] = listFromLine[ 0 : 3 ]
#取得每一行的内容存起来
classLabelVector.append(int(listFromLine[- 1 ]))
index += 1
return returnMat,classLabelVector
 
任务三:使用Matplotlib画图
安装Matplotlib时还需要numpy, dateutil, pytz, pyparsing, six, setuptools这几个包。可以在 这里 下载到,挺全的。加入到python27\Lib\site-packages目录下。
在powershell中cd到datingTestSet2.txt所在文件夹 
输入python命令并且输入以下命令 
粘贴:
import numpy
import matplotlib
import matplotlib.pyplot as plt
import k NN reload (k NN ) datingDataMat , datingLabels = kNN . file2matrix ('dating TestSet2 .txt') fig = plt . figure () ax = fig . add_subplot ( 111 ) ax . scatter (dating DataMat [:, 1 ],dating DataMat [:, 2 ], 15.0 *numpy. array (dating Labels ), 15.0 *numpy. array (dating Labels )) plt . show ()
 
下面使用后两个特征的图片 
将scatter函数修改为:
ax .scatter (datingDataMat[:, 0 ],datingDataMat[:, 1 ], 15.0 *numpy .array (datingLabels), 15.0 *numpy .array (datingLabels))
1
使用前两个特征的图片 
任务四:归一化
免除较大数值的数据给分类带来的影响,将每一项数据归一化为0~1之间的数字。
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 ))
return normDataSet, ranges, minVals
 
任务五: 分类并检验书中所给的数据
def datingClassTest () :
#选取多少数据测试分类器
hoRatio = 0.10
#从datingTestSet2.txt中获取数据
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))
print errorCount
 
出错率为5% 
任务六:将图像转换为测试向量
任务七:测试识别手写数字
def img2vector(filename):
    returnVect = zeros((1,1024))
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')           #load the training set
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
    testFileList = listdir('testDigits')        #iterate through the test set
    errorCount = 0.0
    mTest = len(testFileList)
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]     #take off .txt
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
        print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNumStr)
        if (classifierResult != classNumStr): errorCount += 1.0
    print "\nthe total number of errors is: %d" % errorCount
    print "\nthe total error rate is: %f" % (errorCount/float(mTest))

猜你喜欢

转载自blog.csdn.net/solumin/article/details/79132248