k近邻算法(kNN)

本博客来源于CSDN:http://blog.csdn.net/niuwei22007/article/details/49703719

本博客源代码下载地址:CSDN免费下载、GitHub下载地址 均带有详细注释和测试数据

今天学习了《机器学习实战》这本书介绍的第一个机器学习算法—k近邻算法。书中介绍它对于分类非常有效,比如书中的例子是对电影的题材进行分类。

一、算法原理

算法原理是什么?允许我不严谨的说一下:首先有一堆有标签的样本,比如有一堆各种各样的鸟(样本集),我知道各种鸟的不同外貌(特征),比如羽毛颜色有无脚蹼身体重量身体长度以及最重要的它属于哪一种鸟类别/标签);然后给我一只不是这堆鸟中的一只鸟(测试样本),让我观察了它的羽毛颜色等后,让我说出它属于哪一种鸟?我的做法是:遍历之前的一堆鸟,分别比较每一只鸟的羽毛颜色、身体重量等特征与给定鸟的相应特征,并给出这两只鸟的相似度。最终,从那一堆鸟中找出相似度最大的前k只,然后统计这k只鸟的分类,最后把分类数量最多的那只鸟的类别作为给定的类别。虽然结果不一定准确,但是是有理论支持的,那就是概率论,哈哈。

下面来看一下书上对这个算法的原理介绍:存在一个训练样本集,并且每个样本都存在标签(有监督学习)。输入没有标签的新样本数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取出与样本集中特征最相似的数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中k的出处,而且k通常不大于20。最后选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

二、如何解决问题

没接触过的同学应该能懂了吧。书中的举例是对电影的题材进行分类:爱情片or动作片。依据电影中打斗镜头和接吻镜头的数量。下面来看一下如何用kNN来解决这个问题。

要解决给定一部电影,判断其属于哪一种电影这个问题,就需要知道这个未知电影存在多少个打斗镜头和接吻镜头,如上图所示,问号位置所代表的两种镜头次数分别是多少?

下面我们来看一下图中电影的特征值,如下表:

相信看过数据以后,即使不知道未知电影(?)属于哪一种类型,但是可以通过某个计算方法计算出来。

  • 第一步:首先计算未知电影与已知电影的相似度(抽象距离--相似度越小,距离越远)。具体如何计算暂且不考虑。下面看一下相似度列表:

  • 第二步:再将相似度列表排序,选出前k个最相似的样本。此处我们假设k=3,将上表中的相似度进行排序后前3分别是:He’s Not Really into DudesBeautiful WomanCalifornia Man
  • 第三步:统计最相似样本的分类。此处很容易知道这3个样本均为爱情片。
  • 第四步:将分类最多的类别作为未知电影的分类。那么我们就得出结论,未知电影属于爱情片。

下面贴一下书上总结的k近邻算法的一般流程:

三、用python实现kNN算法之简单分类

[python] view plain copy
  1. #coding=UTF8
  2. from numpy import *
  3. import operator
  4. def createDataSet():
  5. """
  6. 函数作用:构建一组训练数据(训练样本),共4个样本
  7. 同时给出了这4个样本的标签,及labels
  8. """
  9. group = array([
  10. [1.0, 1.1],
  11. [1.0, 1.0],
  12. [0. , 0. ],
  13. [0. , 0.1]
  14. ])
  15. labels = ['A', 'A', 'B', 'B']
  16. return group, labels
  17. def classify0(inX, dataset, labels, k):
  18. """
  19. inX 是输入的测试样本,是一个[x, y]样式的
  20. dataset 是训练样本集
  21. labels 是训练样本标签
  22. k 是top k最相近的
  23. """
  24. # shape返回矩阵的[行数,列数],
  25. # 那么shape[0]获取数据集的行数,
  26. # 行数就是样本的数量
  27. dataSetSize = dataset.shape[0]
  28. """
  29. 下面的求距离过程就是按照欧氏距离的公式计算的。
  30. 即 根号(x^2+y^2)
  31. """
  32. # tile属于numpy模块下边的函数
  33. # tile(A, reps)返回一个shape=reps的矩阵,矩阵的每个元素是A
  34. # 比如 A=[0,1,2] 那么,tile(A, 2)= [0, 1, 2, 0, 1, 2]
  35. # tile(A,(2,2)) = [[0, 1, 2, 0, 1, 2],
  36. #                  [0, 1, 2, 0, 1, 2]]
  37. # tile(A,(2,1,2)) = [[[0, 1, 2, 0, 1, 2]],
  38. #                    [[0, 1, 2, 0, 1, 2]]]
  39. # 上边那个结果的分开理解就是:
  40. # 最外层是2个元素,即最外边的[]中包含2个元素,类似于[C,D],而此处的C=D,因为是复制出来的
  41. # 然后C包含1个元素,即C=[E],同理D=[E]
  42. # 最后E包含2个元素,即E=[F,G],此处F=G,因为是复制出来的
  43. # F就是A了,基础元素
  44. # 综合起来就是(2,1,2)= [C, C] = [[E], [E]] = [[[F, F]], [[F, F]]] = [[[A, A]], [[A, A]]]
  45. # 这个地方就是为了把输入的测试样本扩展为和dataset的shape一样,然后就可以直接做矩阵减法了。
  46. # 比如,dataset有4个样本,就是4*2的矩阵,输入测试样本肯定是一个了,就是1*2,为了计算输入样本与训练样本的距离
  47. # 那么,需要对这个数据进行作差。这是一次比较,因为训练样本有n个,那么就要进行n次比较;
  48. # 为了方便计算,把输入样本复制n次,然后直接与训练样本作矩阵差运算,就可以一次性比较了n个样本。
  49. # 比如inX = [0,1],dataset就用函数返回的结果,那么
  50. # tile(inX, (4,1))= [[ 0.0, 1.0],
  51. #                    [ 0.0, 1.0],
  52. #                    [ 0.0, 1.0],
  53. #                    [ 0.0, 1.0]]
  54. # 作差之后
  55. # diffMat = [[-1.0,-0.1],
  56. #            [-1.0, 0.0],
  57. #            [ 0.0, 1.0],
  58. #            [ 0.0, 0.9]]
  59. diffMat = tile(inX, (dataSetSize, 1)) - dataset
  60. # diffMat就是输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算。
  61. # diffMat是一个矩阵,矩阵**2表示对矩阵中的每个元素进行**2操作,即平方。
  62. # sqDiffMat = [[1.0, 0.01],
  63. #              [1.0, 0.0 ],
  64. #              [0.0, 1.0 ],
  65. #              [0.0, 0.81]]
  66. sqDiffMat = diffMat ** 2
  67. # axis=1表示按照横轴,sum表示累加,即按照行进行累加。
  68. # sqDistance = [[1.01],
  69. #               [1.0 ],
  70. #               [1.0 ],
  71. #               [0.81]]
  72. sqDistance = sqDiffMat.sum(axis=1)
  73. # 对平方和进行开根号
  74. distance = sqDistance ** 0.5
  75. # 按照升序进行快速排序,返回的是原数组的下标。
  76. # 比如,x = [30, 10, 20, 40]
  77. # 升序排序后应该是[10,20,30,40],他们的原下标是[1,2,0,3]
  78. # 那么,numpy.argsort(x) = [1, 2, 0, 3]
  79. sortedDistIndicies = distance.argsort()
  80. # 存放最终的分类结果及相应的结果投票数
  81. classCount = {}
  82. # 投票过程,就是统计前k个最近的样本所属类别包含的样本个数
  83. for i in range(k):
  84. # index = sortedDistIndicies[i]是第i个最相近的样本下标
  85. # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')
  86. voteIlabel = labels[sortedDistIndicies[i]]
  87. # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0
  88. # 然后将票数增1
  89. classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
  90. # 把分类结果进行排序,然后返回得票数最多的分类结果
  91. sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
  92. return sortedClassCount[0][0]
  93. if __name__== "__main__":
  94. # 导入数据
  95. dataset, labels = createDataSet()
  96. inX = [0.1, 0.1]
  97. # 简单分类
  98. className = classify0(inX, dataset, labels, 3)
  99. print 'the class of test sample is %s' %className

四、用python实现kNN算法之改进分类

[python] view plain copy
  1. #coding=UTF8
  2. from numpy import *
  3. import operator
  4. from os import listdir
  5. def classify0(inX, dataset, labels, k):
  6. """
  7. inX 是输入的测试样本,是一个[x, y]样式的
  8. dataset 是训练样本集
  9. labels 是训练样本标签
  10. k 是top k最相近的
  11. """
  12. # shape返回矩阵的[行数,列数],
  13. # 那么shape[0]获取数据集的行数,
  14. # 行数就是样本的数量
  15. dataSetSize = dataset.shape[0]
  16. """
  17. 下面的求距离过程就是按照欧氏距离的公式计算的。
  18. 即 根号(x^2+y^2)
  19. """
  20. # tile属于numpy模块下边的函数
  21. # tile(A, reps)返回一个shape=reps的矩阵,矩阵的每个元素是A
  22. # 比如 A=[0,1,2] 那么,tile(A, 2)= [0, 1, 2, 0, 1, 2]
  23. # tile(A,(2,2)) = [[0, 1, 2, 0, 1, 2],
  24. #                  [0, 1, 2, 0, 1, 2]]
  25. # tile(A,(2,1,2)) = [[[0, 1, 2, 0, 1, 2]],
  26. #                    [[0, 1, 2, 0, 1, 2]]]
  27. # 上边那个结果的分开理解就是:
  28. # 最外层是2个元素,即最外边的[]中包含2个元素,类似于[C,D],而此处的C=D,因为是复制出来的
  29. # 然后C包含1个元素,即C=[E],同理D=[E]
  30. # 最后E包含2个元素,即E=[F,G],此处F=G,因为是复制出来的
  31. # F就是A了,基础元素
  32. # 综合起来就是(2,1,2)= [C, C] = [[E], [E]] = [[[F, F]], [[F, F]]] = [[[A, A]], [[A, A]]]
  33. # 这个地方就是为了把输入的测试样本扩展为和dataset的shape一样,然后就可以直接做矩阵减法了。
  34. # 比如,dataset有4个样本,就是4*2的矩阵,输入测试样本肯定是一个了,就是1*2,为了计算输入样本与训练样本的距离
  35. # 那么,需要对这个数据进行作差。这是一次比较,因为训练样本有n个,那么就要进行n次比较;
  36. # 为了方便计算,把输入样本复制n次,然后直接与训练样本作矩阵差运算,就可以一次性比较了n个样本。
  37. # 比如inX = [0,1],dataset就用函数返回的结果,那么
  38. # tile(inX, (4,1))= [[ 0.0, 1.0],
  39. #                    [ 0.0, 1.0],
  40. #                    [ 0.0, 1.0],
  41. #                    [ 0.0, 1.0]]
  42. # 作差之后
  43. # diffMat = [[-1.0,-0.1],
  44. #            [-1.0, 0.0],
  45. #            [ 0.0, 1.0],
  46. #            [ 0.0, 0.9]]
  47. diffMat = tile(inX, (dataSetSize, 1)) - dataset
  48. # diffMat就是输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算。
  49. # diffMat是一个矩阵,矩阵**2表示对矩阵中的每个元素进行**2操作,即平方。
  50. # sqDiffMat = [[1.0, 0.01],
  51. #              [1.0, 0.0 ],
  52. #              [0.0, 1.0 ],
  53. #              [0.0, 0.81]]
  54. sqDiffMat = diffMat ** 2
  55. # axis=1表示按照横轴,sum表示累加,即按照行进行累加。
  56. # sqDistance = [[1.01],
  57. #               [1.0 ],
  58. #               [1.0 ],
  59. #               [0.81]]
  60. sqDistance = sqDiffMat.sum(axis=1)
  61. # 对平方和进行开根号
  62. distance = sqDistance ** 0.5
  63. # 按照升序进行快速排序,返回的是原数组的下标。
  64. # 比如,x = [30, 10, 20, 40]
  65. # 升序排序后应该是[10,20,30,40],他们的原下标是[1,2,0,3]
  66. # 那么,numpy.argsort(x) = [1, 2, 0, 3]
  67. sortedDistIndicies = distance.argsort()
  68. # 存放最终的分类结果及相应的结果投票数
  69. classCount = {}
  70. # 投票过程,就是统计前k个最近的样本所属类别包含的样本个数
  71. for i in range(k):
  72. # index = sortedDistIndicies[i]是第i个最相近的样本下标
  73. # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')
  74. voteIlabel = labels[sortedDistIndicies[i]]
  75. # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0
  76. # 然后将票数增1
  77. classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
  78. # 把分类结果进行排序,然后返回得票数最多的分类结果
  79. sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
  80. return sortedClassCount[0][0]
  81. def file2matrix(filename):
  82. """
  83. 从文件中读入训练数据,并存储为矩阵
  84. """
  85. fr = open(filename)
  86. numberOfLines = len(fr.readlines())         #获取 n=样本的行数
  87. returnMat = zeros((numberOfLines,3))        #创建一个2维矩阵用于存放训练样本数据,一共有n行,每一行存放3个数据
  88. classLabelVector = []                       #创建一个1维数组用于存放训练样本标签。
  89. fr = open(filename)
  90. index = 0
  91. for line in fr.readlines():
  92. # 把回车符号给去掉
  93. line = line.strip()
  94. # 把每一行数据用\t分割
  95. listFromLine = line.split('\t')
  96. # 把分割好的数据放至数据集,其中index是该样本数据的下标,就是放到第几行
  97. returnMat[index,:] = listFromLine[0:3]
  98. # 把该样本对应的标签放至标签集,顺序与样本集对应。
  99. classLabelVector.append(int(listFromLine[-1]))
  100. index += 1
  101. return returnMat,classLabelVector
  102. def autoNorm(dataSet):
  103. """
  104. 训练数据归一化
  105. """
  106. # 获取数据集中每一列的最小数值
  107. # 以createDataSet()中的数据为例,group.min(0)=[0,0]
  108. minVals = dataSet.min(0)
  109. # 获取数据集中每一列的最大数值
  110. # group.max(0)=[1, 1.1]
  111. maxVals = dataSet.max(0)
  112. # 最大值与最小的差值
  113. ranges = maxVals - minVals
  114. # 创建一个与dataSet同shape的全0矩阵,用于存放归一化后的数据
  115. normDataSet = zeros(shape(dataSet))
  116. m = dataSet.shape[0]
  117. # 把最小值扩充为与dataSet同shape,然后作差,具体tile请翻看 第三节 代码中的tile
  118. normDataSet = dataSet - tile(minVals, (m,1))
  119. # 把最大最小差值扩充为dataSet同shape,然后作商,是指对应元素进行除法运算,而不是矩阵除法。
  120. # 矩阵除法在numpy中要用linalg.solve(A,B)
  121. normDataSet = normDataSet/tile(ranges, (m,1))
  122. return normDataSet, ranges, minVals
  123. def datingClassTest():
  124. # 将数据集中10%的数据留作测试用,其余的90%用于训练
  125. hoRatio = 0.10
  126. datingDataMat,datingLabels = file2matrix('datingTestSet2.txt')       #load data setfrom file
  127. normMat, ranges, minVals = autoNorm(datingDataMat)
  128. m = normMat.shape[0]
  129. numTestVecs = int(m*hoRatio)
  130. errorCount = 0.0
  131. for i in range(numTestVecs):
  132. classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
  133. print "the classifier came back with: %d, the real answer is: %d, result is :%s" % (classifierResult, datingLabels[i],classifierResult==datingLabels[i])
  134. if (classifierResult != datingLabels[i]): errorCount += 1.0
  135. print "the total error rate is: %f" % (errorCount/float(numTestVecs))
  136. print errorCount
  137. if __name__=="__main__"
  138. datingClassTest()

        改进一:数值归一化

第三节就是按照第二节中描述实现的算法。但是这只是最简单的分类,当遇到特征值相差很大的时候,分类效果就不好了。比如,原来的dataSet中有一个这样的样本:[1, 10000]。同时输入样本仍然为第三节中测试的[0.1, 0.1]。所以很明显,当求这两个样本之间的距离的时候就出问题,由于那个10000太大,对最终的结果影响最大,其他的0.1和1可以忽略不计了。因此就用到了数值归一化。如果还有不太清楚地,百度一下。详细实现看代码,有详细注释。

        改进二:从文件中读入数据

要做一个稍微复杂一点的测试,就需要多准备点样本数据,而在第三节中,训练样本只有4个,而且是固定生成的。在新的算法里边加入了可以从文件中读取训练数据。代码有详细注释。

五、用python实现kNN算法之手写数字识别

识别手写数字,需要先把手写数字图片转换为相应的01矩阵格式,这里提供已经经过转换的数据文件。trainingDigits是2000个训练样本,testDigits是900个测试样本。

[java] view plain copy
  1. #coding=UTF8
  2. from numpy import *
  3. import operator
  4. from os import listdir
  5. def classify0(inX, dataset, labels, k):
  6. """
  7. inX 是输入的测试样本,是一个[x, y]样式的
  8. dataset 是训练样本集
  9. labels 是训练样本标签
  10. k 是top k最相近的
  11. """
  12. # shape返回矩阵的[行数,列数],
  13. # 那么shape[0]获取数据集的行数,
  14. # 行数就是样本的数量
  15. dataSetSize = dataset.shape[0]
  16. # tile属于numpy模块下边的函数
  17. # tile(A, reps)返回一个shape=reps的矩阵,矩阵的每个元素是A
  18. # 比如 A=[0,1,2] 那么,tile(A, 2)= [0, 1, 2, 0, 1, 2]
  19. # tile(A,(2,2)) = [[0, 1, 2, 0, 1, 2],
  20. #                  [0, 1, 2, 0, 1, 2]]
  21. # tile(A,(2,1,2)) = [[[0, 1, 2, 0, 1, 2]],
  22. #                    [[0, 1, 2, 0, 1, 2]]]
  23. # 上边那个结果的分开理解就是:
  24. # 最外层是2个元素,即最外边的[]中包含2个元素,类似于[C,D],而此处的C=D,因为是复制出来的
  25. # 然后C包含1个元素,即C=[E],同理D=[E]
  26. # 最后E包含2个元素,即E=[F,G],此处F=G,因为是复制出来的
  27. # F就是A了,基础元素
  28. # 综合起来就是(2,1,2)= [C, C] = [[E], [E]] = [[[F, F]], [[F, F]]] = [[[A, A]], [[A, A]]]
  29. # 这个地方就是为了把输入的测试样本扩展为和dataset的shape一样,然后就可以直接做矩阵减法了。
  30. # 比如,dataset有4个样本,就是4*2的矩阵,输入测试样本肯定是一个了,就是1*2,为了计算输入样本与训练样本的距离
  31. # 那么,需要对这个数据进行作差。这是一次比较,因为训练样本有n个,那么就要进行n次比较;
  32. # 为了方便计算,把输入样本复制n次,然后直接与训练样本作矩阵差运算,就可以一次性比较了n个样本。
  33. # 比如inX = [0,1],dataset就用函数返回的结果,那么
  34. # tile(inX, (4,1))= [[ 0.0, 1.0],
  35. #                    [ 0.0, 1.0],
  36. #                    [ 0.0, 1.0],
  37. #                    [ 0.0, 1.0]]
  38. # 作差之后
  39. # diffMat = [[-1.0,-0.1],
  40. #            [-1.0, 0.0],
  41. #            [ 0.0, 1.0],
  42. #            [ 0.0, 0.9]]
  43. diffMat = tile(inX, (dataSetSize, 1)) - dataset
  44. # diffMat就是输入样本与每个训练样本的差值,然后对其每个x和y的差值进行平方运算。
  45. # diffMat是一个矩阵,矩阵**2表示对矩阵中的每个元素进行**2操作,即平方。
  46. # sqDiffMat = [[1.0, 0.01],
  47. #              [1.0, 0.0 ],
  48. #              [0.0, 1.0 ],
  49. #              [0.0, 0.81]]
  50. sqDiffMat = diffMat ** 2
  51. # axis=1表示按照横轴,sum表示累加,即按照行进行累加。
  52. # sqDistance = [[1.01],
  53. #               [1.0 ],
  54. #               [1.0 ],
  55. #               [0.81]]
  56. sqDistance = sqDiffMat.sum(axis=1)
  57. # 对平方和进行开根号
  58. distance = sqDistance ** 0.5
  59. # 按照升序进行快速排序,返回的是原数组的下标。
  60. # 比如,x = [30, 10, 20, 40]
  61. # 升序排序后应该是[10,20,30,40],他们的原下标是[1,2,0,3]
  62. # 那么,numpy.argsort(x) = [1, 2, 0, 3]
  63. sortedDistIndicies = distance.argsort()
  64. # 存放最终的分类结果及相应的结果投票数
  65. classCount = {}
  66. # 投票过程,就是统计前k个最近的样本所属类别包含的样本个数
  67. for i in range(k):
  68. # index = sortedDistIndicies[i]是第i个最相近的样本下标
  69. # voteIlabel = labels[index]是样本index对应的分类结果('A' or 'B')
  70. voteIlabel = labels[sortedDistIndicies[i]]
  71. # classCount.get(voteIlabel, 0)返回voteIlabel的值,如果不存在,则返回0
  72. # 然后将票数增1
  73. classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1
  74. # 把分类结果进行排序,然后返回得票数最多的分类结果
  75. sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
  76. return sortedClassCount[0][0]
  77. def file2matrix(filename):
  78. """
  79. 从文件中读入训练数据,并存储为矩阵
  80. """
  81. fr = open(filename)
  82. numberOfLines = len(fr.readlines())         #获取 n=样本的行数
  83. returnMat = zeros((numberOfLines,3))        #创建一个2维矩阵用于存放训练样本数据,一共有n行,每一行存放3个数据
  84. classLabelVector = []                       #创建一个1维数组用于存放训练样本标签。
  85. fr = open(filename)
  86. index = 0
  87. for line in fr.readlines():
  88. # 把回车符号给去掉
  89. line = line.strip()
  90. # 把每一行数据用\t分割
  91. listFromLine = line.split('\t')
  92. # 把分割好的数据放至数据集,其中index是该样本数据的下标,就是放到第几行
  93. returnMat[index,:] = listFromLine[0:3]
  94. # 把该样本对应的标签放至标签集,顺序与样本集对应。
  95. classLabelVector.append(int(listFromLine[-1]))
  96. index += 1
  97. return returnMat,classLabelVector
  98. def autoNorm(dataSet):
  99. """
  100. 训练数据归一化
  101. """
  102. # 获取数据集中每一列的最小数值
  103. # 以createDataSet()中的数据为例,group.min(0)=[0,0]
  104. minVals = dataSet.min(0)
  105. # 获取数据集中每一列的最大数值
  106. # group.max(0)=[1, 1.1]
  107. maxVals = dataSet.max(0)
  108. # 最大值与最小的差值
  109. ranges = maxVals - minVals
  110. # 创建一个与dataSet同shape的全0矩阵,用于存放归一化后的数据
  111. normDataSet = zeros(shape(dataSet))
  112. m = dataSet.shape[0]
  113. # 把最小值扩充为与dataSet同shape,然后作差,具体tile请翻看 第三节 代码中的tile
  114. normDataSet = dataSet - tile(minVals, (m,1))
  115. # 把最大最小差值扩充为dataSet同shape,然后作商,是指对应元素进行除法运算,而不是矩阵除法。
  116. # 矩阵除法在numpy中要用linalg.solve(A,B)
  117. normDataSet = normDataSet/tile(ranges, (m,1))
  118. return normDataSet, ranges, minVals
  119. def img2vector(filename):
  120. """
  121. 将图片数据转换为01矩阵。
  122. 每张图片是32*32像素,也就是一共1024个字节。
  123. 因此转换的时候,每行表示一个样本,每个样本含1024个字节。
  124. """
  125. # 每个样本数据是1024=32*32个字节
  126. returnVect = zeros((1,1024))
  127. fr = open(filename)
  128. # 循环读取32行,32列。
  129. for i in range(32):
  130. lineStr = fr.readline()
  131. for j in range(32):
  132. returnVect[0,32*i+j] = int(lineStr[j])
  133. return returnVect
  134. def handwritingClassTest():
  135. hwLabels = []
  136. # 加载训练数据
  137. trainingFileList = listdir('trainingDigits')
  138. m = len(trainingFileList)
  139. trainingMat = zeros((m,1024))
  140. for i in range(m):
  141. # 从文件名中解析出当前图像的标签,也就是数字是几
  142. fileNameStr = trainingFileList[i]
  143. fileStr = fileNameStr.split('.')[0]     #take off .txt
  144. classNumStr = int(fileStr.split('_')[0])
  145. hwLabels.append(classNumStr)
  146. trainingMat[i,:] = img2vector('trainingDigits/%s' % fileNameStr)
  147. # 加载测试数据
  148. testFileList = listdir('testDigits')        #iterate through the test set
  149. errorCount = 0.0
  150. mTest = len(testFileList)
  151. for i in range(mTest):
  152. fileNameStr = testFileList[i]
  153. fileStr = fileNameStr.split('.')[0]     #take off .txt
  154. classNumStr = int(fileStr.split('_')[0])
  155. vectorUnderTest = img2vector('testDigits/%s' % fileNameStr)
  156. classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
  157. print "the classifier came back with: %d, the real answer is: %d, The predict result is: %s" % (classifierResult, classNumStr, classifierResult==classNumStr)
  158. if (classifierResult != classNumStr): errorCount += 1.0
  159. print "\nthe total number of errors is: %d / %d" %(errorCount, mTest)
  160. print "\nthe total error rate is: %f" % (errorCount/float(mTest))
  161. if __name__== "__main__":
  162. handwritingClassTest()

六、小结

引用原话:k近邻算法是分类数据最简单最有效的算法。k紧邻算法必须保存全部数据集,如果训练数据集很大,必须使用大量的存储空间。此外,由于必须对数据集中的每个数据计算距离值,实际使用时可能非常耗时。(这些是很容易理解的)

k近邻算法的另外一个缺陷是它无法给出任何数据的基础结构信息,因此我们也无法知晓平均实例样本和典型实例样本具有什么特征。(就是说k近邻算法只能是单纯的比较样本特征值之间的大小关系,给出样本之间的欧氏距离,并不能给出这些特征数据的内在含义。还是比较抽象!用一句不太恰当的描述是:k近邻算法只是知道两个样本之间的有区别,长得像不像,机械的区分样本之间的差别,没有类似于人的理解能力。)

机器学习实战笔记(Python实现)-02-k近邻算法(kNN)相关推荐

  1. 机器学习实战笔记(Python实现)-04-Logistic回归

    转自:机器学习实战笔记(Python实现)-04-Logistic回归 转自:简单多元线性回归(梯度下降算法与矩阵法) 转自:人工神经网络(从原理到代码) Step 01 感知器 梯度下降

  2. 01 K近邻算法 KNN

    01 K近邻算法 KNN k近邻算法基础 等价于 scikit-learn中的机器学习算法封装 训练数据集,测试数据集 分类准确度 超参数 考虑距离权重 更多关于距离的定义 搜索明可夫斯基距离相应的p ...

  3. 基于KD树的K近邻算法(KNN)算法

    文章目录 KNN 简介 KNN 三要素 距离度量 k值的选择 分类决策规则 KNN 实现 1,构造kd树 2,搜索最近邻 3,预测 用kd树完成最近邻搜索 K近邻算法(KNN)算法,是一种基本的分类与 ...

  4. k近邻算法(KNN)-分类算法

    k近邻算法(KNN)-分类算法 1 概念 定义:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别. k-近邻算法采用测量不同特征值之间的 ...

  5. k近邻算法 (KNN)

    k近邻算法 k近邻算法(KNN,K-NearestNeighbor)是一种基本分类和回归方法,监督学习算法,本质上是基于一种数据统计的方法: 核心思想:给定一个训练数据集,对新的输入实例,在训练数据集 ...

  6. 机器学习-分类之K近邻算法(KNN)原理及实战

    k近邻算法(KNN) 简介 KNN算法是数据挖掘分类技术中最简单的方法之一.它通过测量不同特征值之间的距离进行分类的.其基本思路为:如果一个样本在特征空间中的k个最近邻样本中的大多数属于某一个类别,则 ...

  7. 2 机器学习 K近邻算法(KNN) 学习曲线 交叉验证 手写数字识别

    机器学习 1 K-近邻算法介绍 1.1 分类问题 分类问题:根据已知样本的某些特征,判断一个未知样本属于哪种样本类别. 与回归问题相比,分类问题的输出结果是离散值,用于指定输入的样本数据属于哪个类别. ...

  8. 一文搞懂K近邻算法(KNN),附带多个实现案例

    简介:本文作者为 CSDN 博客作者董安勇,江苏泰州人,现就读于昆明理工大学电子与通信工程专业硕士,目前主要学习机器学习,深度学习以及大数据,主要使用python.Java编程语言.平时喜欢看书,打篮 ...

  9. K近邻算法(KNN)原理小结

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 目录 1. KNN算法原理 2. KNN算法三要素 3. KNN算 ...

最新文章

  1. Html编辑器kindsoft
  2. day 29 socketsetserver 模块
  3. maven book
  4. 学计算机需要多少内存,电脑内存多大才够用
  5. linux svn 自动部署,linux下svn安装和自动部署
  6. [设计模式]抽象工厂模式
  7. java学习笔记_Java学习笔记day11
  8. IOS KVO与NSNotificationCenter简单使用
  9. 创建数据库company写出语句_MySQL中最实用的SQL语句
  10. iOS 常用到的宏#define
  11. 18. OP-TEE中secur world和non-secure world的切换过程
  12. 全程pwm调光_PWM调光技术详解
  13. 傅福:我可能是杭州接受BCH付款的第一个数码商家
  14. 错误: -source 1.6 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符)
  15. 电脑数据信息安全常识
  16. k1658停运到什么时候_k1658列车到龙川一般会晚点吗因为我要转车时间只有四十分钟...
  17. 计算机毕设Python+Vue疫情期间优化旅游平台(程序+LW+部署)
  18. 【Qt】 Fractal Designer 5.1 Bug Report
  19. 《重学设计模式》PDF 出炉了 - 小傅哥,肝了50天写出18万字271页的实战编程资料...
  20. 不走寻常路的Logitech G120

热门文章

  1. 如何基于Redis Replication设计并实现Redis-replicator?
  2. spring容器加载完毕做一件事情(利用ContextRefreshedEvent事件)
  3. Bash For Loop Examples for Your Linux Shell Scripting--ref
  4. Jenkins配置基于角色的项目权限管理--转
  5. 金融风控实战—模型可解释之shap
  6. 李宏毅深度学习——逻辑回归
  7. 【大佬漫谈】数字科技驱动的信贷风险技术——乔杨
  8. 【统计学习】假设检验
  9. 【SQL】SQL(基础查询)、SQL(关联查询)
  10. 【模型调优】风控模型调优相关知识