k-近邻算法(kNN)采用测量不同特征值之间的距离方法进行分类。

优点:精度高、对异常值不敏感、无数据输入假定

缺点:计算复杂度高、空间复杂度高

使用数据范围:数值型和标称型

工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k-近邻算法中的k的出处,通常k是不大于20的整数。然后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。

kNN.py

# coding:utf-8
# !/usr/bin/env python '''
Created on Sep 16, 2010
kNN: k Nearest Neighbors Input: inX: vector to compare to existing dataset (1xN)
dataSet: size m data set of known vectors (NxM)
labels: data set labels (1xM vector)
k: number of neighbors to use for comparison (should be an odd number) Output: the most popular class label @author: pbharrin
''' from numpy import *
import operator
from os import listdir def classify0(inX, dataSet, labels, k): #inX是用于分类的输入向量,dataSet是输入的训练样本集,labels是标签向量,k是选择最近邻居的数目
dataSetSize = dataSet.shape[0] #shape函数求数组array的大小,例如dataSet一个4行2列的数组
#距离计算
diffMat = tile(inX, (dataSetSize,1)) - dataSet #tile函数的功能是重复某个数组,例如把[0,0]重复4行1列,并和dataSet相减
sqDiffMat = diffMat**2 #对数组中和横纵坐标平方
#print(sqDiffMat)
sqDistances = sqDiffMat.sum(axis=1) #把数组中的每一行向量相加,即求a^2+b^2
#print(sqDistances)
distances = sqDistances**0.5 #开根号,√a^2+b^2
#print(distances)
#a = array([1.4, 1.5,1.6,1.2])
sortedDistIndicies = distances.argsort() #按升序排序,从小到大的下标依次是2,3,1,0
#print(sortedDistIndicies)
classCount={} #字典 #选择距离最小的k个点
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]] #按下标取得标记
#print(voteIlabel)
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #在字典中计数
#print(classCount[voteIlabel])
#排序
sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
#print(sortedClassCount)
return sortedClassCount[0][0] #返回计数最多的标记 def createDataSet():
group = array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group, labels def file2matrix(filename): #处理格式问题,输入为文件名字符串,输出为训练样本矩阵和类标签向量
fr = open(filename)
numberOfLines = len(fr.readlines()) #取得文件的行数,1000行
returnMat = zeros((numberOfLines,3)) #生成一个1000行3列的矩阵
classLabelVector = [] #创建一个列表
fr = open(filename)
index = 0 #表示特征矩阵的行数
for line in fr.readlines():
line = line.strip()
listFromLine = line.split('\t') #将字符串切片并转换为列表
returnMat[index,:] = listFromLine[0:3] #选取前三个元素,存储在特征矩阵中
#print listFromLine
#print returnMat[index,:]
classLabelVector.append(int(listFromLine[-1])) #将列表的最后一列存储到向量classLabelVector中
index += 1
return returnMat,classLabelVector #返回特征矩阵和类标签向量 def autoNorm(dataSet): #归一化特征值
minVals = dataSet.min(0) #最小值
maxVals = dataSet.max(0) #最大值
ranges = maxVals - minVals #范围
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1)) #原来的值和最小值的差
normDataSet = normDataSet/tile(ranges, (m,1)) #特征值差除以范围
return normDataSet, ranges, minVals def datingClassTest():
hoRatio = 0.10 #测试数据的比例
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
#inX是用于分类的输入向量,dataSet是输入的训练样本集,labels是标签向量,k是选择最近邻居的数目
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print "分类器的结果: %d, 真正的结果: %d" % (classifierResult, datingLabels[i])
if (classifierResult != datingLabels[i]): errorCount += 1.0
print "整体的错误率: %f" % (errorCount/float(numTestVecs))
print errorCount def classifyPerson():
resultList = ['不喜欢','一点点','很喜欢']
percentTats = float(raw_input('请输入玩游戏的时间百分比:'))
ffMiles = float(raw_input('请输入飞行里程总数:'))
iceCream = float(raw_input('请输入冰淇淋的升数:'))
datingDateMat,datingLabels = file2matrix("datingTestSet2.txt") #导入数据
normMat,ranges,minVals = autoNorm(datingDateMat) #归一化
inArr = array([ffMiles,percentTats,iceCream])
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3) #分类的结果
print "喜欢的程度:",resultList[classifierResult-1] def img2vector(filename): #把32×32的二进制图像矩阵转换为1×1024的向量
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect def handwritingClassTest():
#准备训练数据
hwLabels = []
trainingFileList = listdir('digits/trainingDigits') #导入训练数据集合
m = len(trainingFileList)
trainingMat = zeros((m,1024))
#和m个训练样本进行对比
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] #取得去掉后缀名的文件名
classNumStr = int(fileStr.split('_')[0]) #取得文件名中代表的数字
hwLabels.append(classNumStr) #由文件名生成标签向量
trainingMat[i,:] = img2vector('digits/trainingDigits/%s' % fileNameStr) #输入的训练样本集
#准备测试数据
testFileList = listdir('digits/testDigits') #iterate through the test set
errorCount = 0.0
mTest = len(testFileList)
#预测测试样本
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] #取得去掉后缀名的文件名
classNumStr = int(fileStr.split('_')[0]) #取得文件名中代表的数字
vectorUnderTest = img2vector('digits/testDigits/%s' % fileNameStr) #用于分类的输入向量
#inX是用于分类的输入向量,dataSet是输入的训练样本集,labels是标签向量,k是选择最近邻居的数目
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print "分类器的结果: %d, 真实的结果: %d" % (classifierResult, classNumStr)
if (classifierResult != classNumStr): errorCount += 1.0
print "\n预测的错误数是: %d" % errorCount
print "\n预测的错误率是: %f" % (errorCount/float(mTest)) if __name__ == '__main__':
# #group,labels = createDataSet()
# #classify0([0,0],group,labels,3)
# datingDateMat,datingLabels = file2matrix("datingTestSet2.txt")
# #print datingDateMat
# #print datingLabels
# import matplotlib
# import matplotlib.pyplot as plt
# fig = plt.figure()
# ax = fig.add_subplot(111) #控制位置
# ax.scatter(datingDateMat[:,1],datingDateMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels)) #点的横纵坐标,大小和颜色
# #plt.show()
#
# normMat,ranges,minVals = autoNorm(datingDateMat)
# print normMat
# print ranges
# print minVals # datingClassTest()
# classifyPerson()
# testVector = img2vector("digits/testDigits/0_0.txt")
# print testVector[0,0:31]
handwritingClassTest()

1.使用Python导入数据

NumPy函数库中存在两种不同的数据类型(矩阵matrix和数组array),都可以用于处理行列表示的数字元素

>>> import kNN
>>> group,labels = kNN.createDataSet()
>>> group
array([[ 1. , 1.1],
[ 1. , 1. ],
[ 0. , 0. ],
[ 0. , 0.1]])
>>> labels
['A', 'A', 'B', 'B']
>>> group
array([[ 1. , 1.1],
[ 1. , 1. ],
[ 0. , 0. ],
[ 0. , 0.1]])
>>> group.shape  #shape函数求数组array的大小
(4, 2)
>>> group.shape[0]
4
>>> group.shape[1]
2

2.从文本文件中解析数据

>>> kNN.classify0([0,0],group,labels,3)  #[0,0]是用于分类的输入向量,group是输入的训练样本集,labels是标签向量,3是选择最近邻居的数目
'B'

3.如何测试分类器

例子:使用k-近邻算法改进约会网站的配对效果

1.准备数据:从文本文件中解析数据

2.分析数据:使用Matplotlib创建散点图

datingDateMat,datingLabels = file2matrix("datingTestSet2.txt")
#print datingDateMat
#print datingLabels
import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111) #控制位置
ax.scatter(datingDateMat[:,1],datingDateMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels)) #点的横纵坐标,大小和颜色
plt.show()

 

3.准备数据:归一化数值

在计算欧式距离的时候,数值差最大的属性对计算结果的影响最大。在处理这种不同取值范围的特征值的时候,我们通常的方法是将数值归一化,如将取值范围处理为0到1或者-1到1之间。

def autoNorm(dataSet):			#归一化特征值
minVals = dataSet.min(0) #最小值
maxVals = dataSet.max(0) #最大值
ranges = maxVals - minVals #范围
normDataSet = zeros(shape(dataSet))
m = dataSet.shape[0]
normDataSet = dataSet - tile(minVals, (m,1)) #原来的值和最小值的差
normDataSet = normDataSet/tile(ranges, (m,1)) #特征值差除以范围
return normDataSet, ranges, minVals
normMat,ranges,minVals = autoNorm(datingDateMat)
print normMat
print ranges
print minVals

 

4.测试算法:作为完整程序验证分类器

def datingClassTest():
hoRatio = 0.10 #测试数据的比例
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #load data setfrom file
normMat, ranges, minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio)
errorCount = 0.0
for i in range(numTestVecs):
#inX是用于分类的输入向量,dataSet是输入的训练样本集,labels是标签向量,k是选择最近邻居的数目
classifierResult = classify0(normMat[i,:],normMat[numTestVecs:m,:],datingLabels[numTestVecs:m],3)
print "分类器的结果: %d, 真正的结果: %d" % (classifierResult, datingLabels[i])
if (classifierResult != datingLabels[i]): errorCount += 1.0
print "整体的错误率: %f" % (errorCount/float(numTestVecs))
print errorCount

5.使用算法:构建完整可用系统

def classifyPerson():
resultList = ['不喜欢','一点点','很喜欢']
percentTats = float(raw_input('请输入玩游戏的时间百分比:'))
ffMiles = float(raw_input('请输入飞行里程总数:'))
iceCream = float(raw_input('请输入冰淇淋的升数:'))
datingDateMat,datingLabels = file2matrix("datingTestSet2.txt") #导入数据
normMat,ranges,minVals = autoNorm(datingDateMat) #归一化
inArr = array([ffMiles,percentTats,iceCream])
classifierResult = classify0((inArr-minVals)/ranges,normMat,datingLabels,3) #分类的结果
print "喜欢的程度:",resultList[classifierResult-1]

例子:手写识别系统

1.准备数据,将图像转换为测试向量

def img2vector(filename):		#把32×32的二进制图像矩阵转换为1×1024的向量
returnVect = zeros((1,1024))
fr = open(filename)
for i in range(32):
lineStr = fr.readline()
for j in range(32):
returnVect[0,32*i+j] = int(lineStr[j])
return returnVect
testVector = img2vector("digits/testDigits/0_0.txt")
print testVector[0,0:31]

2.测试算法:使用k-近邻算法识别手写数字

def handwritingClassTest():
#准备训练数据
hwLabels = []
trainingFileList = listdir('digits/trainingDigits') #导入训练数据集合
m = len(trainingFileList)
trainingMat = zeros((m,1024))
#和m个训练样本进行对比
for i in range(m):
fileNameStr = trainingFileList[i]
fileStr = fileNameStr.split('.')[0] #取得去掉后缀名的文件名
classNumStr = int(fileStr.split('_')[0]) #取得文件名中代表的数字
hwLabels.append(classNumStr) #由文件名生成标签向量
trainingMat[i,:] = img2vector('digits/trainingDigits/%s' % fileNameStr) #输入的训练样本集
#准备测试数据
testFileList = listdir('digits/testDigits') #iterate through the test set
errorCount = 0.0
mTest = len(testFileList)
#预测测试样本
for i in range(mTest):
fileNameStr = testFileList[i]
fileStr = fileNameStr.split('.')[0] #取得去掉后缀名的文件名
classNumStr = int(fileStr.split('_')[0]) #取得文件名中代表的数字
vectorUnderTest = img2vector('digits/testDigits/%s' % fileNameStr) #用于分类的输入向量
#inX是用于分类的输入向量,dataSet是输入的训练样本集,labels是标签向量,k是选择最近邻居的数目
classifierResult = classify0(vectorUnderTest, trainingMat, hwLabels, 3)
print "分类器的结果: %d, 真实的结果: %d" % (classifierResult, classNumStr)
if (classifierResult != classNumStr): errorCount += 1.0
print "\n预测的错误数是: %d" % errorCount
print "\n预测的错误率是: %f" % (errorCount/float(mTest))

机器学习——k-近邻算法的更多相关文章

  1. [机器学习] k近邻算法

    算是机器学习中最简单的算法了,顾名思义是看k个近邻的类别,测试点的类别判断为k近邻里某一类点最多的,少数服从多数,要点摘录: 1. 关键参数:k值 && 距离计算方式 &&am ...

  2. Python3入门机器学习 - k近邻算法

    邻近算法,或者说K最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一.所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代 ...

  3. 机器学习(1)——K近邻算法

    KNN的函数写法 import numpy as np from math import sqrt from collections import Counter def KNN_classify(k ...

  4. 1.K近邻算法

    (一)K近邻算法基础 K近邻(KNN)算法优点 思想极度简单 应用数学知识少(近乎为0) 效果好 可以解释机器学习算法使用过程中的很多细节问题 更完整的刻画机器学习应用的流程 图解K近邻算法 上图是以 ...

  5. 机器学习之K近邻算法(KNN)

    机器学习之K近邻算法(KNN) 标签: python 算法 KNN 机械学习 苛求真理的欲望让我想要了解算法的本质,于是我开始了机械学习的算法之旅 from numpy import * import ...

  6. 机器学习03:K近邻算法

    本文来自同步博客. P.S. 不知道怎么显示数学公式以及排版文章.所以如果觉得文章下面格式乱的话请自行跳转到上述链接.后续我将不再对数学公式进行截图,毕竟行内公式截图的话排版会很乱.看原博客地址会有更 ...

  7. 机器学习 Python实践-K近邻算法

    机器学习K近邻算法的实现主要是参考<机器学习实战>这本书. 一.K近邻(KNN)算法 K最近邻(k-Nearest Neighbour,KNN)分类算法,理解的思路是:如果一个样本在特征空 ...

  8. 机器学习:k-NN算法(也叫k近邻算法)

    一.kNN算法基础 # kNN:k-Nearest Neighboors # 多用于解决分裂问题 1)特点: 是机器学习中唯一一个不需要训练过程的算法,可以别认为是没有模型的算法,也可以认为训练数据集 ...

  9. 【机器学习】k近邻算法(kNN)

    一.写在前面 本系列是对之前机器学习笔记的一个总结,这里只针对最基础的经典机器学习算法,对其本身的要点进行笔记总结,具体到算法的详细过程可以参见其他参考资料和书籍,这里顺便推荐一下Machine Le ...

  10. 机器学习(四) 分类算法--K近邻算法 KNN (上)

    一.K近邻算法基础 KNN------- K近邻算法--------K-Nearest Neighbors 思想极度简单 应用数学知识少 (近乎为零) 效果好(缺点?) 可以解释机器学习算法使用过程中 ...

随机推荐

  1. mac终端命令

    目录操作 命令名 功能描述 使用举例 mkdir 创建一个目录 mkdir dirname rmdir 删除一个目录 rmdir dirname mvdir 移动或重命名一个目录 mvdir dir1 ...

  2. webform(八)——LinQ简单增、删、改、查

    一.简单介绍 1.LinQ to Sql类(NET Language Integrated Query (LINQ) ) LINQ定义了大约40个查询操作符,如select.from.in.where ...

  3. nodejs pm2部署配置

    pm2是一个进程管理工具,可以用它来管理你的node进程,并查看node进程的状态,当然也支持性能监控,进程守护,负载均衡等功能. 1.pm2安装使用需要全局安装  npm install -g pm ...

  4. 安装wampserver时提示丢失MSVCR110.dll(在windows server上可用)

    对于32位系统,安装Wampserver 后启动的时候提示系统错误:MSVCR110.dll丢失. 于是卸载原来的WAMPSERVER .安装vcredist_x86.exe,重新安装WAMPSERV ...

  5. android px转换为dip/dp

    /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public int dipTopx(Context context, float dpValue) { final floa ...

  6. [转]Writing Custom Middleware in ASP.NET Core 1.0

    本文转自:https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/ One of the new ...

  7. React构建单页应用方法与实例

    React作为目前最流行的前端框架之一,其受欢迎程度不容小觑,从这门框架上我们可以学到许多其他前端框架所缺失的东西,也是其创新性所在的地方,比如虚拟DOM.JSX等.那么接下来我们就来学习一下这门框架 ...

  8. Linux下使用crontab定时备份日志

    上周学习了Linux,其中有使用crontab定时备份日志的内容,现把主要步骤记录如下: 首先需要备份的日志的源目录位于/opt/lampp/logs/access_log 备份到/tmp/logs下 ...

  9. phpstudy配置伪静态的方法

    mod_rewrite是Apache的一个非常强大的功能,它可以实现伪静态页面.下面我详细说说它的使用方法1.检测Apache是否支持mod_rewrite通过php提供的phpinfo()函数查看环 ...

  10. [LeetCode] House Robber II 打家劫舍之二

    Note: This is an extension of House Robber. After robbing those houses on that street, the thief has ...