机器学习实战第二章,kNN

来源:互联网 发布:js atan2函数 编辑:程序博客网 时间:2024/06/05 19:15
#coding=utf-8

"""

k-近邻算法

优点:精度高,对异常值不敏感,无数据输入假定。

缺点:计算复杂度高,空间复杂度高

适用数据范围:数值型和标称型

"""

from numpy import *
from os import listdir
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


def classify(inX,dataSet,labels,k):
    """
    @author:liyafei
    @parameter:inX,待测数据,k选择的k个点个数
    分类
    """
    dataSetSize=dataSet.shape[0]  #计算多少组数据,4
    diffMat=tile(inX,(dataSetSize,1))-dataSet 
    """
     diffMat=将inX 重复写 dataSetSize行1列 ,然后与dataSet相减
     [[ 0.  -0.1]
      [ 0.   0. ]
      [ 1.   1. ]
      [ 1.   0.9]]


 
    """


    sqDiffMat=diffMat**2  #数组平方,全部转化为正
     
    """
     sqDiffMat=
    [[ 0.    0.01]
     [ 0.    0.  ]
     [ 1.    1.  ]
     [ 1.    0.81]]


    """
    sqDistances=sqDiffMat.sum(axis=1)
    #sqDistances=[ 0.01  0.    2.    1.81],sqdistances每行平方相加


    distances=sqDistances**0.5  #开方
    sortedDistIndicies=distances.argsort() #对距离进行排序
    #sortedDistIndicies=[1 0 3 2]       #给每个距离相对应大小的角标,第3个元素最大
    print(sortedDistIndicies)
    #sortedDistIndicies=sorted(sortedDistIndicies)  #这个语句不能用,因为用了之后,总是选择标签前面几个固定值,类别判定总是相同。
    print(sortedDistIndicies)
    
    classCount={}
    for i in range(k):   #选取k个近邻点,kNN
        voteIlabel=labels[sortedDistIndicies[i]]
        print(voteIlabel)
        classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
    print(classCount)# {'B': 1, 'A': 2}


    sortedClassCount=sorted(classCount.items(),
                            key=operator.itemgetter(1),reverse=True)
    #按值进行排序。
    """
    >>> d['a']=3
    >>> d['b']=5
    >>> sortedClassCount=sorted(d.items(),
                            key=operator.itemgetter(1),reverse=True)
    >>> sortedClassCount
        [('b', 5), ('a', 3)]   
    >>> sortedClassCount[0][0]
        'b'
    >>> 
    """
    print(sortedClassCount[0][0])
    return sortedClassCount[0][0]
    #返回最大值对应的键,也就是类别


group,labels=createDataSet()
x=classify([1,1],group,labels,3)




def file2matrix(filename):
    #将文件数据转化为矩阵
    fr=open(filename)
    arrayOLines=fr.readlines()
    numberOfLines=len(arrayOLines) #获取文件行数


    returnMat=zeros((numberOfLines,3))#创建行为numberOfLines,列为3的0矩阵
    classLabelVector=[]     #创建一个类标签向量空列表
    index=0                 #角标为0
    for line in arrayOLines:
        #遍历文件中所有的行
        line=line.strip()
       # print(line)  #3 2 5 0   字符串类型。


        listFromLine=line.split('\t') #以\t进行分割每行数据。
        #print(listFromLine,'he') #['3', '2', '5', '0'] 转换前


        listFromLineToList=[]
        for i in range(len(listFromLine)):
            #listFromLineToList.append(int(listFromLine[i]))  #文本数据中的一行数据是字符串,将其转换为int放入到list中
            listFromLineToList.append((listFromLine[i]))
       # print(listFromLineToList,'change')  #[3, 2, 5, 0] 转换后




        returnMat[index,:]=listFromLineToList[0:3] #复制每行数据到returnMat矩阵中
        classLabelVector.append(int(listFromLine[-1]))#将每行数据的最后一个类别属性放入到类标签向量中
        index+=1
    return returnMat,classLabelVector  #返回文件对应的属性矩阵和类别标签向量。




#filename="d:point.txt"




def autoNorm(dataSet):
    """
    归一化处理,将任意特征的特征值转化为0到1区间内的值.
    数学公式:
    newValue=(oldValue-min)/(max-min)
    """
    print(dataSet)
    print(type(dataSet))
    minVals=dataSet.min(0)
    maxVals=dataSet.max(0)
    ranges=maxVals-minVals
    normDataSet=zeros(shape(dataSet))  #创建一个与dataSet形状一样的0矩阵
    m=dataSet.shape[0]        #计算dataSet中的元素个数
    normDataSet=dataSet-tile(minVals,(m,1))  #将每列的minVals组成的向量,重复写m行1列,(oldValue-min)
    normDataSet=normDataSet/tile(ranges,(m,1))#(oldValue-min)/(max-min)
    return normDataSet,ranges,minVals
"""
d:point.txt中的数据
3 2 5 0
7 5 3 1
2 3 6 0
3 4 6 1
9 8 5 1


"""
"""
mat,lab=file2matrix(filename)
import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()  #创建一个图片fig
ax=fig.add_subplot(111)  #将大图分割成1*1的图片,选取第一个
ax.scatter(mat[:,1],mat[:,2])  #选取mat的角标为1,2的列,画图。
ax.scatter(mat[:,1],mat[:,2],15.0*array(lab),15.0*array(lab))  #用彩色或其它的记号不同的类,
#plt.show()
"""




#print("归一化处理 autoNorm")
#normDataSet,ranges,minVals=autoNorm(mat)
#print(normDataSet,ranges,minVals)


def datingClassTest():  
    """
    测试分类器,根据测试集,将会计算分类器的错误率,
    """
    hoRatio=0.10  #比例,测试数据所占的比例。
    datingDataMat,datingLabels=file2matrix('d:point.txt')   #读取数据集,返回数据的矩阵形式,和类别标签的向量形式
    normMat,ranges,minVals=autoNorm(datingDataMat) #对矩阵进行归一化处理
    m=normMat.shape[0] #计算元素个数,也就是矩阵的行数
    numTestVecs=int(m*hoRatio)  #计算元素个数十分之一的数量大小
    errorCount=0.0              #分类错误个数
    for i in range(numTestVecs):
        classifierResult=classify(normMat[i,:],normMat[numTestVecs:m,:],\
                                  datingLabels[numTestVecs:m],3)   #分类,用k近邻方法进行分类。训练集为除测试集之外的数据,normMat[numTestVecs:m,:]
        print("the classifier came back with : %d,the real real answer is : %d" %(classifierResult,datingLabels[i]))
        if (classifierResult != datingLabels[i]):
            errorCount+=1.0   #计算错误个数
    print("the total error rate is :%f"%(errorCount/float(numTestVecs)))  #错误率。


#datingClassTest() 


def classifyPerson():
    """
    约会网站预测函数
    """
    resultList=['not at all','in small doses','in large dases']  #结果集,相当于类别标签
    percentTats=float(input("percentage of time spent playing video games?"))#输入花费在打电子游戏上面的时间百分比
    #需用input,input需要输入一个合法的表达式。不能用raw_input.raw_input将所有输入作为字符串
    ffMiles=float(input("frequent flier miles earned per year?"))  #输入每年旅行公里
    iceCream=float(input("liters of ice cream consumed per year?"))#每年在冰激凌上面花费的时间
    datingDataMat,datingLabels=file2matrix('d:datingTestSet2.txt')        #训练数据集
    normMat,ranges,minVals=autoNorm(datingDataMat)                     #归一化
    inArr=array([ffMiles,percentTats,iceCream])                 #将要被预测的数据封装到一个数组里
    classifierResult=classify((inArr-minVals)/ranges,normMat,datingLabels,3)  #分类
    print("you will probably like this person:",resultList[classifierResult-1])  #结果,类别标签中用1,2,3,现在转化为字符串






#classifyPerson()


def img2vector(filename):
    returnVect=zeros((1,1024))
    fr=open(filename) #打开文件,里面是32乘32的图像像素,0,1
    for i in range(32):
        lineStr=fr.readline()  #读取一行,32个0,1.
        for j in range(32):
            returnVect[0,32*i+j]=int(lineStr[j])  #将读取到的像素存储到returnVect中
    return returnVect




def hand():
    hwLabels=[]  #标签
    trainingFileList=listdir('D:/test/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('D:/test/trainingDigits/%s'% fileNameStr) #将像素存放到矩阵中


        
    testFileList=listdir('D:/test/testDigits')  #测试文件的文件名
    errorCount=0.0                #错误个数
    mTest=len(testFileList)   #测试数据个数
    for i in range(mTest):
        fileNameStr=testFileList[i]     #迭代取出每个文件名
        fileStr=fileNameStr.split('.')[0]
        classNumStr=int(fileStr.split('_')[0])
        vectorUnderTest=img2vector('D:/test/testDigits/%s'%fileNameStr)   #转化为1*1024向量
        classifierResult=classify(vectorUnderTest,trainingMat,hwLabels,3)  #用kNN方法进行分类
        print("the classifier came back with:%d,the real answer is :%d"%(classifierResult,classNumStr))
        if(classifierResult!=classNumStr):
            errorCount+=1.0
    print("the total number of errors is :%d"%errorCount)
    print(mTest)
    print("the rate is %d" % float(errorCount/mTest))
    


hand()
    
          








































    







1 0
原创粉丝点击