机器学习 k-近邻算法

1、使用python导入数据

from numpy import *
def createDataSet():
    group=array([[1.1,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group,labels

kNN分类算法:

from numpy import *
import operator
def classify0(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0]    #shape[0]表示dataSet的行数
    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]
distances是1*4的矩阵,分别表示待分类的点与所有已知点的距离;
sortedDistIndicies是distances从小到大的索引值;
voteIlabel相当于临时变量,用来取得标签值;
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1    如果在字典classCount中找到key=voteIlabel的value,就加1,找不到的话classCount.get(voteIlabel,0)返回0然后加1
sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)  先把字典classCount变成列表,再按照第二维降序排列,返回的仍是列表

执行算法:

import kNN
from classify_kNN import *
g,l=kNN.createDataSet()
result=classify0([0,0],g,l,3)
print(result)

输出:

B


 

items():将字典中的项按照列表返回,无序:

get():返回字典对应key的value值,不存在key时返回第二个参数:

dic={'a':1,'b':2,'c':3}
print(dic.items())
print(dic.get('c','no'))
输出:
dict_items([('b', 2), ('c', 3), ('a', 1)])
3

 

shape:返回矩阵的维数;

from numpy import *
c=array([[1,1],[2,3,],[5,6]])
print(c)
print(c.shape)
print(c.shape[0])
print(c.shape[1])
输出:
[[1 1]
 [2 3]
 [5 6]]
(3, 2)
3
2

 

 operator.itemgetter():返回对象特定维的数据,结合sorted()方法使用:

import operator
students=[['刚田武',20,'gangtw'],['朱二娃',25,'zhuerw'],['咪咪two',30,'miomitwo']]
print(sorted(students,key=operator.itemgetter(1),reverse=True))
输出:
[['咪咪two', 30, 'miomitwo'], ['朱二娃', 25, 'zhuerw'], ['刚田武', 20, 'gangtw']]

 

argsort():返回数组值从小到大的索引值

 


 

归一化数值:在计算欧氏距离的过程中,数值较大的属性对结果的贡献大,如果认为不同属性权重应该相同的话,就需要将数值归一化处理。

from numpy import *
def autoNorm(dataset):
    minVals=dataset.min(0)  #取每列的最小值,返回数组
    print(minVals)
    maxVals=dataset.max(0)
    print(maxVals)
    ranges=maxVals-minVals  #ranges是每列的最大值与最小值之差组成的数组
    print(ranges)
    normDataset=zeros(shape(dataset))
    print(normDataset)
    m=dataset.shape[0]  #取dataset的行数
    normDataset=dataset-tile(minVals,(m,1))
    print(normDataset)
    normDataset=normDataset/tile(ranges,(m,1))
    print(ranges)
    return normDataset

 minVals=dataset.min(0)    #取数据集每列的最小值,返回数组

from numpy import *
dataset=array(([6,5],
             [3,1000],
             [10,300]))
print(dataset.min())    #返回所有元素中的最小值
print(dataset.min(0))   #返回每列的最小值组成的数组
print(dataset.min(1))   #返回每行的最小值组成的数组
输出:
3
[3 5]
[ 5  3 10]

 m=dataset.shape[0] #取dataset的行数

from numpy import *
dataset=array(([6,5],
             [3,1000],
             [10,300]))
print(dataset.shape)    #返回数据集的“形状”,行数和列数
print(dataset.shape[0])     #返回行数
print(dataset.shape[1])     #返回列数
输出:
(3, 2)
3
2

 


 

测试分类器

def datingClassTest():
    hoRatio=0.1
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals=autoNorm(datingDataMat)
    m=normMat.shape[0]
    numTestVecs=int(m*hoRatio)
    errorCount=0
    for i in range(numTestVecs):
        classifyerResult=classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print('classify result is %s ,the real answer is %s'%(classifyerResult,datingLabels[i]))
        if classifyerResult!=datingLabels[i]:
            errorCount+=1
    print('the total error rate is %f'%(errorCount/float(numTestVecs)))

hoRatio=0.1  测试数据占数据集的10%


 

使用:输入各参数,输出分类结果:

def classifyPerson():
    resultList=['not at all','in small doses','in largr doses']
    timeOnGames=float(input('请输入游戏时间百分比:'))
    flyMiles=float(input('请输入每年飞行里程数:'))
    iceCream=float(input('请输入每周消耗的冰淇淋升数:'))
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
    normMat,ranges,minVals=autoNorm(datingDataMat)
    person2test=array([flyMiles,timeOnGames,iceCream])
    classifierResult=classify0((person2test-minVals)/ranges,normMat,datingLabels,5)
    print('you may like thie one:',resultList[classifierResult-1])

 通过调节k值可以调整分类器的正确率。


使用k近邻算法识别手写数字

def handwritingClassTest():
    hwLabels=[]
    trainingFileList=listdir('digits/trainingDigits')
    m=len(trainingFileList)
    trainingMat=zeros((m,1024))
    for i in range(m):
        fileNameStr=trainingFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:]=img2vector('digits/trainingDigits/%s'%fileNameStr)
    testFileList=listdir('digits/testDigits')
    errorCount=0
    mTest=len(testFileList)
    for i in range(mTest):
        fileNameStr=testFileList[i]
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        vectorUnderTest=img2vector('digits/testDigits/%s'%fileNameStr)
        classifierResult=classify0(vectorUnderTest,trainingMat,hwLabels,3)
        #print('分类结果:%s,实际结果:%s'%(classifierResult,classNumStr))
        if(classifierResult!=classNumStr):
            errorCount+=1
    print('分类错误总计:',errorCount)
    print('分类错误率:',errorCount/float(mTest))

注释:

trainingMat用来存储数据集,每个待测记录都要计算与此数据集之间的距离

hwLabels用来存储trainingMat对应的标签

fileNameStr存储文件名

fileStr存储不含后缀的文件名

classNumStr存储每条记录实际标签

vectorUnderTest表示待分类记录

计算分类错误率时,使用float()将int型数据变成浮点型

 

posted @ 2018-10-21 19:25  我的下铺刚田武  阅读(310)  评论(0编辑  收藏  举报