背景
监督学习中数据是有标签的,比较入门。而在监督学习中,有分类和回归两个任务。其中分类又是比较简单的,那我们从分类入手,介绍第一个基础分类算法——KNN。
简介
KNN,全称K-NearestNeighbor,也叫K近邻。是监督学习中的一种基础的常用分类算法。
所谓K近邻,即选取k个最近的邻居,来代表每个样本。
说起来比较抽象,我们从图上来看一下。
已分类数据:
图中有两个类别:红色的三角形和蓝色的正方形。他们的样本数据散落在图中。
待分类数据:
绿色圆圈,上面打着问号,也就是我们要将他分到两个类别中。
好了,那么我们现在要看绿色的圆圈到底分到哪个类别中。
首先解决k=?
1.当k=3时,即图中边框为实线的圈中。包含了两个三角形和一个正方形,所以此时绿色圆圈属于三角形的分类。
2.当k=5时,即图中边框为虚线的圈中,包含了两个三角形和三个正方形,绿色圆圈属于正方形的分类。(对!就是这么简单粗暴)
由上可见:
1.待分类元素的k个最近邻居不包含其本身。
2.k近邻算法中,k最好不要选择偶数,以免出现邻居中类别个数相同的情况。
3.k的选取十分关键,他几乎主导着最终的分类结果。
其中,上面所说的“距离”,在KNN中常见的表现方式有:欧式距离、曼哈顿距离。
1.欧式距离
最常用、最简单。(数学符号不好打,偷个懒,贴图了)
2.曼哈顿距离
也叫城市街区距离,即|x1-x2|+|y1-y2|。
实例
Demo1:
直接给出坐标轴中的几个点和他们所属类别,判断新数据的类别。
from numpy import *
import operator
import matplotlib
import matplotlib.pyplot as plt
'''创建数据集和标签'''
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
'''用欧式距离求k近邻'''
def classfiy0(intX,dataSet,labels,k):
dataSetSize=dataSet.shape[0]
diffMat=tile(intX,(dataSetSize,1))-dataSet
sqDiffMat=diffMat**2
sqDistances=sqDiffMat.sum(axis=1)
distance=sqDistances**0.5
sortedDistIndicies=distance.argsort();#返回的是数组值从小到大的索引值
classCount={}
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
#排序
sortedClassCount=sorted(classCount.iteritems(),key=operator.itemgetter(1),reverse = True)
return sortedClassCount[0][0]
开始调用:
group,label=createDataSet()
print(classfiy0([0,0],group,label,3))
打印结果:
B
Tips:可以切换调用时的k取值,查看最终分类结果的变化。
Demo2:
根据收集处理好的文本文件使用,使用该算法,并绘制图像。
对于下面要用到的datingTestSet2.txt,我们简单看其中的几条数据:
第一列:每年的飞行旅程数;
第二列:玩游戏所耗时间占比;
第三列:每周消费的冰淇淋公斤数;
第四列:所属分类:不喜欢、一般、喜欢。
40920 8.326976 0.953952 3
14488 7.153469 1.673904 2
26052 1.441871 0.805124 1
75136 13.147394 0.428964 1
38344 1.669788 0.134296 1
72993 10.141740 1.032955 1
35948 6.830792 1.213192 3
42666 13.276369 0.543880 3
67497 8.631577 0.749278 1
35483 12.273169 1.508053 3
50242 3.723498 0.831917 1
63275 8.385879 1.669485 1
5569 4.875435 0.728658 2
51052 4.680098 0.625224 1
77372 15.299570 0.331351 1
整个分类的需求就比较清楚了,我们需要根据女主人公所记录的以往约会对象以上三个指标和自己是否喜欢的判断,设计好分类器。用来帮助女主人公在后面的约会中,只需要收集前面三个指标,就能推断出相亲对象的魅力程度。
#加载并解析数据
datingDataMat,datingLabels=file2matrix('file/datingTestSet2.txt')
print("开始绘制")
fig=plt.figure()
ax=fig.add_subplot(111)
#ax.scatter(datingDataMat[:,1],datingDataMat[:,2])
ax.scatter(datingDataMat[:,1],datingDataMat[:,2],15.0*array(datingLabels),15.0*array(datingLabels))
plt.show()
'''测试算法'''
def datingClassTest():
hoRatio=0.10
datingDataMat,datingLabels=file2matrix('file/datingTestSet2.txt')
normMat,ranges,minVals=autoNorm(datingDataMat)
m=normMat.shape[0]
numTestVecs=int(m*hoRatio)
errorCount=0.0
for i in range(numTestVecs):
classifierResult=classfiy0(normMat[i,:],normMat[numTestVecs:m,:],
datingLabels[numTestVecs:m],3)
print ("the classifier came back with: %d ,the real answer is: %d" % (classifierResult,datingLabels[i]))
if(classifierResult!=datingLabels[i]):errorCount+=1.0
print ("the total error rate is :%f" % (errorCount/float(numTestVecs)))
散点图:
步骤
KNN实验可以分为以下几个步骤:
- 收集数据:提供文件。
- 准备数据:若不是分类器能直接使用的数据格式,则需要进行转换,如图像格式等。
- 分析数据:检查数据,看是否符合要求。
- 训练算法(该算法不涉及)
- 测试算法:编写函数使用提供的部分数据集作为测试样本,如果预测分类与实际分类不符,则标记为一个错误。
- 使用算法:本例未涉及。
小结
KNN算法简单有效,易于理解。但他的缺点也十分突出。
- 计算中需保存全部数据集,占用大量内存空间。
- k个邻近距离,需要对每条距离进行计算,会十分耗时。
- 对于该算法给出的分类结果,我们无法知道正确与否。且依赖k值的选取。