K-近邻算法

《机器学习实战》这本书配合了python代码去研究算法,这就可以在学习python的同时去学习算法,但是这本书里的算法并不是我们收悉的python代码的方式,而是较多的cmd命令行dos命令的方式去编写。
该算法属于监督学习的一种,主要采用测量不同特征值之间的距离进行分类,具有精度高,对异常值不敏感,无数据输入假定的优点,具有计算的时间和空间复杂度较高的缺点。
原理如下:存在一个样本数据集合,也称作训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一样本数据与所属分类的对应关系。输入没有标签的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前K个最相似的数据,通常K是不大于20的整数。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
.k-近邻算法的一般流程
①收集数据
②准备数据:距离计算所需要的数值,最好是格式化数据
③分析数据
④测试算法:计算错误率
使用python实现代码如下:

from numpy import *
import operator

def classify0(inX, dataSet, labels, k):
‘’‘k-近邻算法’’’
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances
0.5
sortedDistIndicies = distances.argsort()
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

这个函数传入的参数分别是:inX(用于分类的输入向量)

                                        dataSet(输入的训练样本集)

                                        labels(标签向量)

                                        k(最后选择的近邻数目)

核心公式:计算两点之间xA和xB的距离。使用欧氏距离公式

四.实例:使用k-近邻改进约会网站的配对效果

约会网站统计出三条特征值,分别是:

                                               ①每周飞行里数

                                               ②玩游戏视频消耗时间的百分比

                                               ③每周消耗冰淇凌的公升数

                                            目标值:

                                                 1.不喜欢

                                                 2.魅力一般

                                                 3.极具魅力   

过程:

①收集数据:本次使用已经存在的数据集,点击下载(只做学习参考,请勿用于商业用途)

②准备数据:使用Python解析文本文件

③分析数据:使用Matplotlib画二维扩散图

④测试算法:

⑤使用算法:

代码如下:

一.首先将文本解析

form numpy import *
def file2matrix(filename):
'''将文本记录转换到NumPy的解析程序'''
fr = open(filename) # 打开文本
numberOfLines = len(fr.readlines()) # 获得文本行数
returnMat = zeros((numberOfLines,3)) # 设置另一维度为3(可以根据需要调整)
classLabelVector = []
fr = open(filename)
index = 0
for line in fr.readlines(): # 循环处理每行数据("40920   8.326976    0.953952    3")
line = line.strip() # 截掉所有的回车字符('40920\t8.326976\t0.953952\t3')
listFromLine = line.split('\t') # 使用制表符,将整行数据分割成一个元素列表(['40920', '8.326976', '0.953952', '3'])
returnMat[index,:] = listFromLine[0:3] # 获取前三个元素将他们存储到特征矩阵中
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
datingDataMat,datingLabels = file2matrix("datingTestSet2.txt")
print(file2matrix("datingTestSet2.txt"))

二.为了更加直观的了解数据的含义使用Matplotlib使数据可视化

import matplotlib
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(datingDataMat[:,1], datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels ))
plt.show()

横坐标:玩视频游戏的百分比
纵坐标:每周消费的冰激凌公升数
更改字段:
ax.scatter(datingDataMat[:,1], datingDataMat[:,2],15.0array(datingLabels),15.0array(datingLabels ))
输出效果如下:
横坐标:每年飞行的里程
纵坐标:玩视频游戏所占的百分比
三:归一化数据
根据上面的图片可以看出。如果想计算某两个样本之间的距离,使用欧姓距离公式,因为飞行里程数和其他数据相比十分巨大,会对结果造成关键的影响,但是实际上飞行里程数对分类结果造成的影响应该没有这么巨大。
所以在处理不同取值范围的特征值时,通常采用的方法是将数据归一化。将取值范围处理到0到1,或者-1到1之间。
归一化公式:
newValue = (oldValue-min)/(max-min)
min, max 分别为特征的最小,最大值
归一化python代码实现:

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)) #element wise divide
return normDataSet, ranges, minVals
normMat,ranges,minVals = autoNorm(datingDataMat)
normMat,ranges,minVals

四.测试算法
一般情况下使用10%-20%左右的数据作为测试集数据。要求测试数据是在整个样本数据中随机产生的。
代码如下

import operator
def datingClassTest():
hoRatio = 0.10 #选出10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #加载数据
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],3) #数据传入分类器
print ("分类器的计算结果是: %d, 实际的值是: %d" % (classifierResult, datingLabels[i]))
if (classifierResult != datingLabels[i]): errorCount += 1.0
print("分类器的错误率是: %f" % (errorCount/float(numTestVecs)))
print('总共错判:',errorCount)

五.使用分类器

def classMan():
iflist = ['不喜欢','有些魅力','魅力十足']
ftime = float(input('每周的飞行时间是:'))
gtime = float(input('玩游戏所占的时间比是:'))
ice = float(input('每周消耗的冰激凌公升数:'))
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #加载数据
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = array([ftime,gtime,ice])
classifierResult = classify0((inArr -minVals)/ranges,normMat,datingLabels,3)
print('猜你对这个人的感觉是:',iflist[classifierResult-1])
classMan()

下面是完整代码:

from numpy import *
import operator

def file2matrix(filename):
'''将文本记录转换到NumPy的解析程序'''
fr = open(filename) # 打开文本
numberOfLines = len(fr.readlines()) # 获得文本行数
returnMat = zeros((numberOfLines,3)) # 设置另一维度为3(可以根据需要调整)
classLabelVector = []
fr = open(filename)
index = 0
for line in fr.readlines(): # 循环处理每行数据("40920   8.326976    0.953952    3")
line = line.strip() # 截掉所有的回车字符('40920\t8.326976\t0.953952\t3')
listFromLine = line.split('\t') # 使用制表符,将整行数据分割成一个元素列表(['40920', '8.326976', '0.953952', '3'])
returnMat[index,:] = listFromLine[0:3] # 获取前三个元素将他们存储到特征矩阵中
classLabelVector.append(int(listFromLine[-1]))
index += 1
return returnMat,classLabelVector
# datingDataMat,datingLabels = file2matrix("datingTestSet2.txt")
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 classify0(inX, dataSet, labels, k):
'''k-近邻'''
dataSetSize = dataSet.shape[0]
diffMat = tile(inX, (dataSetSize,1)) - dataSet
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort()
classCount={}
for i in range(k):
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]

def datingClassTest():
'''测试类器正确率'''
hoRatio = 0.10 #选出10%
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #加载数据
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],3) #数据传入分类器
print("分类器的计算结果是: %d,实际的值是: %d" % (classifierResult, datingLabels[i]))
if (classifierResult != datingLabels[i]): errorCount += 1.0
print( "分类器的错误率是: %f" % (errorCount/float(numTestVecs)))
print('总共错判',errorCount)
def classMan():
iflist = ['不喜欢','有些魅力','魅力十足']
ftime = float(input('每周的飞行时间是:'))
gtime = float(input('玩游戏所占的时间比是:'))
ice = float(input('每周消耗的冰激凌公升数:'))
datingDataMat,datingLabels = file2matrix('datingTestSet2.txt') #加载数据
normMat, ranges, minVals = autoNorm(datingDataMat)
inArr = array([ftime,gtime,ice])
classifierResult = classify0((inArr -minVals)/ranges,normMat,datingLabels,3)
print('猜你对这个人的感觉是:',iflist[classifierResult-1])
classMan()

总结:主要流程就是数据集的解析,归一化,测试,使用。k-近邻算法对k的选值不好把握。对结果影响也比较大

主要参考:机器学习实战,链接:ine-learning-in-action
原文链接:ttps://blog.csdn.net/cd_home/article/details/79536936

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值