【笔记】k-Nearest Neighbors(KNN/k近邻)原理

文章目录

  • 1 原理
    • 1.1 数学形式
    • 1.2 几何空间
  • 2 优化
    • 2.1 k值的选择
    • 2.2 距离的度量
    • 2.3 分类决策规则
  • 3 代码
    • 3.1 直接使用sklearn中的API
    • 3.2 底层编写
  • 4 其余问题
  • 5 参考

1 原理

1.1 数学形式

kNN的算法和模型十分简单:

给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最近邻的k个实例,在某种评判标准下(平均或加权)这k个实例的“多数”属于某个类,就把该输入实例分为这个类。
本质:两个样本足够相似,就有更高的概率属于同一个类别。而看一个样本往往有失偏颇,因此会看k个样本。
KNN天然可以解决多分类问题
KNN可以解决分类和回归问题

用数学公式来描述该原理,则:

输入:给定训练数据集
T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } { T = \{(x_1,y_1),(x_2,y_2),\dots ,(x_N,y_N) \} } T={(x1,y1),(x2,y2),,(xN,yN)}
其中, x i ∈ R n { x_i \in R^n } xiRn为实例的特征向量, y i ∈ Y = { c 1 , c 2 , … , c K } { y_i \in Y = \{ c_1,c_2,\dots ,c_K \}} yiY={c1,c2,,cK}为实例的类别, i = 1 , 2 , … , N {i=1,2,\dots,N} i=1,2,,N
输出:实例x所属的类y
y = arg max ⁡ c j ∑ x i ∈ N k ( x ) I ( y i = c j ) , i = 1 , 2 , … , N ; j = 1 , 2 , … , K { y=\argmax_{c_j} \sum_{x_i \in N_k(x) } I(y_i = c_j),i=1,2,\dots,N; j=1,2,\dots,K} y=cjargmaxxiNk(x)I(yi=cj),i=1,2,,N;j=1,2,,K
其中, I {I} I为指示函数,即:
I ( y i = c j ) = { 1 , y i = c j 0 , o t h e r w i s e I(y_i=c_j)= \begin{cases} 1,\quad y_i=c_j \\ 0, \quad otherwise \end{cases} I(yi=cj)={1,yi=cj0,otherwise

特别的,当 k = 1 {k=1} k=1时,称为最近邻。

1.2 几何空间

KNN可以根据特征向量给实例一个类别,那么就可以看作该模型把特征空间划分为一些子空间,并确定子空间里的每个点所属的类
单元cell):特征空间中,对于每个训练实例点 x i {x_i} xi,距离该点比其它点更近的所有点组成的一个区域。
每个训练实例点拥有一个单元,所有训练实例的单元构成对特征空间的一个划分。
k = 1 {k=1} k=1时,最近邻模型将实例 x i {x_i} xi的类 y i {y_i} yi作为其单元所有点的类标记。因此,每个单元的实例点的类别是确定的。
【笔记】k-Nearest Neighbors(KNN/k近邻)原理_第1张图片
(图from李航的统计学习方法)

2 优化

通过对原理的了解,我们很容易找到该模型的三个要素:

  • k值的选择
  • 距离的度量
  • 分类决策规则

2.1 k值的选择

选择较小的k值?

用较小的邻域中的训练实例进行预测
近似误差会减小(只有与输入实例较近的训练实例才会对预测结果其作用)
估计误差会增大(预测结果会对近邻的实例点非常敏感,如果那个点恰巧是噪声……)
整体模型变得复杂,容易发生过拟合

选择较大的k值?

近似误差会增大
估计误差会减小
整体模型变得简单

具体应用中,k值一般较小,采用交叉验证法来选取最优k值。
sklearn中API的n_neighbors默认值为5.

2.2 距离的度量

已知:

特征空间 χ {\chi} χ是n维实数向量空间 R n , x i , x j ∈ χ , x i = ( x i ( 1 ) , x i ( 2 ) , … , x i ( n ) ) T , x j = ( x j ( 1 ) , x j ( 2 ) , … , x j ( n ) ) T {R^n,x_i,x_j \in \chi,x_i=(x_i^{(1)},x_i^{(2)},\dots,x_i^{(n)})^T,x_j=(x_j^{(1)},x_j^{(2)},\dots,x_j^{(n)})^T} Rn,xi,xjχ,xi=(xi(1),xi(2),,xi(n))T,xj=(xj(1),xj(2),,xj(n))T
x i , x j 之 间 的 距 离 L p , p ≥ 1 {x_i,x_j之间的距离L_p,p\geq 1} xi,xjLp,p1

数学上常用的距离有:

  • 欧式距离(Euclidean distance

p = 2 , L 2 ( x i , x j ) = ( ∑ l = 1 n ∣ x i ( l ) − x j ( l ) ∣ 2 ) 1 2 {p=2,L_2(x_i,x_j)=(\sum_{l=1}^n |x_i^{(l)}-x_j^{(l)}| ^2)^{\frac{1}{2}}} p=2,L2(xi,xj)=(l=1nxi(l)xj(l)2)21

  • 曼哈顿距离(Manhattan distance

p = 1 , L 1 ( x i , x j ) = ∑ l = 1 n ∣ x i ( l ) − x j ( l ) ∣ {p=1,L_1(x_i,x_j)=\sum_{l=1}^n |x_i^{(l)}-x_j^{(l)}| } p=1,L1(xi,xj)=l=1nxi(l)xj(l)

  • 切比雪夫距离(Chebyshev distance

p = ∞ , L ∞ ( x i , x j ) = max ⁡ l ∣ x i ( l ) − x j ( l ) ∣ {p=\infty,L_\infty(x_i,x_j)=\max_l |x_i^{(l)}-x_j^{(l)}|} p=,L(xi,xj)=lmaxxi(l)xj(l)

但,这些均可以统一成 L p {L_p} Lp距离,即Minkowski distance

L p ( x i , x j ) = ( ∑ l = 1 n ∣ x i ( l ) − x j ( l ) ∣ p ) 1 p {L_p(x_i,x_j)=(\sum_{l=1}^n |x_i^{(l)}-x_j^{(l)}| ^p)^{\frac{1}{p}}} Lp(xi,xj)=(l=1nxi(l)xj(l)p)p1

sklearn中API的metric默认是Minkowski distance,其参数p默认为2,即欧式距离。
具体距离评价指标可以参考官方文档:

sklearn.neighbors.DistanceMetric

2.3 分类决策规则

最简单,也是最常用的就是“多数表决”:

如果分类的损失函数为0-1损失函数,分类函数:
f : R n → { c 1 , c 2 , … , c K } {f:R^n\rightarrow \{ c_1,c_2,\dots,c_K\}} f:Rn{c1,c2,,cK}
误分类的概率:
P ( Y ≠ f ( X ) ) = 1 − P ( Y = f ( X ) ) {P(Y\neq f(X)) = 1-P(Y=f(X))} P(Y=f(X))=1P(Y=f(X))
1 k ∑ x k ∈ N k ( x ) I ( y i ≠ c j ) = 1 − 1 k ∑ x k ∈ N k ( x ) I ( y i = c j ) {\frac{1}{k} \sum_{x_k\in N_k(x)} I(y_i\neq c_j)=1- \frac{1}{k} \sum_{x_k\in N_k(x)} I(y_i=c_j)} k1xkNk(x)I(yi=cj)=1k1xkNk(x)I(yi=cj)
分类决策规则的目的实际上等价于经验风险最小化

但是,这种没有权重的投票规则在遇到平票问题的时候就没法解决。
具体体现在sklearn中API的weights中,来决定是否加权。
如果选择加权,则直接使用距离的倒数来表示权重。

3 代码

代码这里有两部分:

  • 直接使用sklearn中的API进行应用

1.6. Nearest Neighbors
sklearn.neighbors.KNeighborsClassifier
sklearn.neighbors.KNeighborsRegressor

  • 仿照上面的API进行自己编写调用

3.1 直接使用sklearn中的API

这里给出一个分类的demo:

from sklearn.neighbors import KNeighborsClassifier
# 分类器实例化
kNN_classifier = KNeighborsClassifier(n_neighbors=6)
# 训练分类器
kNN_classifier.fit(X_train, y_train)
# 使用训练后的分类器进行预测
y_predict = kNN_classifier.predict(X_predict)

3.2 底层编写

直接参考:
github的04-KNN

4 其余问题

  1. 解决回归问题可以看作周围k个邻居的(加权)平均
  2. KNN使用暴力法效率低下,如果训练集有m个样本,n个特征,则每预测一个新的数据,需要O(m*n)=》使用树结构进行优化:KD-Tree,Ball-Tree
  3. 高度数据相关=》对异常数据敏感
  4. 预测结果不具有可解释性
  5. 维数灾难=》降维手段

5 参考

本博客的目的在于记录自己学习的过程,若有错误,还望各位批评指正。
参考资料如下:

Python3入门机器学习 经典算法与应用
西瓜书 by zzh
南瓜书 from github
统计学习方法 by lh

个人在学习这几个资源的相应章节之后,感觉:

  • bobo老师讲的通俗易懂,更加贴近代码使用层面
  • 西瓜书关于KNN的内容比较少,更加注重于降维处理
  • 南瓜书是对西瓜书中“泛化错误率”推导的解释
  • 统计学习方法这本书,我认为是学习KNN的最好资源,很好的符合学习该模型的思路,并且解释与公式并存。

你可能感兴趣的:(#,机器学习,算法,python,机器学习,深度学习,人工智能)