机器学习之K近邻算法(KNN算法)

KNN算法可以说是机器学习分类中最简单的一种算法了,KNN算法的工作原理是:存在一个样本数据集,也称训练样本集,在这个样本集中每个数据都存在其对应的标签,即我们知道样本集中每一数据与所属分类的对应关系。当我们输入需要预测的数据时,我们将预测数据的每个特征与样本集中对应的特征进行比较,然后提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前K个最相似的数据,这就是KNN算法。通常来说我们的K都是不大于20的整数。最后我们选择K个最相似数据中出现次数最多的分类,作为预测数据的分类。

下面我们用python来实现KNN算法

'''
    KNN算法(k-近邻算法)实习步骤(伪代码)如下:
        对未知类别属性的数据集中的点与当前点之间的距离执行以下操作:
        1.计算已知类别数据集中的点与当前点之间的距离
        2.按照距离递增次序排序
        3.选取与当前点距离最小的k个点
        4.确定前k个点所在类别的出现频率
        5.返回前k个点出现频率最高的类别作为当前点的预测分类
        
    计算距离时我们使用欧式距离公式
'''

# inX:用于分类的向量X(即需要预测数据), dataSet:输入的训练样本集, labels:标签向量, k:用于选择最近邻居的数目
def classify0(inX, dataSet, labels, k):
    dataSetSize = dataSet.shape[0]
    diffMat = tile(inX, (dataSetSize, 1)) - dataSet   # tile()方法用于将输入的预测数据扩展至于训练样本集同样大小
    sqDiffMat = diffMat**2
    sqDistances = sqDiffMat.sum(axis=1)  # axis=1 表示按列相加 即每行的所有列加一起求和
    distance = sqDistances**0.5
    # 按照升序进行快速排序,返回的是原数组的下标。
    # 比如,x = [30, 10, 20, 40]
    # 升序排序后应该是[10,20,30,40],他们的原下标是[1,2,0,3]
    # 那么,numpy.argsort(x) = [1, 2, 0, 3]
    sortedDistIndicies = distance.argsort()  # 在这里就相当于告诉了每行数据(即每个数据点)离预测数据点是第几近
    classCount={}
    # 上面是距离的计算,,下面是选择距离最小的k个点
    # 投票过程,就是统计前k个最近的样本所属类别包含的样本个数
    for i in range(k):
        # index = sortedDistIndicies[i]是第i个最相近的样本下标
        # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')
        voteIlabel = labels[sortedDistIndicies[i]]
        # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1

    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)   # 排序
    return sortedClassCount[0][0]   # 返回第一近的数据点类别

下面我们使用KNN算法来进行手写数字的识别,当然我们对于数据进行了预处理。手写数字集来自www.manning.com/MachineLearninginAction中的CH02文件夹下的digits,zip

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


# 手写数字识别系统的测试代码
def handwritingClassTest():
    hwLabels = []
    trainingFileList = os.listdir('trainingDigits')  # 获取目录内容
    m = len(trainingFileList)
    # print(m)
    trainingMat = zeros((m, 1024))
    # 从文件名解析分类数字
    for i in range(m):
        fileNameStr = trainingFileList[i]
        # print(fileNameStr)
        fileStr = fileNameStr.split('.')[0]
        classNumStr = int(fileStr.split('_')[0])
        hwLabels.append(classNumStr)
        trainingMat[i, :] = img2vector('trainingDigits/%s' % fileNameStr)
    testFileList = os.listdir("testDigits")
    errcount = 0.0
    mTest = len(testFileList)
    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, trainingMat, hwLabels, 3)
        print("The classifier came back with: %d, the real answer is :%d" % (classifierResult, classNumStr))
        if (classifierResult != classNumStr):
            errcount += 1
    print("\nthe total number of erros is :%d" % errcount)
    print("\nthe total error rate is : %f" % (errcount/float(mTest)))

总结

  KNN算法是分类数据最简单最有效的算法,KNN算法是基于实例的学习方法,使用算法时我们必须有接近实际数据的训练样本数据。KNN算法必须保存全部数据集,如果训练数据集很大,必须使用大量的储存空间。此外,由于必须对数据集中的每个数据计算距离值,所以实际用时会非常耗时。

  KNN算法的另一个缺陷是它无法给出任何数据的基础结构信息,因此我们无法知晓平均实例样本和典型实例样本具有什么特征

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章