利用Python实现kNN算法的代码


Posted in Python onAugust 16, 2019

邻近算法(k-NearestNeighbor) 是机器学习中的一种分类(classification)算法,也是机器学习中最简单的算法之一了。虽然很简单,但在解决特定问题时却能发挥很好的效果。因此,学习kNN算法是机器学习入门的一个很好的途径。

kNN算法的思想非常的朴素,它选取k个离测试点最近的样本点,输出在这k个样本点中数量最多的标签(label)。我们假设每一个样本有m个特征值(property),则一个样本的可以用一个m维向量表示: X =( x1,x2,... , xm ),  同样地,测试点的特征值也可表示成:Y =( y1,y2,... , ym )。那我们怎么定义这两者之间的“距离”呢?

在二维空间中,有:d2 = ( x1 - y1 )2 + ( x2 - y2 )2 ,  在三维空间中,两点的距离被定义为:d2 = ( x1 - y1 )2 + ( x2 - y2 )2  + ( x3 - y3 )2 。我们可以据此推广到m维空间中,定义m维空间的距离:d2 = ( x1 - y1 )2 + ( x2 - y2 )2  + ...... + ( xm - ym )2 。要实现kNN算法,我们只需要计算出每一个样本点与测试点的距离,选取距离最近的k个样本,获取他们的标签(label) ,然后找出k个样本中数量最多的标签,返回该标签。

在开始实现算法之前,我们要考虑一个问题,不同特征的特征值范围可能有很大的差别,例如,我们要分辨一个人的性别,一个女生的身高是1.70m,体重是60kg,一个男生的身高是1.80m,体重是70kg,而一个未知性别的人的身高是1.81m, 体重是64kg,这个人与女生数据点的“距离”的平方 d2 = ( 1.70 - 1.81 )2 + ( 60 - 64 )2 = 0.0121 + 16.0 = 16.0121,而与男生数据点的“距离”的平方d2 = ( 1.80 - 1.81 )2 + ( 70 - 64 )2 = 0.0001 + 36.0 = 36.0001 。可见,在这种情况下,身高差的平方相对于体重差的平方基本可以忽略不计,但是身高对于辨别性别来说是十分重要的。为了解决这个问题,就需要将数据标准化(normalize),把每一个特征值除以该特征的范围,保证标准化后每一个特征值都在0~1之间。我们写一个normData函数来执行标准化数据集的工作:

def normData(dataSet):
  maxVals = dataSet.max(axis=0)
  minVals = dataSet.min(axis=0)
  ranges = maxVals - minVals
  retData = (dataSet - minVals) / ranges
  return retData, ranges, minVals

 然后开始实现kNN算法:

def kNN(dataSet, labels, testData, k):
  distSquareMat = (dataSet - testData) ** 2 # 计算差值的平方
  distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和
  distances = distSquareSums ** 0.5 # 开根号,得出每个样本到测试点的距离
  sortedIndices = distances.argsort() # 排序,得到排序后的下标
  indices = sortedIndices[:k] # 取最小的k个
  labelCount = {} # 存储每个label的出现次数
  for i in indices:
    label = labels[i]
    labelCount[label] = labelCount.get(label, 0) + 1 # 次数加一
  sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) 
  # 对label出现的次数从大到小进行排序
  return sortedCount[0][0] # 返回出现次数最大的label

注意,在testData作为参数传入kNN函数之前,需要经过标准化。

我们用几个小数据验证一下kNN函数是否能正常工作:

if __name__ == "__main__":
  dataSet = np.array([[2, 3], [6, 8]])
  normDataSet, ranges, minVals = normData(dataSet)
  labels = ['a', 'b']
  testData = np.array([3.9, 5.5])
  normTestData = (testData - minVals) / ranges
  result = kNN(normDataSet, labels, normTestData, 1)
  print(result)

结果输出 a ,与预期结果一致。

完整代码:

import numpy as np
from math import sqrt
import operator as opt

def normData(dataSet):
  maxVals = dataSet.max(axis=0)
  minVals = dataSet.min(axis=0)
  ranges = maxVals - minVals
  retData = (dataSet - minVals) / ranges
  return retData, ranges, minVals


def kNN(dataSet, labels, testData, k):
  distSquareMat = (dataSet - testData) ** 2 # 计算差值的平方
  distSquareSums = distSquareMat.sum(axis=1) # 求每一行的差值平方和
  distances = distSquareSums ** 0.5 # 开根号,得出每个样本到测试点的距离
  sortedIndices = distances.argsort() # 排序,得到排序后的下标
  indices = sortedIndices[:k] # 取最小的k个
  labelCount = {} # 存储每个label的出现次数
  for i in indices:
    label = labels[i]
    labelCount[label] = labelCount.get(label, 0) + 1 # 次数加一
  sortedCount = sorted(labelCount.items(), key=opt.itemgetter(1), reverse=True) # 对label出现的次数从大到小进行排序
  return sortedCount[0][0] # 返回出现次数最大的label



if __name__ == "__main__":
  dataSet = np.array([[2, 3], [6, 8]])
  normDataSet, ranges, minVals = normData(dataSet)
  labels = ['a', 'b']
  testData = np.array([3.9, 5.5])
  normTestData = (testData - minVals) / ranges
  result = kNN(normDataSet, labels, normTestData, 1)
  print(result)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python实现获取序列中最小的几个元素
Sep 25 Python
Python字符串特性及常用字符串方法的简单笔记
Jan 04 Python
python的else子句使用指南
Feb 27 Python
Python使用Paramiko模块编写脚本进行远程服务器操作
May 05 Python
浅谈五大Python Web框架
Mar 20 Python
Python django框架开发发布会签到系统(web开发)
Feb 12 Python
python中逻辑与或(and、or)和按位与或异或(&、|、^)区别
Aug 05 Python
selenium切换标签页解决get超时问题的完整代码
Aug 30 Python
详解用python -m http.server搭一个简易的本地局域网
Sep 24 Python
如何用python实现一个HTTP连接池
Jan 14 Python
Python实现归一化算法详情
Mar 18 Python
Python中使用Opencv开发停车位计数器功能
Apr 04 Python
python实现kNN算法识别手写体数字的示例代码
Aug 16 #Python
python爬虫 爬取超清壁纸代码实例
Aug 16 #Python
Python PO设计模式的具体使用
Aug 16 #Python
python使用sessions模拟登录淘宝的方式
Aug 16 #Python
Django错误:TypeError at / 'bool' object is not callable解决
Aug 16 #Python
Python facenet进行人脸识别测试过程解析
Aug 16 #Python
Python Web框架之Django框架Model基础详解
Aug 16 #Python
You might like
PHP 文件上传源码分析(RFC1867)
2009/10/30 PHP
php5 apache 2.2 webservice 创建与配置(java)
2011/01/27 PHP
php实现批量下载百度云盘文件例子分享
2014/04/10 PHP
jqGrid随窗口大小变化自适应大小的示例代码
2013/12/28 Javascript
jquery数组封装使用方法分享(jquery数组遍历)
2014/03/25 Javascript
js的延迟执行问题分析
2014/06/23 Javascript
基于JS代码实现实时显示系统时间
2016/06/16 Javascript
Vue.js路由组件vue-router使用方法详解
2016/12/02 Javascript
AngularJS实现页面跳转后自动弹出对话框实例代码
2017/08/02 Javascript
JavaScript设计模式之装饰者模式定义与应用示例
2018/07/25 Javascript
Angular6封装http请求的步骤详解
2018/08/13 Javascript
对angular4子路由&辅助路由详解
2018/10/09 Javascript
jsonp跨域获取百度联想词的方法分析
2019/05/13 Javascript
vue+element加入签名效果(移动端可用)
2019/06/17 Javascript
如何给element添加一个抽屉组件的方法步骤
2019/07/14 Javascript
微信小程序官方动态自定义底部tabBar的例子
2019/09/04 Javascript
[01:37]DOTA2超级联赛专访ChuaN 传奇般的电竞之路
2013/06/19 DOTA
[10:21]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster 选手采访
2021/03/11 DOTA
Python 使用SMTP发送邮件的代码小结
2016/09/21 Python
pyqt5的QComboBox 使用模板的具体方法
2018/09/06 Python
python使用writerows写csv文件产生多余空行的处理方法
2019/08/01 Python
利用pytorch实现对CIFAR-10数据集的分类
2020/01/14 Python
快速查找Python安装路径方法
2020/02/06 Python
面向新手解析python Beautiful Soup基本用法
2020/07/11 Python
Python .py生成.pyd文件并打包.exe 的注意事项说明
2021/03/04 Python
美国著名手表网站:Timepiece
2017/11/15 全球购物
如何转换一个字符串到enum值
2014/04/12 面试题
应届生财务会计求职信
2013/11/05 职场文书
环保倡议书400字
2014/05/15 职场文书
求职教师自荐书
2014/06/19 职场文书
领导班子遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
无违反计划生育证明格式
2015/06/24 职场文书
篮球赛闭幕式主持词
2015/07/03 职场文书
运动会1000米加油稿
2015/07/21 职场文书
早恋主题班会
2015/08/14 职场文书
python基于tkinter制作无损音乐下载工具
2021/03/29 Python