写在前面
本人python菜鸟,最近在学习机器学习。因为实在太菜,代码里的有些函数不太懂,希望能够边写边加深理解吧。
我用的学习资料是MLP_机器学习实战,资源放在下面,有需要的童鞋可以自行下载哈~~
https://pan.baidu.com/s/1jbFZ2YMrC7X2ZvJJJbL0hA
提取码:gjif
概述
k-近邻算法采用测量不同特征值之间的距离方法进行分类。
优点:精度高、对异常值不敏感、无数据输入假定。
缺点:计算复杂度搞、空间复杂度高。
适用数据范围:数值型和标称型
PS:标称型数据:一般在有线的数据中取,而且只存在“是”和“否”两种不同的结果
K近邻算法工作原理
存在一个训练样本集,样本集中每一数据与所属分类的对应关系是已知的。输入没有对应关系的新数据后,将新数据的每个特征与样本集中数据对应的特征进行比较,然后算法提取样本集中特征最相似数据(最近邻)的分类标签。一般,选前k个最相似的数据。最后,选择k个最相似数据中出现次数最多的分类,作为新数据的分类。
K近邻算法的一般流程
对未知类别属性的数据集中的每个点依次执行以下操作:
(1) 计算已知类别数据集中的点与当前点之间的距离;
(2) 按照距离递增次序排序;
(3) 选取与当前点距离最小的k个点;
(4) 确定前k个点所在类别的出现频率;
(5) 返回前k个点出现频率最高的类别作为当前点的预测分类。
算法代码
knn.py
from numpy import *
import operator
sample=array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels=['A','A','B','B']
#classify0函数有4个输入参数
#用于分类的输入向量:inX
#输入的训练样本:dataset
#标签向量为labels
#选择最近邻居的数目:k
def classify0(inX,dataset,labels,k):
'''距离计算'''
#dataset.shape[0]返回dataset的第一维度的长度
setsize=dataset.shape[0]
#tile(inX,(setsize,1))表示将输入向量扩展到和dataset一样的行数,再减去dataset
diffmat=tile(inX,(setsize,1))-dataset
sq_diffmat=diffmat**2
#按行相加求和
sq_distances=sq_diffmat.sum(axis=1)
#得到需要的欧氏距离
distances=sq_distances**0.5
'''选择距离最小的k个点'''
#argsort()函数是将x中的元素从小到大排列,返回其对应的index(索引)
dis_sort_indicies=distances.argsort()
class_count={}
#通过循环,依次找出前k个距离的下标对应的label
for i in range(k):
votedlabel=labels[dis_sort_indicies[i]]
#字典:{'标签':出现次数}
class_count[votedlabel]=class_count.get(votedlabel,0)+1
result=sorted(class_count.items(),key=operator.itemgetter(1),reverse=True)
return result[0][0]
print(classify0([8,0],sample,labels,3))
值得一提的函数
(1)get函数
classCount.get(voteIlabel,0)返回字典classCount中voteIlabel元素对应的值,若无,则初始化为0。
当第一次遇到新的label时,字典中没有对应的元素,则初始化为0,再根据class_count.get(votedlabel,0)+1,label计数为1。以此类推巴拉啦…
(2)sorted函数
sorted(iterable=class_count.iteritems(),key=operator.itemgetter(1),reverse=True)
#iterable--表示可迭代的对象
#key--主要是用来进行比较的元素
#reverse--排序规则,reverse = True 降序 , reverse = False 升序(默认)
iterable表示可迭代的对象。这里的class_count.items()表示将class_count中的所有项,以列表方式返回。
key 表示用来进行比较的元素。这里operator.itemgetter(1)表示按照class_count中的出现次数作为比较元素。
reverse表示排序规则,reverse = True 降序 , reverse = False 升序(默认)。
(3)items()和iteritems()区别
字典的items方法作用:是可以将字典中的所有项,以列表方式返回。因为字典是无序的,所以用items方法返回字典的所有项,也是没有顺序的。
字典的iteritems方法作用:与items方法相比作用大致相同,只是它的返回值不是列表,而是一个迭代器。
在Python 3.x 里面,iteritems()方法已经废除了。在3.x里用 items()替换iteritems() ,可以用于 for 来循环遍历。
实例:使用k-近邻算法改进约会网站的配对效果
案例背景
海伦一直使用在线约会网站寻找适合自己的约会对象。经过一番总结,她发现曾交往过三种类型的人:不喜欢的人,魅力一般的人,极具魅力的人。海伦收集了约会数据,样本数据主要包含3种特征:每年获得的飞行常客里程数,玩视频游戏所耗时间百分比,每周消费的冰淇淋公升数。
原始数据 datingTestSet.txt
文本数据处理
#文本处理
def file2matrix(filename):
fr=open(filename)
arrayOfLines=fr.readlines()
numberOfLines=len(arrayOfLines)
returnMat =zeros((numberOfLines,3))
classlabelvector = []
index=0
for line in arrayOfLines:
line = line.strip() #截取掉所有的回车字符
listfromline=line.split('\t') #用'\t'将上一步的整行数据分割成一个元素列表
returnMat[index,:]=listfromline[0:3]
classlabelvector.append(int(listfromline[-1])) #将列表的最后一列存储到向量classLabelVector中
index += 1
return returnMat,classlabelvector
datingDataMat,datingLabels = file2matrix('E:\\datingTestSet.txt')
print(datingDataMat,datingLabels)
归一化处理
由于原数据中有个变量每年获得的飞行常客里程数和其他变量的差异较大,会影响计算结果。所以要对数据进行归一化。
#归一化特征值
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=dataset/tile(ranges,(m,1))
return normdataset,ranges,minVals
标准化之后的结果
print(autoNorm(returnMat))
测试分类器的效果
#测试分类器效果
def datingClassTest():
hoRatio = 0.1
datingDataMat,datingLabels = file2matrix('E:\\datingTestSet.txt')
normMat,ranges,minVals = autoNorm(datingDataMat)
m = normMat.shape[0]
numTestVecs = int(m*hoRatio) #测试数据集为10%
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)))
这个例子表明我们可以正确地预测分类,错误率仅仅是2.4%。