《机器学习实战》之一:knn(python代码)

数据

  标称型和数值型

算法

  归一化处理:防止数值较大的特征对距离产生较大影响

  计算欧式距离:测试样本与训练集

  排序:选取前k个距离,统计频数(出现次数)最多的类别

 

 1 def classify0(inX, dataSet, labels, k):
 2     '''
 3 
 4     :param inX: 测试样本(arr)
 5     :param dataSet: 训练数据集(arr)
 6     :param labels: 类别(list)
 7     :param k:(int)
 8     :return: 类别
 9     '''
10     #计算距离
11     dataSetSize = dataSet.shape[0]  # 样本数量
12     diffMat = tile(inX, (dataSetSize, 1)) - dataSet #tile(inX{数组},(dataSetSize{倍数},1{竖向})):将数组(inX)竖向(1)复制dataSetSize倍
13     sqDiffMat = diffMat ** 2                        #先求平方
14     sqDistances = sqDiffMat.sum(axis=1)             #再求平方和
15     distances = sqDistances ** 0.5                  #开根号,欧式距离
16     sortedDistIndicies = distances.argsort()  #距离从小到大排序的索引
17     classCount = {}
18     for i in range(k):
19         voteIlabel = labels[sortedDistIndicies[i]]  #用索引得到相应的类别
20         classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
21     return max(classCount, key=lambda k: classCount[k])  # 返回频数最大的类别
kNN

ps:

  需要先  from numpy import *

  训练集(dataSet)可先归一化处理

  arr值numpy的数组(array)类型

 

例子:

约会网站的配对

header:每年获得的飞行常客里程数  玩视频游戏所耗时间百分比  每周消费的冰激凌数  评价(类别)

 

 

from numpy import *
import re

#从文件导入数据
def file2array(filename):
    '''
    :param filename: 文件名
    :return: 数据集(arr)、类别(list)
    '''
    label={
        'didntLike':0,
        'smallDoses':1,
        'largeDoses':2
    }
    with open(filename) as fr:
        lines =fr.readlines()
    tempLine =re.split('\\s+',lines[0].strip())         #'\\s+'表示tab或多个空格  #strip()除去换行符
    returnArr = zeros((len(lines),len(tempLine)-1))     #初始化数组(存放数据集)
    classLabelVector = []                               #存放类别
    for index,line in enumerate(lines):
        listFromLine = re.split('\\s+',line.strip())    #空格或tab都行
        returnArr[index,:] = listFromLine[0:-1]
        classLabelVector.append(label[listFromLine[-1]])
    return returnArr,classLabelVector

#数据归一化
def Norm(dataSet):
    minVals = dataSet.min(0)    #0:列(特征)的最小值;1:行(样本)的最小值
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(dataSet.shape)
    m = dataSet.shape[0]
    normDataSet = dataSet - tile(minVals, (m,1))
    normDataSet /= tile(ranges, (m,1))   #element wise divide
    return normDataSet, ranges, minVals

#约会网站配对例子
def datingClassTest():
    hoRatio = 0.80      #80%作为测试集,20%为训练集
    datingDataMat,datingLabels = file2array('..\data\Ch02\datingTestSet.txt')   #加载数据
    normMat, ranges, minVals = Norm(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("预测类别: %d, 真实类别: %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]): errorCount += 1.0     #统计预测错误的次数
    print ("平均错误率是: %f" % (errorCount/float(numTestVecs)))
    print("总测试数目:",numTestVecs,"总错误数目:",errorCount)

#kNN分类器
def classify0(inX, dataSet, labels, k):
    '''

    :param inX: 测试样本(arr)
    :param dataSet: 训练数据集(arr)
    :param labels: 类别(list)
    :param k:(int)
    :return: 类别
    '''
    #计算距离
    dataSetSize = dataSet.shape[0]  # 样本数量
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet #tile(inX{数组},(dataSetSize{倍数},1{竖向})):将数组(inX)竖向(1)复制dataSetSize倍
    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
    return max(classCount, key=lambda k: classCount[k])  # 返回频数最大的类别

if __name__ =='__main__':
    datingClassTest()
View Code

 

 

手写数字图象识别

数据:转成txt格式的32*32图象

 

 1 from numpy import *
 2 from os import listdir
 3 
 4 def loadData(dirname):
 5     listData =listdir(dirname)
 6     #把32*32文本文件读为1*1024
 7     def file2arr(filename):
 8         with open(filename) as f:
 9             vec =f.read()
10         return list(vec.replace('\n',''))
11     sizeData =len(listData)         #文件的数量
12     cLabel=zeros(sizeData,dtype='int16')          #文件类别
13     arrTrain =zeros((sizeData,1024),dtype='int16')  #训练样本数组
14     for i,j in enumerate(listData):
15         cLabel[i] =int(j[0]) #每个文件对应的类别
16         arrTrain[i,:] =file2arr(dirname + '\\' +j)
17     return cLabel,arrTrain
18 
19 if __name__ =='__main__':
20     from knn import classify0
21     fTrain = r'..\data\Ch02\digits\trainingDigits'
22     fTest = r'..\data\Ch02\digits\testDigits'
23     cLabel,arrTrain =loadData(fTrain)
24     cLabelTest,arrTest =loadData(fTest)
25     err=0
26     for j,i in enumerate(arrTest):
27         label =classify0(i,arrTrain,cLabel,3)
28         if cLabelTest[j] !=label:err+=1
29     print('错误率:',err/len(cLabelTest))
30 
31     #sklearn库knn对比
32     from sklearn.neighbors import KNeighborsClassifier as knn
33     model =knn(n_neighbors=3,n_jobs=4,algorithm='auto')
34     model.fit(arrTrain,cLabel)
35     cLabelPredict =model.predict(arrTest)
36     print('错误率',sum(cLabelPredict!=cLabelTest)/len(cLabelTest))
手写数字识别

 

代码+数据集放在https://github.com/vvlj/ml

直观理解https://cuijiahua.com/blog/2017/11/ml_1_knn.html

 

 

  

posted @ 2019-03-12 22:29  vlj  阅读(931)  评论(0编辑  收藏  举报