整体思想:
K近邻是最简单的机器学习算法中的一种,是一种监督学习中的一种。
K近邻的思想感觉很简单,就是选择K个最近的样本中类别最多的一类。所以其适合类域的交叉或重叠较多的待分类样本集合。
所以这个算法需要注意:
1.度量距离
2.K的选取
3.存储结构
度量距离
k近邻的第一步是选择k个最近的样本,而每个样本有很多特征,那依照什么原则选择最近的样本就是度量距离。而一般的距离度量的表达有:
欧式距离
这是最常用的,每个特征的平方差和开根号
曼哈顿距离
就是每个特征的绝对值差的和
切比雪夫距离
是L∞度量是向量空间中的一种度量,二个点之间的距离定义为其各座标数值差的最大值。以(x1,y1)和(x2,y2)二点为例,其切比雪夫距离为max(|x2-x1|,|y2-y1|)
巴士距离(Bhattacharyya距离)
测量离散或连续概率分布的相似性
离散时:
连续时,巴士系数为
马氏距离
m个样本中协方差为S,均值为u
在这里用的是欧氏距离
K值的选择
K不能选过大,也不能选过小。
K值取太小,则只是在小范围中进行预测,估计误差会比较大。就比如只取1,那么就只是取最近的样本
K值取太大,则是在大范围中进行预测,预测误差会增加,就比如取N,那么将相当于是取类别最多的。
一般用交叉验证去取K
存储结构
如果每次都计算每个训练实例和输入实例的距离显然是非常耗时间的,所以一般用KD树存储。
但这里只用一般的去计算
书中实现
具体用K近邻分类的步骤如下:
1.获取数据和标签,并转化为矩阵
2.归一化特征值
3.用待测试的样本和训练样本进行预测
4.得到预测标签,与真实标签值进行比较,统计错误率
所以这里k近邻最主要的是第三步,预测部分,这个预测的步骤为
1.计算每个训练点与当前点之间的距离
2.按照距离递增次序排序
3.选取与当前点距离最小的k个点
4.确定前K个点所在类别的出现频率
5.返回前K个点出现频率最高的类别作为当前点的预测分类
预测具体代码如下
def classify0(inX, #用于分类的输入向量
dataSet, #输入的训练样本集
labels, #标签向量
k): #最近邻的数目
#计算距离,欧式距离
dataSetSize=dataSet.shape[0]
#shape[0]就是读取矩阵第一维度的长度
diffMat=tile(inX,(dataSetSize,1))-dataSet
sqDiffMat=diffMat**2
sqDistances=sqDiffMat.sum(axis=1)
#sum应该是默认的axis=0 就是普通的相加
#而当加入axis=1以后就是将一个矩阵的每一行向量相加
distances=sqDistances**0.5
#排序
sortedDistIndicies=distances.argsort()
# argsort()函数返回的是数组值从小到大的索引值
classCount={}
#()为元祖,[]为list列表,{}为字典
#选择距离最小的K个点
for i in range(k):
voteIlabel=labels[sortedDistIndicies[i]]
classCount[voteIlabel]=classCount.get(voteIlabel,0)+1
#get()函数返回指定键的值,如果值不在字典中返回默认值
#排序
sortedClassCount=sorted(classCount.iteritems(),
#classCount的全部数据
key=operator.itemgetter(1),
#对数据的第一个域进行排序
reverse=True)
#true时将按降序排列
return sortedClassCount[0][0]
在识别手写数字上的应用
具体步骤都如上面一样,只是将一个32*32的图片变为1024的特征,所预测之前有一个向量转换的步骤。即每个样本的特征数为1024。
参考
1.机器学习实战
2.http://blog.csdn.net/zd0303/article/details/8425823