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 } xi∈Rn为实例的特征向量, y i ∈ Y = { c 1 , c 2 , … , c K } { y_i \in Y = \{ c_1,c_2,\dots ,c_K \}} yi∈Y={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=cjargmaxxi∈Nk(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时,称为最近邻。
KNN可以根据特征向量给实例一个类别,那么就可以看作该模型把特征空间划分为一些子空间,并确定子空间里的每个点所属的类。
单元(cell):特征空间中,对于每个训练实例点 x i {x_i} xi,距离该点比其它点更近的所有点组成的一个区域。
每个训练实例点拥有一个单元,所有训练实例的单元构成对特征空间的一个划分。
k = 1 {k=1} k=1时,最近邻模型将实例 x i {x_i} xi的类 y i {y_i} yi作为其单元所有点的类标记。因此,每个单元的实例点的类别是确定的。
(图from李航的统计学习方法)
通过对原理的了解,我们很容易找到该模型的三个要素:
选择较小的k值?
用较小的邻域中的训练实例进行预测
近似误差会减小(只有与输入实例较近的训练实例才会对预测结果其作用)
估计误差会增大(预测结果会对近邻的实例点非常敏感,如果那个点恰巧是噪声……)
整体模型变得复杂,容易发生过拟合
选择较大的k值?
近似误差会增大
估计误差会减小
整体模型变得简单
具体应用中,k值一般较小,采用交叉验证法来选取最优k值。
sklearn中API的n_neighbors默认值为5.
已知:
特征空间 χ {\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,xj之间的距离Lp,p≥1
数学上常用的距离有:
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=1∑n∣xi(l)−xj(l)∣2)21
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=1∑n∣xi(l)−xj(l)∣
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)=lmax∣xi(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=1∑n∣xi(l)−xj(l)∣p)p1
sklearn中API的metric默认是Minkowski distance,其参数p默认为2,即欧式距离。
具体距离评价指标可以参考官方文档:
sklearn.neighbors.DistanceMetric
最简单,也是最常用的就是“多数表决”:
如果分类的损失函数为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))=1−P(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)} k1xk∈Nk(x)∑I(yi=cj)=1−k1xk∈Nk(x)∑I(yi=cj)
分类决策规则的目的实际上等价于经验风险最小化。
但是,这种没有权重的投票规则在遇到平票问题的时候就没法解决。
具体体现在sklearn中API的weights中,来决定是否加权。
如果选择加权,则直接使用距离的倒数来表示权重。
代码这里有两部分:
1.6. Nearest Neighbors
sklearn.neighbors.KNeighborsClassifier
sklearn.neighbors.KNeighborsRegressor
这里给出一个分类的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)
直接参考:
github的04-KNN
本博客的目的在于记录自己学习的过程,若有错误,还望各位批评指正。
参考资料如下:
Python3入门机器学习 经典算法与应用
西瓜书 by zzh
南瓜书 from github
统计学习方法 by lh
个人在学习这几个资源的相应章节之后,感觉: