《机器学习实战》——KNN算法实战篇

#-*-coding:utf-8-*-
from numpy import *
import operator
from os import listdir

"""
KNN算法的原理:
存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据
与所属分类的对应关系。输人没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,
然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最
相似的数据,这就是 k 近邻算法中k的出处 , 通常k是不大于 20 的整数。最后,选择 k个最相似数据中
出现次数最多的分类,作为新数据的分类。

 构造数据集 -> 归一化特征值 -> 分类 -> 测试错误率(调整k值) -> 投入使用
"""

#构造数据集
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

#-------------------------------------------使用k近邻算法改进约会网站的配对效果-----------------------------------------------
"""
------calssify0()------
------inX: 用于分类的输入向量
------dataSet: 输入的训练样本集
------labels: 标签向量(标签向量的元素数目==dataSet的行数)
------k: 用于选择最近邻居的数目
"""

#用KNN进行预测
def classify0(inX,dataSet,labels,k):
    # array.shape返回一个元组(行数,列数),shape[0]表示的是行数
    dataSetSize = dataSet.shape[0]

    #计算距离,使用的是欧氏距离公式
    """
    ----------------tile()--------------------
    函数格式tile(A,reps)
    A和reps都是array_like
    A的类型众多,几乎所有类型都可以:array, list, tuple, dict, matrix以及基本数据类型int, string, float以及bool类型。
    reps的类型也很多,可以是tuple,list, dict, array, int, bool.但不可以是float, string, matrix类型。
    例如:
    >>> b=[1,3,5]
    >>> tile(b,[2,3])
    array([[1, 3, 5, 1, 3, 5, 1, 3, 5],
          [1, 3, 5, 1, 3, 5, 1, 3, 5]])
    """
    diffMat = tile(inX,(dataSetSize,1)) - dataSet
    sqDiffMat = diffMat ** 2
    """
    ----------------mat.sum()--------------------
    a1=mat([[1,1],[2,3],[4,2]]);
    a2=a1.sum(axis=0);//列和,这里得到的是1*2的矩阵
    a3=a1.sum(axis=1);//行和,这里得到的是3*1的矩阵
    a4=sum(a1[1,:]);//计算第一行所有列的和,这里得到的是一个数值
    """
    sqDistances = sqDiffMat.sum(axis = 1)   #行和,这里得到的是4*1的矩阵
    distances = sqDistances ** 0.5

    #选择距离最小的k个点
    """
    ----------------array.argsort()--------------------
    argsort函数返回的是数组值从小到大的索引值
    >>> x = np.array([3, 1, 2])
    >>> np.argsort(x)
    array([1, 2, 0])
    """
    sorteDistIndicies = distances.argsort()
    #定义一个字典
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sorteDistIndicies[i]]
        """
        ----------------dict.get()--------------------
        Python 字典 get() 方法和 setdefault() 方法类似,返回指定键的值,如果键不在字典中,返回一个指定值,默认为None。
        key -- 字典中要查找的键。
        default -- 可选参数,如果指定键的值不存在时,返回该值,默认为 None。
        """
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1

    #排序
    """
    ----------------sorted()--------------------
    sorted(iterable[, cmp[, key[, reverse]]])
    sorted() 函数对所有可迭代的对象进行排序操作。
    sort 与 sorted 区别:
    sort 是应用在 list 上的方法,sorted 可以对所有可迭代的对象进行排序操作。
    list 的 sort 方法返回的是对已经存在的列表进行操作,而内建函数 sorted 方法返回的是一个
    新的 list,而不是在原来的基础上进行的操作。
    # sorted()可以利用参数reverse=True进行反向排序
    >>>list=[3,4,2,6,1]
    >>>sorted(list)
    [1, 2, 3, 4, 6]
    >>>sorted(list, reverse=True)
    [6, 4, 3, 2, 1]
    """
    """
    ----------------dict.items()--------------------
    字典(Dictionary) items() 函数以列表返回可遍历的(键, 值) 元组数组。
    返回可遍历的(键, 值) 元组数组。
    """
    """
    ----------------operator.itemgetter()--------------------
    operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号),下面看例子。
    a = [1,2,3] 
    >>> b=operator.itemgetter(1)      //定义函数b,获取对象的第1个域的值
    >>> b(a) 
    2 
    要注意,operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值。
    """
    sortedClassCount = sorted(classCount.items(),
                              key = operator.itemgetter(1),
                              reverse = True)

    #返回k个最近邻居出现频率最高的类别,作为当前inX的预测分类
    return sortedClassCount[0][0]

#将文本记录转换为Numpy的解析程序
def file2matrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()#将每一行内容作为一个元素,共同组成一个列表
    numberOfLines = len(arrayOLines)#列表长度,即列表成员个数
    returnMat = zeros((numberOfLines,3))#用0填充一个(numberOfLines*3)的矩阵
    classLabelVector = []#用于存储每条数据所对应的类别
    index = 0
    for line in arrayOLines:
        """
        ----------------str.strip()--------------------
        Python strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)。
        语法:str.strip([chars]);
        """
        line = line.strip()
        listFromLine = line.split('\t')
        returnMat[index,:] = listFromLine[0:3]
        classLabelVector.append(int(listFromLine[-1]))
        index += 1
    return returnMat, classLabelVector

# 归一化特征值
def autoNorm(dataSet):
    """
    ----------------mat.min()--------------------
    a = np.array([[1,5,3],[4,2,6]])  
    print(a.min()) #无参,所有中的最小值  
    print(a.min(0)) # axis=0; 每列的最小值 ,得到1*3的矩阵
    print(a.min(1)) # axis=1;每行的最小值 ,得到2*1的矩阵
    """
    minVals = dataSet.min(0)#得到1*3的矩阵
    maxVals = dataSet.max(0)
    ranges = maxVals - minVals
    normDataSet = zeros(shape(dataSet))#shape(矩阵),返回一个元组(行数,列数)
    m = dataSet.shape[0]#矩阵的行数
    normDataSet = dataSet - tile(minVals,(m,1))
    normDataSet = normDataSet/tile(ranges,(m,1))
    return normDataSet, ranges, minVals

'''
----------------datingClassTest()------------------
用于测试knn预测结果的错误率
首先把数据集datingDataMat分为两部分:测试集(0-numTestVecs)和训练集(numTestVecs-m)
'''
def datingClassTest():
    # hoRatio 是测试集占数据集的比例
    hoRatio = 0.1
    datingDataMat,datingLabels = file2matrix('datingData.txt')
    normMat,ranges,minVals = 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('the total error rate is: %f' % (errorCount/float(numTestVecs)))

#约会网站预测函数
"""
每年获得的飞行常客里程数     玩视频游戏所耗时间百分比   每周消费的冰激凌公升数         分类
         7-10                 7-10                    1-3             极具魅力的人
         4-6                  4-6                     4-6             魅力一般的人
         1-3                  1-3                     7-10            不喜欢
"""
def classifyPerson():
    resultList = ['in large doses','in small doses','not at all']
    """
    -----------------input()----------------------
    python2.x 用的是 raw_input()
    python3.x 用的是 input()
    """
    percentTats = float(input(\
        'percentage of time spent playing video games:'))
    ffMiles = float(input(\
        'frequent flier miles earned per years:'))
    iceCream = float(input(\
        'liters of ice cream consumed per year:'))
    datingDataMat,datingLabels = file2matrix('datingData.txt')
    normMatm,ranges,minVals = autoNorm(datingDataMat)
    inArr = array([ffMiles,percentTats,iceCream])
    classifierResult = classify0((inArr-minVals)/ranges,\
                                 normMatm,datingLabels,3)
    print('You will probably like this person:%s'\
          % resultList[classifierResult - 1])


#----------------------------------------------------使用 k-近邻算法 识别手写数字---------------------------------------------------
"""
--------------------img2vector()-------------------------
该函数创建1×1024的NumPy数组,然后打开给定的文件,循环读出文件的前32行,
并将每行的头32个字符值存储在NumPy数组中,最后返回数组
"""
def img2vector(filename):
    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

"""
--------------------handwritingClassTest()-------------------------
手写数字识别系统的测试代码
"""
def handwritingClassTest():
    hwLabels = []
    trainingFileList = listdir('digits//trainingDigits')
    m = len(trainingFileList)
    trainingMat = zeros((m,1024))
    for i in range(m):
        #该目录下的文件按照规则命名,如文件9_45.txt的分类是9,它是数字9的第45个实例
        fileNameStr = trainingFileList[i]
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i,:] = img2vector('digits//trainingDigits//%s' % 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 = classify0(vectorUnderTest,\
                                     trainingMat,hwLabels,3)
        print('the classifier came back 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)))



你可能感兴趣的:(机器学习)