【是什么】

KNN 即 k_近邻算法(k- nearest neighbor) ,就是寻找K个邻居作为该样本的特征,近朱者赤,近墨者黑,你的邻居是什么特征,那么就认为你也具备该特征;核心公式为:

数据来源:https://github.com/apachecn/AiLearning/blob/master/data/2.KNN/datingTestSet2.txt

读取数据转换成矩阵

  1. # 提取文件中的数据 转换成矩阵
  2. def file2matric(filename):
  3. """
  4. disc:
  5. param: filename: 导入数据文本
  6. return: 数据矩阵
  7. """
  8. f = open(filename,'r',encoding= 'utf-8')
  9. # 获取文件的行数
  10. lines_list = f.readlines()
  11. num_of_lines = len(lines_list)
  12. # 创建存放标签的列表
  13. class_label_list = []
  14. # 生成对应的空矩阵 zeros(2,3) 就是生成2行3列的0矩阵
  15. returnMat = np.zeros((num_of_lines,3))
  16. # 将文本中的数据放到矩阵中
  17. for i in range(num_of_lines):
  18. lines = lines_list[i].strip().split('\t')
  19. # 将文本中的前3个数据放到矩阵中
  20. returnMat[i,:] = lines[0:3]
  21. # 将标签存到列表中
  22. class_label_list.append(int(lines[-1]))
  23.  
  24. # print(returnMat)
  25. return returnMat, class_label_list

利用 matplotlib 绘制散点图

  1. def DrawScatter(dataMat,label_list):
  2. # 导入中文字体,及字体大小
  3. zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=14)
  4. # 绘制绘图窗口 2行2列
  5. fig,ax = plt.subplots(2,2,figsize=(13,8))
  6. # 不同标签赋予不同颜色
  7. label_color = []
  8. for i in label_list:
  9. if i == 1:
  10. label_color.append('black')
  11. elif i == 2:
  12. label_color.append('orange')
  13. elif i == 3:
  14. label_color.append('red')
  15. # 开始绘制散点图 设定散点尺寸与透明度
  16. scatter_size = 12
  17. scatter_alpha = 0.5
  18. # ===================散点图========================
  19. ax[0][0].scatter(dataMat[:,0], dataMat[:,1],color = label_color,s = scatter_size ,alpha = scatter_alpha)
  20. ax[0][1].scatter(dataMat[:, 1], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)
  21. ax[1][0].scatter(dataMat[:, 0], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)
  22.  
  23. # 坐标轴标题
  24. title_list = ['每年获得的飞行常客里程数和玩视频游戏所消耗时间占比',
  25. '每年获得的飞行常客里程数和每周消费的冰激淋公升数',
  26. '玩视频游戏所消耗时间占比和每周消费的冰激淋公升数']
  27. x_name_list = ['每年获得的飞行常客里程数','玩视频游戏所消耗时间占比','每周消费的冰激淋公升数']
  28. y_name_list = ['玩视频游戏所消耗时间占比','每周消费的冰激淋公升数','每年获得的飞行常客里程数']
  29. #设置图例
  30. didntLike = mlines.Line2D([], [], color='black', marker='.',
  31. markersize=6, label='didntLike')
  32. smallDoses = mlines.Line2D([], [], color='orange', marker='.',
  33. markersize=6, label='smallDoses')
  34. largeDoses = mlines.Line2D([], [], color='red', marker='.',
  35. markersize=6, label='largeDoses')
  36.  
  37. p = 0
  38. for i in range(2):
  39. for j in range(2):
  40. if p > 2:
  41. break
  42. # 设置坐标轴名称和标题
  43. plt.setp(ax[i][j].set_title(u'%s'%(title_list[p]),FontProperties = zhfont),size=9, weight='bold', color='red')
  44. plt.setp(ax[i][j].set_xlabel(u'%s'%(x_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')
  45. plt.setp(ax[i][j].set_ylabel(u'%s'%(y_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')
  46. p+=1
  47. # 添加图例
  48. ax[0][0].legend(handles=[didntLike, smallDoses, largeDoses])
  49. ax[0][1].legend(handles=[didntLike, smallDoses, largeDoses])
  50. ax[1][0].legend(handles=[didntLike, smallDoses, largeDoses])
  51.  
  52. plt.show()

对数据进行归一化处理

由于不同数据的范围波动不同,在权重一样的情况下,需要进行归一化,即将数据转换成0-1之间

  1. # 对矩阵进行归一化处理
  2. def dataNorm(dataMat):
  3. """
  4. :param dataMat:
  5. :return: 归一化后的数据集
  6. 归一化公式: Y = (X - Xmin)/(Xmax - Xmin)
  7. """
  8. # max(0) min(0) 求出每列的最大值和最小值
  9. d_min = dataMat.min(0)
  10. d_max = dataMat.max(0)
  11. # 计算极差
  12. d_ranges = d_max - d_min
  13. # 创建输出矩阵
  14. normDataSet = np.zeros(np.shape(dataMat))
  15. print(normDataSet)
  16. # 获得矩阵行数 .shape 获取矩阵的大小 3x3
  17. m = dataMat.shape[0]
  18. # 计算 (X - Xmin) 这部分 首先要创建Xmin矩阵 将d_min扩展到m行
  19. # 需要使用np.tile 函数进行扩展 将d_min扩展成m行1列 变成m x 3 矩阵
  20. normDataSet = dataMat - np.tile(d_min,(m,1))
  21. print(normDataSet)
  22. # 计算Y
  23. normDataSet = normDataSet / np.tile(d_ranges,(m,1))
  24.  
  25. print(normDataSet)
  26. return normDataSet

创建分类函数与分类器(kNN算法的实现)

(ps:每次都需要将测试数据与所有训练数据进行对比,感觉比较繁琐)

  1. def classfy_fun(test_data, train_data, labels, k):
  2. """
  3.  
  4. :param test_data: 测试集
  5. :param train_data: 训练集
  6. :param labels: 训练集标签
  7. :param k: KNN 算法参数 选择距离最小的个数
  8. :return: 分类结果
  9. """
  10. # 计算训练集的矩阵行数
  11. train_size = train_data.shape[0]
  12. # 接下来按照欧氏距离进行元素距离计算 公式
  13. # 将测试集扩充成与训练集相同行数 求差
  14. diffMat = np.tile(test_data,(train_size,1)) - train_data
  15. # 将差值矩阵的每个元素平方
  16. sq_diffMat = diffMat**2
  17. # 差值平方矩阵每行元素相加 axis = 1 是按行相加
  18. sum_diffMat = sq_diffMat.sum(axis = 1)
  19. # 对新的求和矩阵进行开方 得到距离值
  20. distances = sum_diffMat ** 0.5
  21. # 获得距离值中从小到大值的索引
  22. sorted_distant = distances.argsort()
  23. # 定义一个字典 存放标签 与 出现的数量
  24. class_count = {}
  25. for i in range(k):
  26. # 找出前k个距离值最小的对应标签
  27. temp_label = labels[sorted_distant[i]]
  28. # 将标签作为 key 存放到字典中 出现次数作为 value
  29. class_count[temp_label] = class_count.get(temp_label,0) + 1
  30. # 将字典按照value 大小进行排序
  31. sort_class_count = sorted(class_count.items(),key = operator.itemgetter(1))
  32. return sort_class_count[0][0]
  33. pass
  34. # 创建分类器函数
  35. def dating_class_test():
  36.  
  37. # 首先获取文件,将文件分成测试集和训练集
  38. dating_Mat, dating_label = file2matric('datingdata.txt')
  39. # 设置测试集的比例
  40. test_ratio = 0.1
  41. # 数据归一化
  42. normMat = dataNorm(dating_Mat)
  43. #获得矩阵的行数
  44. m = normMat.shape[0]
  45. # 计算测试集的数量
  46. numTestData = int(m * test_ratio)
  47. # 错误分类的数量
  48. error_count = 0.0
  49.  
  50. for i in range(numTestData):
  51. class_result = classfy_fun(dating_Mat[i,:], dating_Mat[numTestData:m,:],
  52. dating_label[numTestData:m],4 )
  53. print("分类结果:%s,实际分类:%s"%(class_result,dating_label[i]))
  54. if class_result != dating_label[i]:
  55. error_count += 1
  56. # print("错误识别的数量:%f" %error_count)
  57. print("正确率:%f%% \n" %((1 - error_count / numTestData)*100))

从结果看 识别率还是很低的,目前k值为4 ,可以改变k值看看正确率的变化

完整代码

  1. #!/usr/bin/python
  2. # -*- coding: UTF-8 -*-
  3. """
  4. 【KNN 实战】
  5.  
  6. """
  7. import numpy as np
  8. import matplotlib.pyplot as plt
  9. import matplotlib.lines as mlines
  10. from matplotlib.font_manager import FontProperties
  11. import operator
  12.  
  13. # 提取文件中的数据 转换成矩阵
  14. def file2matric(filename):
  15. """
  16. disc:
  17. param: filename: 导入数据文本
  18. return: 数据矩阵
  19. """
  20. f = open(filename,'r',encoding= 'utf-8')
  21. # 获取文件的行数
  22. lines_list = f.readlines()
  23. num_of_lines = len(lines_list)
  24. # 创建存放标签的列表
  25. class_label_list = []
  26. # 生成对应的空矩阵 zeros(2,3) 就是生成2行3列的0矩阵
  27. returnMat = np.zeros((num_of_lines,3))
  28. # 将文本中的数据放到矩阵中
  29. for i in range(num_of_lines):
  30. lines = lines_list[i].strip().split('\t')
  31. # 将文本中的前3个数据放到矩阵中
  32. returnMat[i,:] = lines[0:3]
  33. # 将标签存到列表中
  34. class_label_list.append(int(lines[-1]))
  35.  
  36. # print(returnMat)
  37. return returnMat, class_label_list
  38.  
  39. def DrawScatter(dataMat,label_list):
  40. # 导入中文字体,及字体大小
  41. zhfont = FontProperties(fname='C:/Windows/Fonts/simsun.ttc', size=14)
  42. # 绘制绘图窗口 2行2列
  43. fig,ax = plt.subplots(2,2,figsize=(13,8))
  44. # 不同标签赋予不同颜色
  45. label_color = []
  46. for i in label_list:
  47. if i == 1:
  48. label_color.append('black')
  49. elif i == 2:
  50. label_color.append('orange')
  51. elif i == 3:
  52. label_color.append('red')
  53. # 开始绘制散点图 设定散点尺寸与透明度
  54. scatter_size = 12
  55. scatter_alpha = 0.5
  56. # ===================散点图========================
  57. ax[0][0].scatter(dataMat[:,0], dataMat[:,1],color = label_color,s = scatter_size ,alpha = scatter_alpha)
  58. ax[0][1].scatter(dataMat[:, 1], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)
  59. ax[1][0].scatter(dataMat[:, 0], dataMat[:, 2], color=label_color, s=scatter_size , alpha=scatter_alpha)
  60.  
  61. # 坐标轴标题
  62. title_list = ['每年获得的飞行常客里程数和玩视频游戏所消耗时间占比',
  63. '每年获得的飞行常客里程数和每周消费的冰激淋公升数',
  64. '玩视频游戏所消耗时间占比和每周消费的冰激淋公升数']
  65. x_name_list = ['每年获得的飞行常客里程数','玩视频游戏所消耗时间占比','每周消费的冰激淋公升数']
  66. y_name_list = ['玩视频游戏所消耗时间占比','每周消费的冰激淋公升数','每年获得的飞行常客里程数']
  67. #设置图例
  68. didntLike = mlines.Line2D([], [], color='black', marker='.',
  69. markersize=6, label='didntLike')
  70. smallDoses = mlines.Line2D([], [], color='orange', marker='.',
  71. markersize=6, label='smallDoses')
  72. largeDoses = mlines.Line2D([], [], color='red', marker='.',
  73. markersize=6, label='largeDoses')
  74.  
  75. p = 0
  76. for i in range(2):
  77. for j in range(2):
  78. if p > 2:
  79. break
  80. # 设置坐标轴名称和标题
  81. plt.setp(ax[i][j].set_title(u'%s'%(title_list[p]),FontProperties = zhfont),size=9, weight='bold', color='red')
  82. plt.setp(ax[i][j].set_xlabel(u'%s'%(x_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')
  83. plt.setp(ax[i][j].set_ylabel(u'%s'%(y_name_list[p]),FontProperties = zhfont), size=7, weight='bold', color='black')
  84. p+=1
  85. # 添加图例
  86. ax[0][0].legend(handles=[didntLike, smallDoses, largeDoses])
  87. ax[0][1].legend(handles=[didntLike, smallDoses, largeDoses])
  88. ax[1][0].legend(handles=[didntLike, smallDoses, largeDoses])
  89. plt.savefig('.\\123.png', bbox_inches='tight')
  90. plt.show()
  91.  
  92. # 对矩阵进行归一化处理
  93. def dataNorm(dataMat):
  94. """
  95. :param dataMat:
  96. :return: 归一化后的数据集
  97. 归一化公式: Y = (X - Xmin)/(Xmax - Xmin)
  98. """
  99. # max(0) min(0) 求出每列的最大值和最小值
  100. d_min = dataMat.min(0)
  101. d_max = dataMat.max(0)
  102. # 计算极差
  103. d_ranges = d_max - d_min
  104. # 创建输出矩阵
  105. normDataSet = np.zeros(np.shape(dataMat))
  106. print(normDataSet)
  107. # 获得矩阵行数 .shape 获取矩阵的大小 3x3
  108. m = dataMat.shape[0]
  109. # 计算 (X - Xmin) 这部分 首先要创建Xmin矩阵 将d_min扩展到m行
  110. # 需要使用np.tile 函数进行扩展 将d_min扩展成m行1列 变成m x 3 矩阵
  111. normDataSet = dataMat - np.tile(d_min,(m,1))
  112. print(normDataSet)
  113. # 计算Y
  114. normDataSet = normDataSet / np.tile(d_ranges,(m,1))
  115.  
  116. print(normDataSet)
  117. return normDataSet
  118.  
  119. def classfy_fun(test_data, train_data, labels, k):
  120. """
  121.  
  122. :param test_data: 测试集
  123. :param train_data: 训练集
  124. :param labels: 训练集标签
  125. :param k: KNN 算法参数 选择距离最小的个数
  126. :return: 分类结果
  127. """
  128. # 计算训练集的矩阵行数
  129. train_size = train_data.shape[0]
  130. # 接下来按照欧氏距离进行元素距离计算 公式
  131. # 将测试集扩充成与训练集相同行数 求差
  132. diffMat = np.tile(test_data,(train_size,1)) - train_data
  133. # 将差值矩阵的每个元素平方
  134. sq_diffMat = diffMat**2
  135. # 差值平方矩阵每行元素相加 axis = 1 是按行相加
  136. sum_diffMat = sq_diffMat.sum(axis = 1)
  137. # 对新的求和矩阵进行开方 得到距离值
  138. distances = sum_diffMat ** 0.5
  139. # 获得距离值中从小到大值的索引
  140. sorted_distant = distances.argsort()
  141. # 定义一个字典 存放标签 与 出现的数量
  142. class_count = {}
  143. for i in range(k):
  144. # 找出前k个距离值最小的对应标签
  145. temp_label = labels[sorted_distant[i]]
  146. # 将标签作为 key 存放到字典中 出现次数作为 value
  147. class_count[temp_label] = class_count.get(temp_label,0) + 1
  148. # 将字典按照value 大小进行排序
  149. sort_class_count = sorted(class_count.items(),key = operator.itemgetter(1))
  150. return sort_class_count[0][0]
  151. pass
  152. # 创建分类器函数
  153. def dating_class_test():
  154.  
  155. # 首先获取文件,将文件分成测试集和训练集
  156. dating_Mat, dating_label = file2matric('datingdata.txt')
  157. # 设置测试集的比例
  158. test_ratio = 0.1
  159. # 数据归一化
  160. normMat = dataNorm(dating_Mat)
  161. #获得矩阵的行数
  162. m = normMat.shape[0]
  163. # 计算测试集的数量
  164. numTestData = int(m * test_ratio)
  165. # 错误分类的数量
  166. error_count = 0.0
  167.  
  168. for i in range(numTestData):
  169. class_result = classfy_fun(dating_Mat[i,:], dating_Mat[numTestData:m,:],
  170. dating_label[numTestData:m],4 )
  171. print("分类结果:%s,实际分类:%s"%(class_result,dating_label[i]))
  172. if class_result != dating_label[i]:
  173. error_count += 1
  174. # print("错误识别的数量:%f" %error_count)
  175. print("正确率:%f%% \n" %((1 - error_count / numTestData)*100))
  176.  
  177. def main():
  178. # reMat, label = file2matric('datingdata.txt')
  179. # DrawScatter(reMat,label )
  180. # dataNorm(reMat)
  181. # 测试分类情况
  182. dating_class_test()
  183. pass
  184.  
  185. if __name__ =='__main__':
  186. main()

机器学习实战_KNN(一)的更多相关文章

  1. 机器学习实战笔记(Python实现)-08-线性回归

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  2. 机器学习实战笔记(Python实现)-06-AdaBoost

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  3. 机器学习实战笔记(Python实现)-05-支持向量机(SVM)

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

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

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  5. 机器学习实战笔记(Python实现)-03-朴素贝叶斯

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  6. 机器学习实战笔记(Python实现)-01-K近邻算法(KNN)

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  7. 机器学习实战笔记(Python实现)-02-决策树

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  8. 机器学习实战笔记(Python实现)-00-readme

    近期学习机器学习,找到一本不错的教材<机器学习实战>.特此做这份学习笔记,以供日后翻阅. 机器学习算法分为有监督学习和无监督学习.这本书前两部分介绍的是有监督学习,第三部分介绍的是无监督学 ...

  9. 《机器学习实战》 code debug

    摘要:最近在看<机器学习实战>,在code的过程中总是会报一些小错误,所以发下debug过的地方:由于是跳着看的,所以只是其中一部分,希望之后能把这本书我遇见的全部错误都在此更正下. 内容 ...

随机推荐

  1. guava multimap介绍

    引用一篇别人的博客,理解理解 http://vipcowrie.iteye.com/blog/1517338

  2. airflow使用本地时区

    ​ 在airflow中使用的时间是utc时间,而更多时候我们希望的是使用本地时间,于是在定义airflow定时任务的时候,涉及到了时间的转换. 1.python中本地时间和utc时间的转换 查看国内可 ...

  3. Linux、Windows 和 Mac 中的换行符对比

    原文地址:Linux.Windows 和 Mac 中的换行符对比 博客地址:http://www.moonxy.com 一.前言 经常使用 Window.Linux 等不同操作系统的开发者,在处理文本 ...

  4. 19 (OC)* RunLoop

    面试题 1:讲讲RunLoop,项目中有用到吗? 2:RunLoop内部实现逻辑? 3:Runloop和线程的关系? 4:timer 与 Runloop 的关系? 5:程序中添加每3秒响应一次的NST ...

  5. 云服务器 ECS Linux 系统 MySQL 备份的导入导出

    MySQL 备份的导出 注意: 如果您使用的是帮助中心的一键环境配置,那么 MySQL 的安装目录是 /alidata/server/mysql. 如果您将 MySQL 安装到其他目录,您需要输入您 ...

  6. 自己制作一个简单的操作系统二[CherryOS]

    自己制作一个简单的操作系统二[CherryOS] 我的上一篇博客 自己制作一个简单的操作系统一[环境搭建], 详细介绍了制作所需的前期准备工作 一. 一点说明 这个操作系统只是第一步, 仅仅是开机显示 ...

  7. vue-router之路由元信息

    路由元信息?(黑人问号脸???)是不是这么官方的解释很多人都会一脸懵?那么我们说meta,是不是很多人恍然大悟,因为在项目中用到或者看到过呢? 是的,路由元信息就是我们定义路由时配置的meta字段:那 ...

  8. Spring MVC-从零开始-@RequestMapping结合@PathVariable (从URL路径中取值,作用于函数参数)

    1.可以直接在RequestMapping中value元素中使用{key}描述属性键 2.也可以在{key}中使用正则限定key的取值范围,从而限定url的变化范围 package com.jt; i ...

  9. 配置Redis(远程访问及授权设置)

    配置Redis(远程访问及授权设置) 1.将redis.conf里面的bind 127.0.0.1这一行注释掉,添加自己服务器的IP 2. 还有,找到protected-mode这行, 将改为yes. ...

  10. pikachu-数字型注入(post)#手工注入

    1, 因为是post型,所以需要抓取数据包 2, 测试结果为数字型注入 提交恒等的语句可以查询到所有的数据信息 3, 使用UNION联合查询法 判断字段数,测试为2个字段时没有报错,所以可以判断字段数 ...