机器学习实战ch02 KNN k-近邻算法代码注释

机器学习实战ch02 KNN k-近邻算法代码注释

最近在读《机器学习实战》这本书打算入门机器学习,无奈发现自己的python底子太差了,就像没学一样,所以决定将书上的代码进行一遍完全的注释,也当是学习了一下python和numpy了,希望能有是收获。

# coding=utf-8
import operator
from os import listdir

import matplotlib.pyplot as plt
from numpy import *


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


# 用于分类的输入向量inX,  训练样本集合dataSet, 标签向量labels(其元素数目与dataset的行数相同), k 是选择k个邻近的k
def classify0(inX, dataSet, labels, k):
    """分类器"""
    # 此部分使用欧式距离公式求出距离
    dataSetSize = dataSet.shape[0]  # shape() 用来求矩阵的维数
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet  # 将数据集中的每个点都与待分分类的点相减,tile(a,b)表示把a重复b次数
    sqDiffMat = diffMat ** 2  # 平方差
    sqDistance = sqDiffMat.sum(axis=1)  # 平方差的和  (axis = 1 表示沿着行的方向相加,反之是沿着列方向相加)
    distances = sqDistance ** 0.5  # 标准的距离公式

    sortedDistIndicies = distances.argsort()  # 返回从小到大排序的索引
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1  # 这句话的意思是对cassCount中的值进行+1操作,如果没有出现过就初始化为1
        # dict.get(k,d) get相当于一条if...else...语句,参数k在字典中,
        # 字典将返回dict[k]也就是k对应的value值;如果参数k不在字典中则返回参数d。

    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
    # 按照逆序进行排序, itemgetter() 用来获取对象的某一个域的值,这里面表示的是用字典(可以想象为一个二维数组),其中的第二维度的值
    # 也就是每一个'A'.'B'出现的次数作为关键字来进行排序
    return sortedClassCount[0][0]


def file2matrix(filename):
    """将数据文件转换成需要的格式,将特征与标签分离"""
    fr = open(filename)
    arrayOLines = fr.readlines()  # readlne()比readlines() 慢得多,前者是一次读取整个文件,而后者仅仅是读了一行.
    numberOfLines = len(arrayOLines)  # 获取文件行数 len() 用于返回对象的长度过着元素的个数
    returnMat = zeros((numberOfLines, 3))  # zeros() 用于创建给定类型的矩阵并将其初始化为0,此处是用来创建与文件行数相同的有三列属性的矩阵
    classLabelVector = []  # 用来存储所有可能的标签
    index = 0
    for line in arrayOLines:
        line = line.strip()  # strip()用于移除字符串头部和尾部指定的字符,默认为空格.
        listFromLine = line.split('\t')  # split()可以加上参数num表示分割几次
        returnMat[index, :] = listFromLine[0:3]  # returnMat[index, :]表示选取地第index行的所有列
        classLabelVector.append(int(listFromLine[-1]))  # 文本数据中最后一列给出的是约会对象的属性,所以这里面直接获取最后一个数据
        # 这两行的作用是将文本数据中的特征与标签分开存储,也是整个函数的用处
        index += 1
    return returnMat, classLabelVector


def autoNorm(dataSet):
    """用于将数字特征值转换成0~1区间的值"""
    minVals = dataSet.min(0)  # 参数为空表示求所有的最小值,为1每列的最小值,为2每行的最小值
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))
    m = dataSet.shape[0]
    # 使用公式 newvalue = (oldvalus-min)/(max-min)
    normDataSet = dataSet - tile(minVals, (m, 1))  # 表示行m行,每列进重复1次(若为2则会1,2,3,1,2,3这样的重复两次)
    normDataSet /= tile(ranges, (m, 1))
    return normDataSet, ranges, minVals


def datingClassTest():
    """分类器效果检测"""
    hoRatio = 0.10  # 取10%数据来检测分类器的效果
    datingDataMat, datingLabels = file2matrix('datingTestSet2.txt')
    normMat, ranges, minVal = autoNorm(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("the classifier came back  with %d, the real answer is : %d" % (classifierResult, datingLabels[i]))
        if (classifierResult != datingLabels[i]):
            errorCount += 1.0
    print("total is %f " % (errorCount / float(numTestVecs)))


def img2vector(filename):
    """将32×32像素的图片转换成1*1024的向量"""
    returnVect = zeros((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


def handWritingClassTest():
    hwLabels = []
    trainingFileList = listdir('trainingDigits')  # listdir()函数可以获取每个目录下面的所有文件的名字
    m = len(trainingFileList)
    traningMat = zeros((m, 1024))  # 需要的训练矩阵
    for i in range(m):
        fileNameStr = trainingFileList[i]  # 获取文件名
        # 下面两条语句为什么不写成一条直接使用一split('+')应该就足以使用了吧
        fileStr = fileNameStr.split('.')[0]  # 获取不带扩展的文件名字
        classNumStr = fileStr.split('_')[0]  # 获取标签
        hwLabels.append(int(classNumStr))
        traningMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)
    # 这里为什么不重新写一个函数呢????这样结构不是会更加清晰一点嘛
    testFileList = listdir('testDigits')
    errorCount = 0.0  # 个人觉得此处使用float是为了提高错误率的精度
    mTest = len(testFileList)
    testMat = zeros((m, 1024))
    for i in range(mTest):
        fileNameStr = testFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
        classifierResult = classify0(vectorUnderTest, traningMat, hwLabels, 3)
        print("the classifier came back  with %d, the real answer is : %d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr):
            errorCount += 1.0
    print("total is %f " % (errorCount / float(mTest)))


handWritingClassTest()
# datingClassTest()
# group, labels = createDataSet()
# print classify0([0, 0], group, labels, 3)
# datingDataMat, datingLabels = file2matrix("datingTestSet2.txt")
# fig = plt.figure()  # 用于新建画布
# ax = fig.add_subplot(111)  # 子图,在一张图里面画多个图,111表示将画布分成一行一列,本图放在第一个分块上
# ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2],
# 15.0 * array(datingLabels), 15.0 * array(datingLabels))
# ax.scatter(datingDataMat[:, 0], datingDataMat[:, 1])
# 绘制散点图,详细参数见 http://blog.csdn.net/qiu931110/article/details/68130199
# plt.show()
# normMat, ranges, minVal = autoNorm(datingDataMat)
# print(normMat)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值