KNN的学习
1.KNN介绍
1.1 KNN思想的基本思想
把要分类的对象(例如)一个特征向量与训练集中已知类标记的所有对象进行对比,并由k近邻对指派到哪个类进行投票。
比如说k=3,我们要找到下图中绿色原点属于哪个类别。k个最近的邻居哪个最多,就将该对象分给该类别。黑圈内是绿点的最近的3个邻居。
1.2 KNN三要素
1.距离度量
KNN算法的核心在于要找到实例点的距离。要找邻居就要度量相似性。估量不同样本之间的相似性,通常采用的方法就是计算样本间的“距离”,相似性度量方法有:欧式距离、余弦夹角、曼哈顿距离、切比雪夫距离等。
2.k值选择
若k值较小,只有与输入实例较近(相似)的训练实例才会对预测结果起作用,预测结果会对近邻实例点非常敏感。如果近邻实例点恰巧是噪声,预测就会出错。容易发生过拟合。
若k较大,与输入实例较远的(不相似的)训练实例也会对预测起作用,容易使预测出错。k值的增大就意味着整体的模型变简单。
3.分类决策规则
分类决策规则是指找到k个邻居后该如何分类待分类对象。常用的方法有:投票表决(少数服从多数),加权投票法(根据距离的远近,对k个近邻的投票进行加权,距离越近则权重越大)
1.3 KNN实现过程
(1)计算当前待分类对象与训练集中已知类标记的所有对象的距离;
(2)按照距离递增次序排序;
(3)选取与待分类对象距离最小的k个训练实例;
(4)统计这k个实例所属各个类别数;
(5)将统计的类别数最多的类别作为待分类的预测类别
2.稠密SIFT(Dense SIFT)
稠密SIFT省去了传统SIFT特征中尺度变换和采样点的步骤,直接在指定尺寸的采样窗口中对图像进行均匀采样。稠密SIFT特征提取方法不需要进行采样点筛选和特征归一化等繁琐计算,特征提取效率较高,易于实现。此外,通过均匀采样提取到的稠密特征能够更为全面地描述图像不同区域的差异信息,并且一定程度上兼顾到图像空间位置关系等全局信息,更适合图像表示和图像分类。
然而,尽管稠密SIF特征有如上优势,但依然无法替代稀疏SIFT,其中一个原因是图像的特征描述很大程度上依赖于图像的尺度,很多细节结构只存在于一定的尺度范围内,传统的稀疏SIFT通过高斯金字塔空间来实现图像的尺度变换,从而可以捕捉到原始图像中难以发现先的深层次细节信息。相比之下,稠密SIFT缺乏多尺度结构,只能发现先图像在单一尺度下表现出来的表层特征,不利于挖掘图像隐藏在深层次中的细节信息。
3.实验分析
3.1 KNN的实现
在这个实验中用欧氏距离进行度量,分类决策规则采用投票决策。
class KnnClassifier(object):
def __init__(self,labels,samples):
""" Initialize classifier with training data. """
#使用训练数据初始化分类器
self.labels = labels
self.samples = samples
def classify(self,point,k=3):
""" Classify a point against k nearest
in the training data, return label. """
#在训练数据上采用k近邻分类,并返回标记
# compute distance to all training points
#计算所有训练数据点的距离
dist = array([L2dist(point,s) for s in self.samples])
# sort them
#对他们进行排序
ndx = dist.argsort()
# use dictionary to store the k nearest
#用字典存储k近邻
votes = {
}
for i in range(k):
label = self.labels[ndx[i]]
votes.setdefault(label,0)
votes[label] += 1
return max(votes, key=lambda x: votes.get(x))
def L2dist(p1,p2):
return sqrt( sum( (p1-p2)**2) )
3.2 简单的二维示例
先建立一些简单的而为示例数据集来说明并可视化分类器的工作原理,下面的脚本将创建两个不同的二维点集,每个点集有两类,用PIckle模块来保存创建的数据。
# -*- coding: utf-8 -*-
from numpy.random import randn
import pickle
from pylab import *
# create sample data of 2D points
n = 200
# two normal distributions
class_1 = 0.6 * randn(n,2)
class_2 = 1.2 * randn(n,2) + array([5,1])
labels = hstack((ones(n),-ones(n)))
# save with Pickle
#with open('points_normal.pkl', 'w') as f:
with open('points_normal_test.pkl', 'wb') as f:
pickle.dump(class_1,f)
pickle.dump(class_2,f)
pickle.dump(labels,f)
# normal distribution and ring around it
print ("save OK!")
class_1 = 0.6 * randn(n,2)
r = 0.8 * randn(n,1) + 5
angle = 2*pi * randn(n,1)
class_2 = hstack((r*cos(angle),r*sin(angle)))
labels = hstack((