菜鸟初学者第三周之k近邻算法 及测试

时间:20180723-20180729

Machine Learning in Action 第二章

下方为kNN算法:

from numpy import *
import operator
from os import listdir
import matplotlib.pyplot as plt

def createDataSet():  # 给定4组数据
    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):#kNN算法:4个输入参数:{(分类输入向量,inX(分类坐标)),(输入训练样本集,dataSet(createDataSet的array,已经分类过的坐标)),(标签向量(分类标签),labels),(最近邻居的数目,k)}
    dataSetSize=dataSet.shape[0] #dataSetSize是dataSet的行数  shape是用来取矩阵维度的长度的函数
    diffMat=tile(inX,(dataSetSize,1))-dataSet
    #diffMat得到了目标与训练数组的差值
    # tile函数是在numpy。lib。shape_base里的,作用是重复某个数组
    # 比如tile(A,n),功能是将数组A重复n次,构成一个新的数组
    # 前面用tile,把一行inX变成4行一模一样的
    # tile有重复的功能,dataSetSize是重复4遍,后面的1保证重复完了是4行,而不是一行里有四个一样的
    # 然后再减去dataSet,是为了求两点的距离,先要坐标相减,这个就是坐标相减
    sqDiffMat = diffMat**2  #元素平方
    sqDistances = sqDiffMat.sum(axis=1)  # axis=1是列相加,,这样得到了(x1-x2)^2+(y1-y2)^2
    distances = sqDistances**0.5  # 开方求距离
    sortedDistances = distances.argsort()  # 升序排序,将元素按照由小到大的顺序返回下标,比如([3,1,2]),它返回的就是([1,2,0]
    classCount = {}
    for i in range(k):  # 选择距离最小的k个点
        voteIlabel = labels[sortedDistances[i]]
        classCount[voteIlabel]=classCount.get(voteIlabel, 0)+1
        # get是取字典里的元素
        # 如果之前这个voteIlabel是有的,那么就返回字典里这个voteIlabel里的值
        # 如果没有就返回0(后面写的),这行代码的意思就是算离目标点距离最近的k个点的类别
        # 这个点是哪个类别哪个类别就加1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    # key=operator.itemgetter(1)的意思是按照字典里的第一个排序
    # {A:1,B:2},要按照第1个(AB是第0个),即‘1’‘2’排序。
    # reverse=True是降序排序
    return sortedClassCount[0][0]  # 返回类别最多的类别
def file2matrix  (filename):
    fr = open(filename)  # 打开文件名为filename的文件
    arrayOLines = fr.readlines()  # 按行读取文本数据,自动生成一个列表。
    # 一次读取整个文本数据,并且自动将文件内容分析成一个行的列表,比readline()快
    # 后面的img2vector就是使用的readline(),因为要逐行逐个读取,可以对比一下
    # 每个样本数据占据一行
    numberOfLines = len(arrayOLines)  # 样本数据的个数
    returnMat = zeros((numberOfLines, 3))  # 创建一个矩阵numberOfline行3列
    classLabelvector = []
    index = 0
    for line in arrayOLines:  # 循环处理文件
        # print(line)
        line = line.strip()  # 去掉回车符,pre(使上下的数据紧凑在一起),
        # 括号里面是之前不太对的理解,是去掉那个超级大的一行的列表中的回车符“\n” ,然后一行一行的处理,才得到所看到的上下的数据紧凑在一起的数据
        # 也就是说,不是一次就得到的,是迭代出来的,所显示的是最终迭代完成之后的结果print line很多
        # strip() 方法用于移除字p符串头尾指定的字符(默认为空格或换行符)或字符序列
        listFromLine = line.split('\t')  # python split()默认以空格分割成列表,split(\t)是按tab分割

        # 分成了4列数据,得到了4个列表

        returnMat[index, :] = listFromLine[0:3]  # 将数据前三列提取出来,存放到returnMat的NumPy矩阵中,也就是特征矩阵
        classLabelvector.append(int(listFromLine[-1]))  # 将不喜欢,极具魅力,一般魅力填到分类标签
        index += 1  # 继续迭代
    return returnMat, classLabelvector  # 返回样本数据和特征矩阵和分类标签
def autoNorm(dataSet):  # 归一化特征值
    # X' = ( X - Xmin) / ( Xmax - Xmin) 归一化特征值的求解
    minVals = dataSet.min(0)  # 取出数据集中每一列的最小值
    maxVals = dataSet.max(0)  # 取出数据集中每一列的最大值
    # 可以指定关键字参数axis来获得行最大(小)值或列最大(小)值
    # print(minVals)
    # axis=0 行方向最大(小)值,即获得每列的最大(小)值
    # axis=1 列方向最大(小)值,即获得每行的最大(小)值
    ranges = maxVals-minVals  # 计算差值
    normDataSet = zeros(shape(dataSet))  # 初始化一个矩阵,该矩阵和所给数据集维度相同,用于存放归一化之后的数据
    m = dataSet.shape[0]  # 取出数据集的行数
    normDataSet = dataSet - tile(minVals, (m, 1))  # 这里tile()函数创建了一个以min_value为值的m行列向量,然后计算oldValue-min_value
    normDataSet = normDataSet/tile(ranges, (m, 1))  # 特征值相除得到归一化后的数值
    return normDataSet, ranges, minVals  # 返回归一化后的数据,差值,最小值



def img2vector(filename):  # 将图像转换为向量
    returnVect = zeros((1, 1024))  # 创建1*1024的numpy数组
    fr = open(filename)  # 打开给定文件
    for i in range(32):  # 循环读出文件的前32行,并且将每行的头32个字符值存储在numpy数组中,最后返回数组
        lineStr = fr.readline()
        for j in range(32):
            returnVect[0, 32*i+j] = int(lineStr[j])
    return returnVect

def handwritingClassTest():  # 手写数字识别系统的测试代码
    hwLabels = []  # 类别标签
    trainingFileList = listdir('digits/trainingDigits')  # 获取文件夹目录
    m = len(trainingFileList)  # 获取文件夹下文件数目
    trainingMat = zeros((m, 1024))  # 定义一个m*1024的矩阵,填充为0
    for i in range(m):  #遍历目录,截取文件名,获得真正的数字标签
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i, :]=img2vector('digits/traingDigits/%s' % fileNameStr)  #将图片fileNameStr转化为向量
    testFileList =listdir('digits/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('digits/testDigits/%s' % fileNameStr)
        classifierResult = classify(vectorUnderTest, trainingMat, hwLabels, 3)
        print("the classifier came bake 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("the total error rate is: %f" % (errorCount/float(mTest)))

 测试kNN算法。

from kNN import  *
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
# group,labels= kNN.createDataSet()
# print(kNN.classify([0.5, 1], group, labels, 3))
#
datingDataMat,datingLabels=file2matrix('datingTestSet2.txt')
# print(datingDataMat)
# print(datingLabels)
#
# fig = plt.figure()
# ax = fig.add_subplot(111) #画图 看线性关系
# ax.scatter(datingDataMat[:, 0],datingDataMat[:, 1])
# plt.show()

# normMatch, ranges, minVals = autoNorm(datingDataMat)
# print(normMatch)
# print(ranges)
# print(minVals)


def datingClassTest():  # 分类器针对约会网站的测试代码
    hoRatio = 0.10  # 测试样本比率
    datingDataMat, datingLabels=file2matrix('datingTestSet2.txt')  # 取样本的特征矩阵,特征标签
    normMat, ranges, minVals = autoNorm(datingDataMat)  # 特征矩阵归一化
    m = normMat.shape[0]  # 取矩阵的行数
    numTestVecs = int(m*hoRatio)  # 测试的个数
    erroCount = 0.0  # 出错的个数
    for i in range(numTestVecs):  # 遍历测试集
        classifierResult = classify(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3)
        # 分类器(需要测试的向量,训练样本集(90%),标签集合,K)
        # {(分类输入向量,inX(分类坐标)),(输入训练样本集,dataSet(createDataSet的array,已经分类过的坐标)),(标签向量(分类标签),labels),(最近邻居的数目,k)}
        # 输出最接近的结果和原始数据进行比较
        print("the classifier came back with: %d, the real answer is: %d" % (classifierResult,datingLabels[i]))
        if (classifierResult != datingLabels[i]):
            erroCount +=1.0
    print("the total error rate is: %f" % (erroCount/float(numTestVecs)))
datingClassTest()


def classifyPerson():  # 约会网站预测函数
    resultList = ['not at tall', 'in small doses', 'in large doses']  # 输出结果列表
    percentTats = float(input("percentage of time spent playing video games?"))  # 玩视频游戏所耗用时间的百分比
    ffMiles = float(input("frequent flier miles earned per year?"))  # 每年获得的飞行常客里程数
    iceCream = float(input("liters of ice cream consumed per year?"))  # 消费冰激凌的公升数
    datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')  # 取特征矩阵和吧特征标签
    norMat, ranges, minVals = autoNorm(datingDataMat)  # 特征矩阵归一化
    inArr = np.array([ffMiles, percentTats, iceCream])  # 将输入的三个数据形成列表形式
    clasifierResult = classify((inArr - minVals)/ranges, norMat, datingLabels, 3)  # 求出最接近的类别标号
    print("You will probably like this person:", resultList[clasifierResult - 1])

classifyPerson()


testVector = img2vector('digits/testDigits/0_13.txt')
print(testVector[0, 0:31])
print(testVector[0,32:63])

数据集在网上自己下载

你可能感兴趣的:(Study,kNN)