机器学习之KNN算法原理及Python实现方法详解

本文实例讲述了机器学习之KNN算法原理及Python实现方法。分享给大家供大家参考,具体如下:

文中代码出自《机器学习实战》CH02,可参考本站:

机器学习实战 (Peter Harrington著) 中文版

机器学习实战 (Peter Harrington著) 英文原版 [附源代码]

KNN算法介绍

KNN是一种监督学习算法,通过计算新数据与训练数据特征值之间的距离,然后选取K(K>=1)个距离最近的邻居进行分类判(投票法)或者回归。若K=1,新数据被简单分配给其近邻的类。

KNN算法实现过程

(1)选择一种距离计算方式, 通过数据所有的特征计算新数据与已知类别数据集中的数据点的距离;

(2)按照距离递增次序进行排序,选取与当前距离最小的k个点;

(3)对于离散分类,返回k个点出现频率最多的类别作预测分类;对于回归则返回k个点的加权值作为预测值;

算法关键

(1)数据的所有特征都要做可比较的量化

若是数据特征中存在非数值的类型,必须采取手段将其量化为数值。例如样本特征中包含颜色,可通过将颜色转换为灰度值来实现距离计算。

(2)样本特征要做归一化处理

样本有多个参数,每一个参数都有自己的定义域和取值范围,他们对距离计算的影响不一样,如取值较大的影响力会盖过取值较小的参数。所以样本参数必须做一些scale处理,最简单的方式就是所有特征的数值都采取归一化处置。

(3)需要一个距离函数以计算两个样本之间的距离

距离的定义:欧氏距离、余弦距离、汉明距离、曼哈顿距离等,一般选欧氏距离作为距离度量,但是这是只适用于连续变量。在文本分类这种非连续变量情况下,汉明距离可以用来作为度量。通常情况下,如果运用一些特殊的算法来计算度量的话,K近邻分类精度可显著提高,如运用大边缘最近邻法或者近邻成分分析法。

(4)确定K的值

K值选的太大易引起欠拟合,太小容易过拟合。交叉验证确定K值。

KNN分类

分类算法常采用多数表决决定。一个缺点是出现频率较多的样本将会主导测试点的预测结果。解决这个缺点的方法之一是在进行分类时将K个邻居到测试点的距离考虑进去。若样本到测试点距离d,则选1/d为该邻居的权重,统计k个邻居所有类标签的权重和,值最大的就是新数据点的预测类标签。

KNN回归

KNN回归是取K个邻居类标签值得加权作为新数据点的预测值。

优缺点

(1)KNN算法的优点

  • 1.简单、有效。
  • 2.重新训练的代价较低(类别体系的变化和训练集的变化,在Web环境和电子商务应用中是很常见的)。
  • 3.计算时间和空间线性于训练集的规模(在一些场合不算太大)。
  • 4.由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
  • 5.该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。

(2)KNN算法缺点

  • 1.KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多。
  • 2.类别评分不是规格化的(不像概率评分)(???)。
  • 3.输出的可解释性不强,例如决策树的可解释性较强。
  • 4.该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算最近的邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
  • 5.计算量较大。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。

KNN实现

import numpy as np
import operator
import matplotlib
import matplotlib.pyplot as plt
from os import listdir
def Create_DataSet():
 group = np.array([[1.0, 1.1],[1.0,1.0],[0,0],[0,0.1]])
 labels = ['A','A','B','B']
 return group,labels

函数Create_DataSet创建一个数据集,坐标轴左下角分类为B,右上角分类为A。

下面函数classify0,计算向量inX与数据集中各点的距离,计算n_estimators个近邻中label频率最高的分类号并返回作为向量inX的分类号。

def classify0(inX, dataSet, labels, n_estimators=3):
 dataSetSize = dataSet.shape[0]
 #print 'in classify0,dataSetSize = \n',dataSetSize
 #转变向量inx格式为datasize行,1列;并计算与dataset元素距离
 diffMat = np.tile(inX, (dataSetSize,1)) - dataSet
 #计算欧氏距离((x0-x1)^2 + (y0-y1)^2 )^(1/2)
 sqDiffMat = diffMat**2 #diffMat每个元素取平方
 sqDistances = sqDiffMat.sum(axis=1)
 distances = sqDistances**0.5
 #排序,将值从小到大排列,返回索引
 sortedDistIndicies = distances.argsort()
 #print 'in classify0,sortedDistIndicies:\n',sortedDistIndicies
 #求与距离最近的k个点的label统计
 classCount={}
 for i in range(n_estimators):
  voteIlabel = labels[sortedDistIndicies[i]] #获取对应label号
  classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
 #对字典排序,按value值降序排列
 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
 #print 'sortedClassCount[0][0]:\n',sortedClassCount[0][0]
 return sortedClassCount[0][0]

dataSet.shape()函数用于获取矩阵dataSet的大小,shape[0]返回对应行数,shape[1]返回对应列数。

因为需要对每列属性做距离运算,所以需要将输入inX转换为和dataSet相同行数和列数的矩阵,因为inX列数与dataSet中每个元素列数相同,所以需要将其行数进行扩展,np.tile(inX, (dataSetSize,1))将inX行数拓展为dataSetSize行,1表示纵向复制1次,即列不变。

距离公式采用欧式距离计算,得到的距离值为一维列表,分别对应dataSet中每个元素和inX的距离。distances.argsort() 将距离按从小到大排列,并返回索引。例如distance = [0.1,0.5,0.3],distance.argsort()返回[1,3,2] 。返回索引是为了找到对应的label值,并进行统计。

下面for循环用于建立字典并统计前n_estimators个label的个数。key对应label,key_value对应个数。

operator.itemgetter函数,operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号,即需要获取的数据在对象中的序号;例如a = [1,2,3] ,定义函数b=operator.itemgetter(1),获取对象的第1个域的值,则 b(a)=2;若定义函数b,获取对象的第1个域和第0个的值b=operator.itemgetter(1,0),则b(a)=(2, 1) 。注意operator.itemgetter函数获取的不是值,而是定义了一个函数,通过该函数作用到对象上才能获取值;

sorted函数:Python内置的排序函数sorted可以对list或者iterator进行排序;第一个参数iterable指定要排序的list或者iterable,第二个参数指定排序时进行比较的函数,可以指定一个函数或者lambda函数。例如students为类对象的list,每个成员有三个域,用sorted进行比较时可以自己定cmp函数,例如这里要通过比较第三个数据成员来排序,students = [(‘john', ‘A', 15), (‘jane', ‘B', 12), (‘dave', ‘B', 10)],sorted(students, key=lambda student : student[2]),key为函数,指定取待排序元素的哪一项进行排序,key指定的lambda函数功能是去元素student的第三个域(student[2]),因此sorted排序时会以students所有元素的第三个域来进行排序;也可以这么写sorted(students, key=operator.itemgetter(2)) ,sorted函数也可以进行多级排序,例如要根据第二个域和第三个域进行排序;sorted(students, key=operator.itemgetter(1,2))即先跟句第二个域排序,再根据第三个域排序;第三个参数reverse是一个bool变量,表示升序还是降序排列,默认为false升序排列,定义为True时将按降序排列。

此处sort函数用于对字典进行排序。按key_value降序排列,即对应label个数从大到小排列。返回值为列表,列表元素为元组,元组第一个元素对应label,第二个元素对应label个数。sortedClassCount[0][0]即返回label次数最多的类标号,为inX的label。

下面测试一个简单的向量:

group,labels = Create_DataSet()
sortedClassCount = classify0([0,0.5],group,labels,3)

输出为

sortedClassCount:[(‘B', 2), (‘A', 1)]
sortedClassCount[0][0]:
B

下面函数file2matrix用于从txt中读取原始数据并转化为矩阵。

test.txt格式为

40920 8.326976 0.953952 largeDoses
14488 7.153469 1.673904 smallDoses
26052 1.441871 0.805124 didntLike
75136 13.147394 0.428964 didntLike
……

最后一列为label,值为largeDoses、smallDoses或didntLike。每行元素用\t隔开。转换后label分别对应3、2、1。

转换函数如下:

def file2matrix(filename):
 fr = open(filename)
 numberOfLines = len(fr.readlines())
 print 'in file2matrix,numberOfLines:\n',numberOfLines
 returnMat = np.zeros((numberOfLines,3))
 classLabelVector = []
 fr = open(filename)
 index = 0
 for line in fr.readlines(): #遍历每一行
  line = line.strip() #strip用于删除字符,此处删除空白字符,回车
  listFromLine = line.split('\t') #获取每行的元素列表,元素用\t分开
  returnMat[index,:] = listFromLine[0:3]#取前3个元素,对应属性集
  if(listFromLine[-1] == 'largeDoses'):#有什么有效的方法 将属性值和类标号分开,相互对应
   classLabelVector.append(3)
  elif(listFromLine[-1] == 'smallDoses'):
   classLabelVector.append(2)
  elif(listFromLine[-1] == 'didntLike'):
   classLabelVector.append(1)
  elif(listFromLine[-1] == 3):
   classLabelVector.append(3)
  elif(listFromLine[-1] == 2):
   classLabelVector.append(2)
  elif(listFromLine[-1] == 1):
   classLabelVector.append(1)
  index += 1
 #print 'returnMat = ',returnMat
 #print 'classLabelVector = ',classLabelVector
 return returnMat,classLabelVector #得到属性集和类标号

首先打开文件并获取行数,建立一个相同大小的空矩阵,用于存储转换后的属性集,并新建一个一维列表,用于存放类标号。fr.readlines()读取所有行,得到一个行列表,列表元素为每行内容;readline只读取1行,获取该行元素的列表。
上述函数即返回属性集矩阵和类标号列表。

因为属性值差距较大,为了减少值太大的属性对值小的属性的影响,分类之前还需要进行归一化。归一化方程为(datain-min_val) / (max_val - min_val),输出值都介于0-1。

def autoNorm(dataSet):
 minVals = dataSet.min(0) #获取每列最大值与最小值,(0)指定列,而不是行
 print 'in autoNorm,minVals:',minVals
 maxVals = dataSet.max(0)
 print 'in autoNorm,maxVals:',maxVals
 ranges = maxVals - minVals
 print 'in autoNorm,ranges:',ranges
 normDataSet = np.zeros(np.shape(dataSet))
 m = dataSet.shape[0] #获取行数
 #特征值矩阵为1000x3,minVals值为1x3,使用tile函数扩展为相同大小的矩阵
 #np.tile(minVals, (m,1))矩阵minval,横向复制m次,纵向复制1次
 normDataSet = dataSet - np.tile(minVals, (m,1)) # (data - minval)/(maxval - minval)
 normDataSet = normDataSet/np.tile(ranges, (m,1)) #element wise divide
 print 'in autoNorm,normDataSet = ',normDataSet
 return normDataSet, ranges, minVals

返回归一化以后的属性集。即可进行距离运算并分类。

下面函数即对文件中所有输入的行向量属性进行分类

def datingClassTest(n_estimators=3):
 hoRatio = 0.50
 #(1)读取文件
 datingDataMat,datingLabels = file2matrix('datingTestSet.txt')
 #(2)归一化
 normMat, ranges, minVals = autoNorm(datingDataMat)
 m = normMat.shape[0]
 numTestVecs = int(m*hoRatio)
 errorCount = 0.0
 for i in range(numTestVecs):
  classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],n_estimators=n_estimators)
  if (classifierResult != datingLabels[i]): errorCount += 1.0
 print "in datingClassTest,the total error rate is: %f" % (errorCount/float(numTestVecs))
 print 'in datingClassTest,errorCount:',errorCount

将测试文件分为数据集和用于测试的向量2部分。前一半用于测试,后一半作为数据集,并定义errorCount用于统计出错个数。经过归一化以后的数据集和验证通过for循环计算分类结果,并与实际结果进行对比,得到总出错数和出错率。

执行该函数,结果显示:

in datingClassTest,the total error rate is: 0.064000
in datingClassTest,errorCount: 32.0

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python数学运算技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》及《Python文件与目录操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

(0)

相关推荐

  • Python语言描述KNN算法与Kd树

    最近邻法和k-近邻法 下面图片中只有三种豆,有三个豆是未知的种类,如何判定他们的种类? 提供一种思路,即:未知的豆离哪种豆最近就认为未知豆和该豆是同一种类.由此,我们引出最近邻算法的定义:为了判定未知样本的类别,以全部训练样本作为代表点,计算未知样本与所有训练样本的距离,并以最近邻者的类别作为决策未知样本类别的唯一依据.但是,最近邻算法明显是存在缺陷的,比如下面的例子:有一个未知形状(图中绿色的圆点),如何判断它是什么形状? 显然,最近邻算法的缺陷--对噪声数据过于敏感,为了解决这个问题,我们可

  • 以Python代码实例展示kNN算法的实际运用

    邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一.所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表. kNN算法的核心思想是如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性.该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别. kNN方法在类别决策时,只与极少量的相邻样本有关.由于kNN方法主

  • Python实现的knn算法示例

    本文实例讲述了Python实现的knn算法.分享给大家供大家参考,具体如下: 代码参考机器学习实战那本书: 机器学习实战 (Peter Harrington著) 中文版 机器学习实战 (Peter Harrington著) 英文原版[附源代码] 有兴趣你们可以去了解下 具体代码: # -*- coding:utf-8 -*- #! python2 ''''' @author:zhoumeixu createdate:2015年8月27日 ''' #np.zeros((4,2)) #np.zero

  • Python代码实现KNN算法

    kNN算法是k-近邻算法的简称,主要用来进行分类实践,主要思路如下: 1.存在一个训练数据集,每个数据都有对应的标签,也就是说,我们知道样本集中每一数据和他对应的类别. 2.当输入一个新数据进行类别或标签判定时,将新数据的每个特征值与训练数据集中的每个数据进行比较,计算其到训练数据集中每个点的距离(下列代码实现使用的是欧式距离). 3.然后提取k个与新数据最接近的训练数据点所对应的标签或类别. 4.出现次数最多的标签或类别,记为当前预测新数据的标签或类别. 欧式距离公式为: distance=

  • python可视化实现KNN算法

    简介 这里通过python的绘图工具Matplotlib包可视化实现机器学习中的KNN算法. 需要提前安装python的Numpy和Matplotlib包. KNN–最近邻分类算法,算法逻辑比较简单,思路如下: 1.设一待分类数据iData,先计算其到已标记数据集中每个数据的距离,例如欧拉距离sqrt((x1-x2)^2+(y1-y2)^2): 2.然后根据离iData最近的k个数据的分类,出现次数最多的类别定为iData的分类. KNN--最近邻算法python代码 代码实现: import

  • python实现kNN算法

    kNN(k-nearest neighbor)是一种基本的分类与回归的算法.这里我们先只讨论分类中的kNN算法. k邻近算法的输入为实例的特征向量,对对应于特征空间中的点:输出为实例的类别,可以取多类,k近邻法是建设给定一个训练数据集,其中的实例类别已定,分类时,对于新的实例,根据其k个最邻近的训练实例的类别,通过多数表决等方式进行预测.所以可以说,k近邻法不具有显示的学习过程.k临近算法实际上是利用训练数据集对特征向量空间进行划分,并作为其分类的"模型" k值的选择,距离的度量和分类

  • 使用python实现knn算法

    本文实例为大家分享了python实现knn算法的具体代码,供大家参考,具体内容如下 knn算法描述 对需要分类的点依次执行以下操作: 1.计算已知类别数据集中每个点与该点之间的距离 2.按照距离递增顺序排序 3.选取与该点距离最近的k个点 4.确定前k个点所在类别出现的频率 5.返回前k个点出现频率最高的类别作为该点的预测分类 knn算法实现 数据处理 #从文件中读取数据,返回的数据和分类均为二维数组 def loadDataSet(filename): dataSet = [] labels

  • python使用KNN算法手写体识别

    本文实例为大家分享了用KNN算法手写体识别的具体代码,供大家参考,具体内容如下 #!/usr/bin/python #coding:utf-8 import numpy as np import operator import matplotlib import matplotlib.pyplot as plt import os ''''' KNN算法 1. 计算已知类别数据集中的每个点依次执行与当前点的距离. 2. 按照距离递增排序. 3. 选取与当前点距离最小的k个点 4. 确定前k个点所

  • 纯python实现机器学习之kNN算法示例

    前面文章分别简单介绍了线性回归,逻辑回归,贝叶斯分类,并且用python简单实现.这篇文章介绍更简单的 knn, k-近邻算法(kNN,k-NearestNeighbor). k-近邻算法(kNN,k-NearestNeighbor),是最简单的机器学习分类算法之一,其核心思想在于用距离目标最近的k个样本数据的分类来代表目标的分类(这k个样本数据和目标数据最为相似). 原理 kNN算法的核心思想是用距离最近(多种衡量距离的方式)的k个样本数据来代表目标数据的分类. 具体讲,存在训练样本集, 每个

  • 机器学习之KNN算法原理及Python实现方法详解

    本文实例讲述了机器学习之KNN算法原理及Python实现方法.分享给大家供大家参考,具体如下: 文中代码出自<机器学习实战>CH02,可参考本站: 机器学习实战 (Peter Harrington著) 中文版 机器学习实战 (Peter Harrington著) 英文原版 [附源代码] KNN算法介绍 KNN是一种监督学习算法,通过计算新数据与训练数据特征值之间的距离,然后选取K(K>=1)个距离最近的邻居进行分类判(投票法)或者回归.若K=1,新数据被简单分配给其近邻的类. KNN算法

  • TF-IDF算法解析与Python实现方法详解

    TF-IDF(term frequency–inverse document frequency)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术.比较容易理解的一个应用场景是当我们手头有一些文章时,我们希望计算机能够自动地进行关键词提取.而TF-IDF就是可以帮我们完成这项任务的一种统计方法.它能够用于评估一个词语对于一个文集或一个语料库中的其中一份文档的重要程度. 在一份给定的文件里,词频 (term frequency, T

  • python多线程方法详解

    处理多个数据和多文件时,使用for循环的速度非常慢,此时需要用多线程来加速运行进度,常用的模块为multiprocess和joblib,下面对两种包我常用的方法进行说明. 1.模块安装 pip install multiprocessing pip install joblib 2.以分块计算NDVI为例 首先导入需要的包 import numpy as np from osgeo import gdal import time from multiprocessing import cpu_c

  • 决策树剪枝算法的python实现方法详解

    本文实例讲述了决策树剪枝算法的python实现方法.分享给大家供大家参考,具体如下: 决策树是一种依托决策而建立起来的一种树.在机器学习中,决策树是一种预测模型,代表的是一种对象属性与对象值之间的一种映射关系,每一个节点代表某个对象,树中的每一个分叉路径代表某个可能的属性值,而每一个叶子节点则对应从根节点到该叶子节点所经历的路径所表示的对象的值.决策树仅有单一输出,如果有多个输出,可以分别建立独立的决策树以处理不同的输出. ID3算法:ID3算法是决策树的一种,是基于奥卡姆剃刀原理的,即用尽量用

  • json跨域调用python的方法详解

    本文实例讲述了json跨域调用python的方法.分享给大家供大家参考,具体如下: 客户端: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">

  • Python魔术方法详解

    介绍 此教程为我的数篇文章中的一个重点.主题是魔术方法. 什么是魔术方法?他们是面向对象的Python的一切.他们是可以给你的类增加"magic"的特殊方法.他们总是被双下划线所包围(e.g. __init__ 或者 __lt__).然而他们的文档却远没有提供应该有的内容.Python中所有的魔术方法均在Python官方文档中有相应描述,但是对于他们的描述比较混乱而且组织比较松散.很难找到有一个例子(也许他们原本打算的很好,在开始语言参考中有描述很详细,然而随之而来的确是枯燥的语法描述

  • 散列表的原理与Java实现方法详解

    本文实例讲述了散列表的原理与Java实现方法.分享给大家供大家参考,具体如下: 概述 符号表是一种用于存储键值对(key-value pair)的数据结构,我们平常经常使用的数组也可以看做是一个特殊的符号表,数组中的"键"即为数组索引,值为相应的数组元素.也就是说,当符号表中所有的键都是较小的整数时,我们可以使用数组来实现符号表,将数组的索引作为键,而索引处的数组元素即为键对应的值,但是这一表示仅限于所有的键都是比较小的整数时,否则可能会使用一个非常大的数组.散列表是对以上策略的一种&

  • java数据结构与算法之桶排序实现方法详解

    本文实例讲述了java数据结构与算法之桶排序实现方法.分享给大家供大家参考,具体如下: 基本思想: 假定输入是由一个随机过程产生的[0, M)区间上均匀分布的实数.将区间[0, M)划分为n个大小相等的子区间(桶),将n个输入元素分配到这些桶中,对桶中元素进行排序,然后依次连接桶输入0 ≤A[1..n] <M辅助数组B[0..n-1]是一指针数组,指向桶(链表).将n个记录分布到各个桶中去.如果有多于一个记录分到同一个桶中,需要进行桶内排序.最后依次把各个桶中的记录列出来记得到有序序列. [桶-

  • C++数据结构与算法之反转链表的方法详解

    本文实例讲述了C++数据结构与算法之反转链表的方法.分享给大家供大家参考,具体如下: 算法概述:要求实现将一条单向链表反转并考虑时间复杂度. 算法分析: 数组法(略): 将列表元素逐个保存进数组,之后再逆向重建列表 点评:实现逻辑最简单,需要额外的内存开销. 移动指针: 通过三个指针逐个从链表头开始逐一反转链表元素的指针 点评:不需要额外的内存开销,会改变原始链表. 递归: 以递归的方式首先找到链表尾部,再逐一反转指针 点评:不需要额外的内存开销,不会改变原始链表. 算法实现: 构建链表结构 /

  • 感知器基础原理及python实现过程详解

    简单版本,按照李航的<统计学习方法>的思路编写 数据采用了著名的sklearn自带的iries数据,最优化求解采用了SGD算法. 预处理增加了标准化操作. ''' perceptron classifier created on 2019.9.14 author: vince ''' import pandas import numpy import logging import matplotlib.pyplot as plt from sklearn.datasets import loa

随机推荐