机器学习实战-【K-近邻】

【K-近邻】


全文代码及数据

提取码:27kp

1.难点说明

np.tile()

复制

>>>b = np.array([[1,2],[3,4]])
>>>np.tile(b, 2)
array([[1, 2, 1, 2],
       [3, 4, 3, 4]])
>>> np.tile(b, (2, 1))
    array([[1, 2],
           [3, 4],
           [1, 2],
           [3, 4]])

argsort()

获取排序(有小到大)后的距离值的索引(序号)

字典(Dictionary)

dict.get() 函数

返回指定键的值,如果值不在字典中返回默认值

dict.get(key, # 字典中要查找的键
         default=None # 如果指定键的值不存在时,返回该默认值值
        )
dict.items()函数

dic.items() 将字典中的元素以列表形式显示出来

>>>dict={'A': 2, 'C': 3, 'B': 1} 
>>>dict.items()
dict_items([('A', 2), ('C', 3), ('B', 1)])

sorted()

'''对字典按照 value 进行排序'''
sortedClassCount = sorted(classCount.items(),  # classCount字典分解为元组列表
                          key=operator.itemgetter(1),  # 按照第二个元素的次序对元组进行排序
                          reverse=True)   # 是逆序

os.listdir()

用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序

os.listdir(path)

2.伪代码

对未知类别属性的数据集中每个点依次执行以下的操作

  1. 计算已知类别数据集中的点与当前点之间的距离
  2. 按照距离递增次序排序
  3. 选取与当前点距离最小的k个点
  4. 确定前k个点所在类别的出现频率
  5. 返回前k个点出现频率最高的类别作为当前点的预测分类

3.实施kNN分类算法(kNN.py

import numpy as np
import matplotlib.pyplot as plt

import operator # 导入运算模块

def createDataSet():
    group=np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
    labels=['A','A','B','B']
    return group, labels


def plotknn(group, labels):
    n = np.shape(group)[0]
    xcord1 = [];ycord1 = []
    xcord2 = [];ycord2 = []
    for i in range(n):
        if int(labels[i]=='A'):
            xcord1.append(group[i,0]);ycord1.append(group[i,1])
        else:
            xcord2.append(group[i,0]);ycord2.append(group[i,1])
    
    fig = plt.figure() # 生成一个新的图片
    ax = fig.add_subplot(111) # 创建一个或多个子图(subplot)
    ax.scatter(xcord1,ycord1,c='red', marker='s')
    ax.scatter(xcord2,ycord2, c='green')   
    plt.legend(['A','B'])  # 添加图例
    plt.show()

def classify0(inX, dataSet, labels, K):
    '''算法实现
    @ inX 测试样本数据
    @ 训练样本数据
    @ 标签
    @ K  选取的k 值
    '''
    dataSetSize = dataSet.shape[0] # 数据集的行(即数据大小)
    # 将inX复制成dataSeSize行,计算与数据集dataSet间的距离 
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    sqDiffMat = diffMat**2
    sqdistances = sqDiffMat.sum(axis=1) # 每一行相加
    distances = sqdistances**0.5  # 开根号得出距离
    #获取排序(由小到大)后的距离值的索引(序号)
    sortedDistIndicies = distances.argsort()
    
    classCount={}
    # 获取最近的K个点
    for i in range(K):
        # 获取该索引对应的样本标签
        voteIlabel = labels[sortedDistIndicies[i]]
        #累加几类标签出现的次数,构成键值对key/values并存于classCount中
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
    # 对字典中的 values 进行反序排序(由大到小)
    sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1), reverse=True)   
    # 返回第一个元素(最高频率)的标签
    return sortedClassCount[0][0]
    
if __name__=='__main__':
    group, labels = createDataSet()
    plotknn(group, labels)
    print('[0,0]的类别是:',classify0([0,0], group,labels,3))
    

在这里插入图片描述

[0,0]的类别是: B

4.示例:k-近邻算法改进约会网站的匹配效果(kNN_1.py)

import numpy as np
import matplotlib.pyplot as plt
import kNN

def file2matrix(filename):
    '''数据的读取'''
    fr = open(filename)
    arrayOLines = fr.readlines() # 读取文件的每一行,组成一个字符串列表
    numberOLines = len(arrayOLines) # 得到文件的行
    returnMat = np.zeros((numberOLines,3))  # 得到一个数组(n,3)
    classLabelVector = []
    index = 0
    for line in arrayOLines:
        line = line.strip()  #去掉字符串头尾的空格
        listFromLine = line.split('\t') #分割
         # listFromLine的前三个元素依次存入returnmat的index行的三列
        returnMat[index,:] = listFromLine[0:3]      
        classLabelVector.append(int(listFromLine[-1])) # 标签
        index += 1
    return returnMat, classLabelVector

def autoNorm(dataSet):
    '''归一化数据'''
    minVals = dataSet.min(0)
    maxVals = dataSet.max(0) # 每一列的最大值和最小值
    ranges = maxVals - minVals   
    normDataSet = np.zeros(np.shape(dataSet)) # 创建与dataSet等大小的矩阵
    m = dataSet.shape[0] # 数据的个数  
    normDataSet = dataSet - np.tile(minVals, (m,1)) # 将dataSet的每一行的对应列减去minVals中对应列的最小值
     #归一化,公式newValue=(value-minvalue)/(maxVal-minVal)
    normDataSet = normDataSet / np.tile(ranges, (m,1))
    return normDataSet, ranges, minVals
    
def plotKnn_1(datingDataMat, datingLabels):
    '''绘制图形'''
    fig=plt.figure()
    ax=fig.add_subplot(111)
    # 直接绘制
    ax.scatter(datingDataMat[:,0],datingDataMat[:,1],15.0*np.array(datingLabels),15.0*np.array(datingLabels))
    plt.show()

def datingClassTest():
    '''分类器针对约会网站的测试代码'''
    hoRatio = 0.10
    # 获取数据
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    # 归一化
    normMat, ranges, minVals = autoNorm(datingDataMat)
    m = normMat.shape[0]  # 获取数据数
    numTestVecs = int(hoRatio*m) # 测试样本数量
    
    errorCount =0.0
    for i in range(numTestVecs):
        # 利用分类函数classify0获取测试样本数据分类结果
        classifierResult = kNN.classify0(normMat[i,:], normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
        print('预测结果为',classifierResult,'实际标签为',datingLabels[i])
        if(classifierResult != datingLabels[i]):errorCount+=1.0
    
    print('误差率为:',errorCount/float(numTestVecs))

def classifyPerson():
    '''构建可手动输入系统'''
    resultList = ['不喜欢','魅力一般','极具魅力'] # 定义预测结果
    percentTats = float(input("玩视频游戏所耗时间百分比?"))
    ffMiles = float(input("每年获取的分行常客里程数?"))
    iceCream = float(input("每周消耗的冰淇淋公斤数?"))  # 输入数据
    datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')   #读取数据
    normMat,ranges,minValues=autoNorm(datingDataMat)
    
    inArr = np.array([ffMiles,percentTats,iceCream]) # 输入数据放在数组中
    
    classifierResult = kNN.classify0((inArr-minValues)/ranges, normMat, datingLabels, 3)
    
    print("对这个人的评价:",resultList[classifierResult-1])
    
if __name__=='__main__':
    
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    print(datingDataMat[0:5])
    print(datingLabels[0:5])
    plotKnn_1(datingDataMat, datingLabels)
    
    normMat, ranges, minVals = autoNorm(datingDataMat)
    print(normMat[0:20])
    
    datingClassTest()   
    
    classifyPerson()

在这里插入图片描述

玩视频游戏所耗时间百分比?10

每年获取的分行常客里程数?10000

每周消耗的冰淇淋公斤数?0.5
对这个人的评价: 魅力一般

5.示例:手写数字识别系统(kNN_2.py)

trainingDigits 中大约有2000个例子

testDigits 中大约有900个例子

import numpy as np
import os

def img2vector(filename):
    '''图像大小32*32,转为为1024向量'''
    returnVec = np.zeros((1,1024))
    fr = open(filename)
    # 读取每一行内容
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVec[0,32*i+j] = int(lineStr[j])            
    return returnVec

def handwritingClassTest():
    '''k-近邻算法识别手写数字'''
    hwLabels = []
    # 列出给定目录的文件名列表
    trainingFileList = os.listdir('digits/trainingDigits') 
    m = len(trainingFileList) #获取列表的长度   
    trainingMat = np.zeros((m,1024)) # 创建一个矩阵用来存储训练数据
       
    for i in range(m):
        fileNameStr = trainingFileList[i] # 获取当前的字符串       
        fileStr=fileNameStr.split('.')[0]  # 将字符串按照'.'分开,并将前一部分放于fileStr     
        classNumStr=int(fileStr.split('_')[0])  #将fileStr按照'_'分开,并将前一部分存于classNumStr
        
        hwLabels.append(classNumStr)    # 将每个标签值全部存入一个列表中  
        #解析目录中的每一个文件,将图像转化为向量,最后存入训练矩阵中
        trainingMat[i,:] = img2vector('digits/trainingDigits/%s' %fileNameStr)     
    
    '''对测试集进行处理'''
    testFileList = os.listdir('digits/testDigits')
    errorCount=0.0
    mTest=len(testFileList)
    for i in range(mTest):
        #获取第i行的文件名
        fileNameStr = testFileList[i]
        #将字符串按照'.'分开,并将前一部分放于fileStr
        fileStr = fileNameStr.split('.')[0]
        #将fileStr按照'_'分开,并将前一部分存于classNumStr
        classNumStr = int(fileStr.split('_')[0])
        #解析目录中的每一个文件,将图像转化为向量
        vectorUnderTest = img2vector('digits/testDigits/%s' %fileNameStr)
        
        classifierResult = kNN.classify0(vectorUnderTest,trainingMat,hwLabels,3) # 预测结果
        print('预测结果:',classifierResult,'真实结果:',classNumStr)
        if(classifierResult != classNumStr):errorCount+=1.0
        
    print("\n整个错误数: %d" %errorCount)
    print("\n整个错误率: %f" %(errorCount/float(mTest)))
        
if __name__=='__main__':
#    testVector = img2vector('digits/testDigits/0_13.txt')
    handwritingClassTest()
预测结果: 9 真实结果: 9
预测结果: 9 真实结果: 9

整个错误数: 10

整个错误率: 0.010571

6.参考

  1. 机器学习算法之kNN算法
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值