从本节博客开始,我们直接进入具体的机器学习算法以及应用上,笔者暂时的想法是每一个算法都分成三个部分。第一个部分是算法原理,包括算法的描述,数学的内容。第二部分是算法的具体代码实现细节(没错,就是手撸算法)第三部分是一个应用的实例,来加深对于算法的理解。
K-近邻算法
KNN算法是由Cover和Hart在1968年提出,是一种简单而典型的机器学习的监督式学习算法。
今天要整理的K-近邻算法是监督学习中最简单的一种,如果简单实现的话,我们只需要提供一个线性搜索的程序就可以很轻松的实现这个算法,虽然算法本身原理上并不难,但是仍然有一些值得我们去理解的东西。现在开始吧。
1.算法描述
通常KNN算法都被应用在分类问题上,我们对于算法的初步掌握只需要知道这件事情:
算法输入:训练数据集、实例向量x(搭配下方python代码理解噢)、K值选择
算法输出:实例向量x的类别
模型三要素:距离度量,k值的选择,分类决策规则
输入
def classify0(inX,dataSet,lables,k):
看起来和它的算法原理本身一样简单又简洁,在对其做正式的算法描述之前,让我用一个通俗的话来描述这个算法。
- KNN算法:假定我们已经拥有了一个训练集,它分布在我们的模型空间中,每一个训练样本,都已知它自己的类别。此时,新来了一个未知类别的实例向量x,我们根据它在空间的位置,找到K个距离它最近的训练样本,然后根据这K个样本中类别分布,将这个实例向量x划分到K个类别中最多的类别
- 正式的定义与算法描述:
输入:训练集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) . . . . . ( x n , y n ) } T=\{ (x_{1},y_{1}),(x_{2},y_{2})..... (x_{n},y_{n})\} T={(x1,y1),(x2,y2).....(xn,yn)}
与实例特征向量x
输出:实例特征向量x的类别
step1:根据给定的距离度量,在训练集T中找到与x最相近的K个点,涵盖这k个点的x的邻域记作:
N
k
(
x
)
N_{k}(x)
Nk(x)
step2:根据分类决策规则,来决定x的类别y
y
=
a
r
g
max
c
j
∑
x
i
∈
N
k
(
x
)
I
(
y
i
=
c
i
)
,
i
=
1
,
2
,
.
.
.
.
.
,
n
;
j
=
1
,
2....
,
k
j
其
中
I
是
指
示
函
数
,
若
y
i
=
c
i
,
I
=
1
,
否
则
为
0
y=arg \max\limits_{c_{j}} \ \sum\limits_{x_{i}\in N_{k}(x) } \ I(y_{i}=c_{i}), \ \ \ i=1,2,.....,n;j=1,2....,kj\\ \ \\ 其中I是指示函数,若y_{i}=c_{i},I=1,否则为0
y=argcjmax xi∈Nk(x)∑ I(yi=ci), i=1,2,.....,n;j=1,2....,kj 其中I是指示函数,若yi=ci,I=1,否则为0
对于argmax函数我解释一下,这是一个参数函数,我们可以通俗的理解为,这个函数的作用就是找到在x所对应类别集合中x的类最多的那个类,说起来可能有一些绕,但是作用确实就是一个给y一个确定的类别的作用
2.KNN模型
讲到模型,我们很自然的就可以想到直接从模型的三个要素来考虑整个模型的搭建。
(1)距离度量
距离度量决定了我们在计算两个样本之间的距离采用的计算方法。
一般来说,我们可以选择欧式距离,或者使用其他的常用的距离计算方法。关于机器学习中常用的计算距离的方法,有兴趣的朋友可以看这一篇博文。此出给出链接:
我们必须要知道的一点就是,在选取不同的距离度量的时候,带来的分类结果是不一样的。
(2)k值选择
在定义k值的时候,我们通常会在一开始选一个比较小的值,然后通过交叉验证来最终决定我们所选取的K值。
为什么k值的选择如此重要呢?
-
假设k值选择过大:
- 那么我们一次需要参考许多个邻近的样本类别,计算量会增加,不仅如此:如果k值较大,那么那些实际上距离很远的,即与实例向量x不相似的样本,也会进入我们的最终参考范围。这样就导致了我们学习误差增大。
- 极端情况下:如果k值取得过大,例如取了整个得空间的样本数量,那么KNN算法将变得毫无意义。
-
假设k值选择过小:
- 会导致我们只用了很小一部分的训练样本来估计我们的实例x,这样虽然我们保证了只有与实例x极为相似的样本才对结果起作用,但我们的估计误差会变得很大,因为实例会对近邻的类别非常敏感,且参考的范围非常的小。
- 极端情况下:我们只选K=1。每次我们只参考一个最近的样本点,然后判别,这当然是不可取的。
(3)分类决策规则
在我们的算法描述中,我们采用的是多数表决。即k个样本中,哪个类别占比最多就判定我们的实例x为哪个类别。
现在我从以下来证明”多数表决“策略的合理性:
假设分类函数为:
f
:
R
n
→
{
c
1
,
c
2
.
.
.
.
.
c
K
}
f: R^{n}\rightarrow\{c_{1},c_{2}.....c_{K} \}
f:Rn→{c1,c2.....cK}
误分类的概率是:
P
(
Y
≠
f
(
X
)
)
=
1
−
P
(
Y
=
f
(
X
)
)
(1)
P(Y\not=f(X))=1-P(Y=f(X)) \tag {1}
P(Y=f(X))=1−P(Y=f(X))(1)
我们想要的是,使得误分类的概率尽可能的小,则需要使得
P
(
Y
=
f
(
X
)
)
P(Y=f(X))
P(Y=f(X))尽可能的大
而(1)式可以化为:
1
k
∑
x
i
∈
N
k
(
x
)
I
(
y
i
≠
c
i
)
=
1
−
1
k
∑
x
i
∈
N
k
(
x
)
I
(
y
i
=
c
i
)
\frac{1}{k}\sum\limits_{x_{i}\in N_{k}(x)}I(y_{i}\not=c_{i})=1-\frac{1}{k}\sum\limits_{x_{i}\in N_{k}(x)}I(y_{i}=c_{i})
k1xi∈Nk(x)∑I(yi=ci)=1−k1xi∈Nk(x)∑I(yi=ci)
即
我
们
需
要
使
得
∑
x
i
∈
N
k
(
x
)
I
(
y
i
=
c
i
)
最
大
,
即
多
数
表
决
等
价
于
风
险
最
小
化
即我们需要使得\sum\limits_{x_{i}\in N_{k}(x)}I(y_{i}=c_{i})最大,即多数表决等价于风险最小化
即我们需要使得xi∈Nk(x)∑I(yi=ci)最大,即多数表决等价于风险最小化
当然,我们也可以根据我们自己的想法,为K个近邻元素作为参考时,添加相应的权值。例如对越近的,那么认为它的贡献值和可信度应该是更高的,赋予其更高的权值。这样也是可以的。
3.算法的数据结构
了解了算法的原理,但是放到计算机上跑数据的时候,仍然还有很大的问题。就是计算量和计算时间的问题,我们不可能等待我们的结果半个月甚至一个月,因此对于算法的实现也是非常重要且有各种优化的需求的。
(1)线性扫描
最容易实现也最简单的是线性扫描的方法来实现,直接每判定一个实例x的分类的时候,就计算所有样本与x的距离,再排序,再选k个值,再判定。
但是这样的计算量非常大。
假设我们的样本空间有约100万个样本,样本的维度是5维。采用欧式距离,我们需要进行100万次的欧式距离的计算,其中每次距离的计算,我们要进行五次减法,五次平方,和一次开方。(这个时候可以快速回忆起欧式距离的计算方法)
所以我们的核心任务就是如何快速的找到k个最邻近的样本点。如果有计算机基础的同学,学过数据结构,会想到一个拥有诸多搜索算法的结构,数结构。
(2)KD树
注意:KD树的KD指的是 K-dimension,K指的是k维空间,而不是我们讨论的KNN中的K值,请注意。
KD树是一种便于提高我们查找效率的一种数据结构。这部分涉及到数据结构的知识,如果只是初步了解KNN算法,则没有必要一定要了解KD树的构造以及具体的搜索算法。
因此,我也就在机器学习算法的文章讲解中我不做赘述。
如果你想要了解KD树的构造以及搜索算法,在这篇博文中,我专门为KD树写了一些相关的知识。
(3)Ball Tree
针对高维度的数据,KD树的效果就不再那么显著。(一般是高于20维的数据),这个时候就要采用Ball Tree的方法。
4 小结
我们通过这篇博文可以了解到,什么是KNN算法,具体的算法步骤,以及KNN算法的模型,模型的三要素:距离度量,k值的选择,分类决策规则,以及我们该选择怎么样的结构去实现这样的一个算法,并且效率还不差。
虽然KNN算法算是机器学习中最简单的算法之一,但是仍然不失为一个经典的算法。我们可以看到,它简单的部分就在于,它并没有根据训练数据得到一个参数。(无需进行模型的训练)事实上,我们知道它其实就是根据样本本身的分布特性,它的样本空间就是它的模型。这是KNN的一个非常显著的特点。
优点 | 缺点 |
---|---|
实现简单 | 计算量大(尤其是采用线性结构时) |
可以用来做分类也可以用来做回归 | 数据不平衡问题,稀缺资源的判断非常不准确 |
对数据没有假设要求 | 无法给出任何数据的任何信息,过程不可见 |
之后我们会用一些实际的例子来实现KNN的代码细节以及几个关于KNN的实例。