K-nearest neighbor(KNN)
k
近邻法一种基本的分类与回归方法,原理和实现都比较直观。其输入为样本的特征向量,输出为样本的类别,可以进行多类别分类。k近邻法是通过统计与未知样本最近点的训练样本的类别来投票决定未知样本的类别,不具有显式的学习过程。
1.k 近邻模型
距离度量
特征空间中两个样本的距离是两个样本的相似程度的反映。在
k
近邻法中常用的距离度量包括:
(1)Minkowski Distacne(闵可夫斯基距离)
定义两个变量
当 p =1时,称为曼哈顿距离(Manhattan distance)
当 p =2时,是常用的欧式距离(Euclidean distance)
当 p=∞ 时,是常用的切比雪夫距离(chebyshev distance)
上述距离在不同特征中存在一定的缺点,比如特征维度中不同的单位,如果用绝对值会导致比重不一,因此不同的特征都需要归一化,即统一为相对值。
(2)马氏距离(Mahalanobis distance)
定义两个变量 xi,xj∈χ,xi=(x1i,x2i,…,xni) , xj=(x1j,x2j,…,xnj) ,则他们之间的马氏距离为:
其中 S 是协方差矩阵。马氏距离与量纲无关,排除了变量之间相关性的干扰。在图像处理领域中常用作特征测量的标尺。
(3)夹角余弦(Cosine)
夹角余弦可以用来衡量两个特征向量方向的差异,机器学习中常用这一概念来衡量样本的差异,对于给定变量,其定义为:
夹角余弦越大表示两个向量夹角越小,向量相似度越高。夹角余弦度量的特征距离常用在自然语言处理中,是很常用的机器学习特征向量度量手段。
其余衡量样本相似度的手段还有汉明距离,杰卡德相似系数,相关系数和信息熵等。不同距离标准的选择对于KNN最终的分类结果是可能不同的。
k 值选择
如果选择较小的
k
值,相当于在较小的邻域中进行预测,使“学习”的近似误差减小,估计误差增大,预测结果会对近邻的样本点非常敏感。这意味着,
通常选取交叉验证法来选取
k
值。
分类决策规则
在KNN中常用的分类决策规则往往是多数表决,即由距离测试样本最近的
分类函数:
那么误分类的概率:
给定样本 x∈χ ,其最近邻的 k 个训练样本构成的集合
要使误分类率最小,即经验风险最小,就要使 ∑xi∈Nk(x)I(yi=cj) 最大,所以多数表决规则等效于经验风险最小化。
2. k 近邻算法
- Algorithm 3.1
- Input: traning_data
T={(x1,y1),(x2,y2),…,(xN,yN)} , testing_data (xi,yi)- Output: the label of yi
- calculate all distances between testing_data and training_data
- select the nearest
k
sample
Nk(x) voting rule: yi=argmax∑xi∈Nk(x)I(yi=cj)
KNN算法的简单实现
# Project: Machine Learning-KNN # Author:Lyndon # Date: 2015/10/18 from numpy import * import operator # Creating training data def createdata(): group = array([[1,1],[1,1.1],[0.9,1],[0,0.1],[0.1,0],[0.1,0.1],[0,1],[0.1,0.9],[0,0.8]]) labels = ['A','A','A','B','B','B','C','C','C'] return group,labels # testing process def knnclassify(testing_data,group,labels,k): datasize = group.shape[0] #the rows of array # calculate the distance diffMat = tile (testing_data,(datasize,1))-group sqdiffMat = diffMat**2 sqdiffMatsum=sqdiffMat.sum(axis=1) distances = sqdiffMatsum**2 # majority voting rule classcount={} sortdistances = distances.argsort() for i in range(k): votelabel = labels[sortdistances[i]] classcount[votelabel] = classcount.get(votelabel,0)+1 sortclass=sorted(classcount.iteritems(),key=operator.itemgetter(1),reverse=True) return sortclass[0][0] # main if __name__ == "__main__": string=raw_input("please enter two numbers, split by comma:") input_data= string.split(",") testing_data= [] for i in range(len(input_data)): testing_data.append(float(input_data[i])) string1=raw_input("please enter the k:") k=int(string1) group,labels = createdata() label=knnclassify(testing_data,group, labels, k) print "the label of input data is:" + str(label)
kNN 没有显式的学习过程,直接通过给定的训练来预测未知样本的结果,测试结果:
kNN 是经典的数据分类算法,在邮件分类,文字识别,推荐系统等领域都有相应的应用,但其整体计算量大,特别对于高维数据会消耗很多资源,虽然KD树能够优化搜索的计算量,但计算大部分的数据还是消耗很大资源。
PS:本文为机器学习(3)总结笔记,通过python实现了简单分类,原理主要参考李航《统计学习理论》第三章。