(2)机器学习实战笔记:k近邻算法

写的很粗糙,以后实现了具体的算法再改进内容
———————————————————————————————————————————————
k近邻算法:
概述:
优点:
1、精度高,对异常值不敏感,无数据输入假定
 
缺点:计算复杂高,空间复杂高
适用数据范围:数值型与标称型
 
原理:存在一个样本数据集合,并且样本集中每个数据都存在标签
对于输入没有标签的新数据,把新数据的每个特征与样本集中数据对应的特征进行比较
算法提取样本集中特征最相似 的数据(最近邻)分类标签
 
always 只选择k个最相似数据中出现次数最多的分类,作为新数据的分类
 
k近邻算法的一般流程:
1、收集数据:any way
2、准备数据:距离计算所需要的数值,最好是结构化的数据格式
3、分析数据:any way
4、测试算法:计算错误率
5、使用算法:首先需要输入样本数据和结构化输出结果,然后运行k近邻算法判定输入数据分别属于哪个类,最后应用对计算出的分类执行后续处理
 
算法思路:
对未知类别属性数据集:
1、计算已知类别数据集中的点和当前点之间的距离
2、按照距离递增次序排序
3、选取与当前距离最小的k个点
4、确定前k个点所在类别的出现频率
5、返回前k个点出现频率最高的类别作为当前点的预测分类
 
分类器的测试:
错误率,用于评估分类器在某个数据集上的执行效果
 
需要了解数据的真实含义,一般会采用图形化的方式直观展示数据
 
2.2.2 分析数据:使用matplotlib创建散点图
 
可以变色:更好的辨识数据
2.2.3
准备数据:进行数值的归一化
是为了减少个体数值数字差值大对属性计算结果影响大的问题;
 
2.2.4
测试算法:作为完整程序验证分类器
 
 
 
————————————————————————————————————————————-
 
总步骤:
读取数据,进行特征值归一化
计算测试向量的数量,将两部分数据输入到原始knn分类器函数中
最后计算错误率实现结果输出。
————————————————————————————————————————————
数据集量很大,必须使用大量的存储空间
必须对数据集中每个数据计算距离值,使用时候很耗时间
无法知晓平均实例样本和典型实例样本特征
 
下面是简单实例:k近邻算法实现手写数字验证
数据集来自http://archive.ics.uci.edu/ml手写识别的数据(手写数字数据集的光学识别)
 
数据集和代码传到gitHub上去了!下载数据集点我
 
实现步骤:
1、处理图像数据,转化为向量(img2vector)
2、对数据进行提取,通过文件名提取数据向量对应的数字标签,获得一个“训练集”
3、对于“测试集”里的每一条向量,获得对应的数字标签 然后调用classify0函数使用knn算法进行向量距离的计算→通过排序获得前k个最小的结果→统计最小结果集里数字出现的概率→返回概率最高的结果作为分类答案
4、计算错误率
 
具体实现代码如下:
import numpy
import matplotlib
from os import listdir
import numpy as np
import operator

#将图片转换为向量
def img2vector(filename):
    returnVect=np.zeros((1,1024)) #生成1行1024列的全零矩阵
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0,32*i+j] = int(lineStr[j])
    return returnVect

#单条数据(测试数据),“训练”数据集,对应训练数据集的数字标签,选前k个参数
def classify0(testData,dataSet,labels,k):
    dataSetSize = dataSet.shape[0]
    diffMat = np.tile(testData,(dataSetSize ,1))-dataSet



    #使用欧氏距离公式计算距离
    sqDiffMat = diffMat**2
    sqDistances =  sqDiffMat.sum(axis = 1) #axis=1:按行计算(计算和)

    distances=sqDistances**0.5
    sortedDistIndicies = distances.argsort() #argsort()将distances中的数据从小到大排列,然后返回其对应由下标组成的list

    classCount = {}

    #选择距离最小的k个点,这里k=3
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]] #找到差值对应下标 在labels中对应的数据标签是多少
        classCount[voteIlabel]=classCount.get(voteIlabel,0) +1 #通过hash的方式统计结论标签出现的次数
    #排序
    print(classCount)
    sortedClassCount=sorted(classCount.items(),key=operator.itemgetter(1),reverse = True)
    return sortedClassCount[0][0]


def handwritingClassTest():
    hwLabels = []
    #获取目录的内容
    trainingFileList = listdir('trainingDigits')
    m_len = len(trainingFileList)
    trainingMat = np.zeros((m_len,1024))

    for i in range(m_len):
        fileNameStr=trainingFileList[i] #通过文件名获得数据 对应的数字
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)

        trainingMat[i,:] = img2vector('trainingDigits/%s' %fileNameStr)
        # print(trainingMat[i][0:32])
    # print(hwLabels)
    # print(trainingMat.size)
    testFileList = listdir('testDigits')
    errorCount =0.0

    mTest_len = len(testFileList)
    for i in range(mTest_len):
        fileNameStr = testFileList[i] #获取数据集文件名字
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0]) #找到其对应是什么数据
        vectorUnderTest = img2vector('testDigits/%s'%fileNameStr)

        classifierResult = classify0(vectorUnderTest,trainingMat,hwLabels,3)

        print("判断的数字是%d,而其真实数字是%d"%(classifierResult,classNumStr))
        if(classifierResult!=classNumStr):errorCount += 1.0

    print("判断错误的实例有%d个" % errorCount)
    print("错误率是%f" % (errorCount / float(mTest_len)))


def main():
    handwritingClassTest()


if __name__ == '__main__':
    main()

 

 

posted @ 2020-11-26 10:34  -DP-  阅读(138)  评论(0编辑  收藏  举报