第二章:k-近邻算法
内容:
k-近邻分类算法
从文本文件中解析和导入数据
使用Matplotlib创建扩散图
归一化数值
2.1 k-近邻算法概述
使用测量不同特征值之间的距离方法进行分类
优点:精度高,对异常值不敏感,无数据输入假定
缺点:计算复杂度高、空间复杂度高
使用数据范围:数值型 & 标称型
工作原理:训练样本集中每个数据都存在标签。
输入没有标签的新数据之后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据的分类标签,一般只选择前k个最相似的数据,选择k个最相似数据中出现次数最多的分类标签,作为新数据的分类标签。
一般流程:
1)收集数据
2)准备数据:距离计算所需要的数值,最好是格式化的数据格式
3)分析数据
4)训练算法:此处不适用
5)测试算法:计算错误率
6)使用算法:首先需要输入样本数据和结构化的输出结构,然后运行k-近邻算法判定输入数据分别属于哪个分类,最后应用对计算出的分类执行后续的处理。
一、 准备:使用python导入数据
# 通用函数
from numpy import *
#运算符模块,排序操作时将使用
import operator
#创建数据集和标签
def createDataSet():
group = array([[1.0,1.1],
[1.0,1.0],
[0 , 0],
[0 ,0.1]
])
lables = ['A','A','B','B']
return group,lables
lables含有多少行,就说明有多少个数据,也就等于group的矩阵行数
二、 实施KNN分类算法
函数功能:使用k-近邻算法将每组数据划分到某个类中
伪代码:
对位置类别属性的数据集中的每个点依次执行以下操作:
1)计算已知类别数据集中的点与当前点的距离
2)按照距离递增次序排序
3)选取与当前点距离最小的k个点
4)确定前k个点所在类别的出现频率
5)返回前k个点出现频率最高的类别作为当前点的预测分类
# 通用函数
from numpy import *
#运算符模块,排序操作时将使用
import operator
#创建数据集和标签
def createDataSet():
group = array([[1.0,1.1],
[1.0,1.0],
[0 , 0],
[0 ,0.1]
])
lables = ['A','A','B','B']
return group,lables
###
# classify0 的四个参数:
# inX——用于分类的输入向量(未知样本) dataSet——输入的训练样本集
# lables——标签向量 k——选择最近邻居的数目
# ①标签向量与矩阵dataSet的行数相同 ②使用欧氏距离
###
def classify0(inX,dataSet,lables,k):
dataSetSize = dataSet.shape[0] # 得到数据集的行数 shape方法用来得到矩阵或数组的维数 shape[0]为行数 shape[1]为列数
# 计算距离: 相减 → 平方 → 相加 → 根号
diffMat = tile(inX,(dataSetSize,1)) - dataSet # 相减 tile(A,n),功能是将数组A重复n次,构成一个新的数组 把inX补成有datasetsize行数的矩阵
sqDiffMat = diffMat ** 2 # 平方 **2 表示对其中每个数做平方
sqDistances = sqDiffMat.sum(axis=1) # 相加 矩阵求和时候的顺序,axis=0是按照列求和,axis=1是按照列行求和 此处按行求和
distances = sqDistances**0.5 # 开方
# 排序
sortedDistIndicies = distances.argsort() # argsort函数返回数组值从小到大的【索引值】 距离越小越好
classCount={ } # 新建classCount变量 类型为字典
# 统计
for i in range(k): # 从1-k 统计对应标签的出现次数
voteIlabel = lables[sortedDistIndicies[i]] # 从sortedDistIndicies中的最近的到第k近的标签
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 # 在该标签的值中加1,如果该标签首次存在,则get()返回0 再加1
# get() 函数返回指定键的值,如果值不在字典中返回默认值
sortedClassCount = sorted(classCount.items(),key=operator.itemgetter(1),reverse=True)
# ---------sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list----------
# key:用列表元素的某个属性或函数作为关键字,有默认值,迭代集合中的一项
# cmp:用于比较的函数,比较什么由key决定
# reverse:排序规则,True降序 False升序
# 返回值是一个经过排序的可迭代类型
# iteritems()返回iterator(迭代器)
# ---------operator--------------
# operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(从0开始计算)
# classCount.iteritems()返回一个可迭代的iterator reverse = True按降序排列
# key=operator.itemgetter(1) 用1号关键字进行比较 第0个关键字是标签名称 第1个关键字是标签出现的次数 此处使用标签出现的次数来进行排序
# 按降序排序就是讲出现次数最高的标签放在最前方 出现最少的标签放在最后方
return sortedClassCount[0][0] # 返回前k近样本中出现次数最多的标签的标签名
①报错 TypeError: list indices must beintegers or slices, not tuple
[1.0,1.0] [1.0,1.0] [0,0]之间忘了加逗号
②想在服务器上跑 配置pycharm远程的mapping时候弄错路径
最开始一直想为什么说上传成功 但是项目文件夹里的py文件没有更新
结果发现配置项目路径的时候 最开始以为非root用户需要指定到自己的文件夹下面就用的/home/username/projname 但是pycharm直接根据填的用户名找到了文件夹所以直接/projname 就可以了
③之前看一篇博文说axis=0是按行 但是如果这样就和计算距离不太对 就试了下
得: axis = 0 是按列加 axis = 1 是按行加
④ AttributeError: 'dict' object has noattribute 'iteritems'
把classCount.iteritems()改成了classCount.items()
结果: