机器学习实战之kNN

本文为自己学习机器学习所记笔记,主要参考《统计学习方法》和《机器学习实战》两本书。

1.算法描述

    输入:训练数据集 T={(x1,y1),(x2,y2)...(xN,yN)},xi为实例的特征向量,yi为类别(标签)

    输出:实例x所属的类y

    (1)根据给定的距离度量,在训练集T中找出与x最近的k个点

    (2)在这k个点中根据分类决策规则(如多数表决),决定x的类别y

   模型三个要素:距离度量,k值选择,分类决策规则。

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

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

2.kNN算法实现

# 分类函数,四个参数分别为:待分类特征向量x,训练数据集,标签,用于选取最近邻居的数目
def classify(inX,dataSet,labels,k):
    dataSetSize=dataSet.shape[0] #获取样本数目
    #计算待分类特征向量x与训练集中每一个样本的距离。此处为欧式距离
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    #tile(a,(b,c)) 将a按行复制b次,按列复制c次
    sqDiffMat=diffMat**2
    sqDistances=sqDiffMat.sum(axis=1)  #按行求和
    distances=sqDistances**0.5
    distIndicies=distances.argsort() #排序 返回从小到大的索引
    classCount={} #建立一个字典,记录标签和出现的次数
    for i in range(k):
        voteILabel=labels[distIndicies[i]] #距离第i近的数据的标签
        classCount[voteILabel]=classCount.get(voteILabel,0)+1
    # 转化为元组,逆序排列
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
    return sortedClassCount[0][0] #返回出现次数最大的标签

3.实例1:kNN用于约会网站配对

(1)从文本文件解析数据

文本文件如下,每一列分别为男嘉宾每年飞行里程数,玩游戏所占时间百分比,每周消耗冰淇淋公升数,最后一列为对男嘉宾喜欢程度。


def file2matrix(filename):
    fr=open(filename)
    numberOfLines=len(fr.readlines())
    returnMat=zeros((numberOfLines,3))
    labelsVec=[]
    index=0
    fr=open(filename)
    for line in fr.readlines():
        line=line.strip()
        listFromLine=line.split('\t')
        returnMat[index,:]=listFromLine[0:3]
        labelsVec.append(int(listFromLine[-1]))
        index+=1
    fr.close()
    return returnMat,labelsVec

用两个矩阵分别保存特征向量和标签。

(2)归一化特征值

由于不同特征值相差较大,需归一化至同一范围(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)) # 对应元素相除。矩阵除法为linalg.solve(matA,matB)
    return normDataset,ranges,minVals

(3)测试:

将带标签数据一部分作为训练数据,另一部分作为测试数据,测试分类器的错误率。

# 约会网站配对结果错误率测试
def datingClassTest():
    ratio=0.5
    dataset,labelsVec=file2matrix('D:\python\code\machinelearninginaction\Ch02\datingTestSet2.txt')
    normData,ranges,minVals=autoNorm(dataset)
    m=dataset.shape[0]
    numTestVec=int(m*ratio)
    errorCount=0
    for i in range(numTestVec):
        testResult=classify(normData[i,:],normData[numTestVec:m,:],labelsVec[numTestVec:m],3)
        print('The result by classifier is:%s,the real result is:%s'%(testResult,labelsVec[i]))
        if testResult!=labelsVec[i]:
            errorCount+=1
    print('the total error rate is:%f'%(errorCount/numTestVec))
#给定一个人的具体信息,预测喜欢程度
def datingPredict():
    resultList=['not at all','in small doses','in large doses']
    percentTats=float(input('percentage of time spent on video games:'))
    ffMiles=float(input('frequent fliers miles earned per year: '))
    iceCream=float(input('liters of icecream consumed per year:'))
    inX=array([percentTats,ffMiles,iceCream])
    dataSet,labelsVec=file2matrix('D:\python\code\machinelearninginaction\Ch02\datingTestSet2.txt')
    normData,ranges,minVals=autoNorm(dataSet)
    result=classify((inX-minVals)/ranges,normData,labelsVec,3)
    print('You will probably like this person:',resultList[result-1])

4.实例2:kNN用于识别手写数字

所用数据集为32*32像素的黑白图片,已经处理为文本文件。如图

(1)将文本文件转换为测试向量。将原来32*32的图像用一个1024的数组来表示并作为特征向量

def img2vector(filename):
    returnvec=zeros(1024)
    fr=open(filename)
    for i in range(32):
        strLine=fr.readline()
        for j in range(32):
            returnvec[32*i+j]=strLine[j]
    fr.close()
    return returnvec

(2)准确率测试。

def handwritingClassTest():
    hwLabels=[]
    trainFlieList=listdir('D:\python\code\machinelearninginaction\Ch02\\trainingDigits') #获得该目录下的文件名的字符串列表形式
    m=len(trainFlieList)
    trainMat=zeros((m,1024))
    for i in range(m):
        fileNameStr=trainFlieList[i]
        fileStr=fileNameStr.split('.')[0] #以‘.’分开,去掉后缀
        classNum=int(fileStr.split('_')[0]) # 从文件名改获得数字标签
        hwLabels.append(classNum)
        trainMat[i,:]=img2vector('D:\python\code\machinelearninginaction\Ch02\\trainingDigits\%s'%fileNameStr)
    testFileList=listdir('D:\python\code\machinelearninginaction\Ch02\\testDigits')
    mTest=len(testFileList)
    errorCount=0
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]  # 以‘.’分开,去掉后缀
        classNum = int(fileStr.split('_')[0])  # 从文件名改获得数字标签
        testVev=img2vector('D:\python\code\machinelearninginaction\Ch02\\testDigits\%s'%fileNameStr)
        classifierResult=classify(testVev,trainMat,hwLabels,3)
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, classNum))
        if (classifierResult != classNum):
            errorCount += 1.0
    print('\nthe total error rate is:%f'%(errorCount/mTest))
文章所用数据集: https://github.com/pbharrin/machinelearninginaction/tree/master/Ch02

 

猜你喜欢

转载自blog.csdn.net/qq_29325189/article/details/79776139