机器学习之KNN
目录
放弃该放弃的是无奈,放弃不该放弃的是无能;不放弃该放弃的是无知,不放弃不该放弃的是执着。
KNN是什么?
- 何谓K近邻算法,即K-Nearest Neighbor algorithm,简称KNN算法,单从名字来猜想,可以简单粗暴的认为是:K个最近的邻居,当K=1时,算法便成了最近邻算法,即寻找最近的那个邻居。
- 所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是上面所说的K个邻居),这K个实例的多数属于某个类,就把该输入实例分类到这个类中(近朱者赤近墨者黑)。
- KNN算法是机器学习算法中最基础、最简单的算法之一。它既能用于分类,也能用于回归。KNN通过测量不同特征值之间的距离来进行分类。
K近邻算法的核心思想
如上图所示,有两类不同的样本数据,分别用蓝色的小正方形和红色的小三角形表示,而图正中间的那个绿色的圆所标示的数据则是待分类的数据。也就是说,现在,我们不知道中间那个绿色的数据是从属于哪一类(蓝色小正方形or红色小三角形),KNN就是解决这个问题的。
- 如果K=3,绿色圆点的最近的3个邻居是2个红色小三角形和1个蓝色小正方形,少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于红色的三角形一类。
- 如果K=5,绿色圆点的最近的5个邻居是2个红色三角形和3个蓝色的正方形,还是少数从属于多数,基于统计的方法,判定绿色的这个待分类点属于蓝色的正方形一类。
于此我们看到,当无法判定当前待分类点是从属于已知分类中的哪一类时,我们可以依据统计学的理论看它所处的位置特征,衡量它周围邻居的权重,而把它归为(或分配)到权重更大的那一类。这就是K近邻算法的核心思想。
knn三要素是!
- K值的选取
- 距离度量的方式
- 分类决策规划
计算公式有哪些?
我们看到,K近邻算法的核心在于找到实例点的邻居,这个时候,问题就接踵而至了,如何找到邻居,邻居的判定标准是什么,用什么来度量。这一系列问题便是下面要讲的距离度量表示法。
明可夫斯基距离(Minkowski distance)
明氏距离是欧氏距离的推广,是对多个距离度量公式的概括性的表述:
d
i
s
t
(
x
i
,
x
j
)
=
(
∑
l
=
1
n
∣
x
i
(
l
)
−
x
j
(
l
)
∣
p
)
1
p
dist(x_i,x_j) = (\sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}|^p)^{\frac{1}{p}}
dist(xi,xj)=(l=1∑n∣xi(l)−xj(l)∣p)p1
当p=1,“明可夫斯基距离”变成“曼哈顿距离”
当p=2,“明可夫斯基距离”变成“欧几里得距离”
当p=∞,“明可夫斯基距离”变成“切比雪夫距离”
曼哈顿距离(Manhattan Distance)
当p=1时,称为曼哈顿距离,即: L 1 ( x i , x j ) = ∑ l = 1 n ∣ x i ( l ) − x j ( l ) ∣ L_1(x_i,x_j) = \sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}| L1(xi,xj)=l=1∑n∣xi(l)−xj(l)∣ 曼哈顿距离:两个点在标准坐标系上的绝对轴距总和,在2维空间中的计算公式为: d = ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ d={|x_1-x_2|+|y_1-y_2|} d=∣x1−x2∣+∣y1−y2∣
欧式距离 (Eucledian Distance)
当p=2时,称为欧式距离,即 :
L
2
(
x
i
,
x
j
)
=
(
∑
l
=
1
n
∣
x
i
(
l
)
−
x
j
(
l
)
∣
p
)
1
2
L_2(x_i,x_j) = (\sum_{l=1}^{n}|x_i^{(l)}-x_j^{(l)}|^p)^{\frac{1}{2}}
L2(xi,xj)=(l=1∑n∣xi(l)−xj(l)∣p)21
欧几里得距离:两个点之间的距离,也即通常情况下,我们所计算的距离,n维空间中的欧式距离的计算公式为:
d
=
(
x
1
−
x
2
)
2
+
(
y
1
−
y
2
)
2
+
.
.
.
+
(
y
n
1
−
y
n
2
)
2
d=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2+...+(y_{n_1}-y_{n_2})^2}
d=(x1−x2)2+(y1−y2)2+...+(yn1−yn2)2
切比雪夫距离
当p=∞时,它是各个坐标距离的最大值,计算公式为: L ∞ ( x i , x j ) = m a x l ∣ x i ( l ) − x i ( l ) ∣ L_∞(x_i,x_j)=max_l|x^{(l)}_i−x^{(l)}_i| L∞(xi,xj)=maxl∣xi(l)−xi(l)∣切比雪夫距离:各坐标数值差的最大值,在2维空间中的计算公式为: d = m a x ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) d=max({|x_1-x_2|,|y_1-y_2|)} d=max(∣x1−x2∣,∣y1−y2∣)
余弦相似度
余弦相似度衡量的是2个向量间的夹角大小,通过夹角的余弦值表示结果,因此2个向量的余弦相似度为:
cos
θ
=
A
⋅
B
∣
∣
A
∣
∣
∗
∣
∣
B
∣
∣
(
1
)
\cos\theta=\frac{A\cdot B}{||A|| *||B||} \qquad(1)
cosθ=∣∣A∣∣∗∣∣B∣∣A⋅B(1)分子为向量A与向量B的点乘,分母为二者各自的L2相乘,即将所有维度值的平方相加后开方。
余弦相似度的取值为[-1,1],值越大表示越相似。
例如:计算向量 ( x 1 , y 1 ) % (x_1,y_1) (x1,y1)与向量 ( x 2 , y 2 ) % (x_2,y_2) (x2,y2)的余弦相似度。
- 一个三角形三条边的长度关系为: c 2 = a 2 + b 2 − 2 a b cos θ ( 2 ) c^2=a^2+b^2-2ab\cos\theta \qquad(2) c2=a2+b2−2abcosθ(2)
- 其中: a 2 = x 1 2 + y 1 2 b 2 = x 2 2 + y 2 2 c 2 = ( x 1 − x 2 ) 2 + ( y 1 − y 2 ) 2 ( 3 ) \begin{aligned} a^2&=x_1^2+y_1^2 \\ b^2&=x_2^2+y_2^2 \\ c^2&=(x_1-x_2)^2+(y_1-y_2)^2 \end{aligned} \qquad(3) a2b2c2=x12+y12=x22+y22=(x1−x2)2+(y1−y2)2(3)
- 于是,我们可以得到:
cos
θ
=
a
2
+
b
2
−
c
2
2
a
b
=
2
(
x
1
x
2
+
y
1
y
2
)
2
x
1
2
+
y
1
2
x
2
2
+
y
2
2
=
A
⋅
B
∣
∣
A
∣
∣
∗
∣
∣
B
∣
∣
(
4
)
\begin{aligned} \cos\theta &=\frac{a^2+b^2-c^2}{2ab}\\ &=\frac{2(x_1x_2+y_1y_2)}{2\sqrt{x_1^2+y_1^2}\sqrt{x_2^2+y_2^2}}\\ &=\frac{A\cdot B}{||A|| *||B||} \end{aligned}\qquad(4)
cosθ=2aba2+b2−c2=2x12+y12x22+y222(x1x2+y1y2)=∣∣A∣∣∗∣∣B∣∣A⋅B(4)其中A与B表达向量
(
x
1
,
y
1
)
% (x_1,y_1)
(x1,y1)与向量
(
x
2
,
y
2
)
% (x_2,y_2)
(x2,y2)。
分子为A与B的点乘,分母为二者各自的L2相乘,即将所有维度值的平方相加后开方。
汉明距离
两个等长字符串s1与s2之间的汉明距离定义为将其中一个变为另外一个所需要作的最小替换次数。
- 例如字符串“1111”与“1001”之间的汉明距离为2。
应用:信息编码(为了增强容错性,应使得编码间的最小汉明距离尽可能大)。
杰卡德相似系数
两个集合A和B的交集元素在A,B的并集中所占的比例,称为两个集合的杰卡德相似系数,用符号J(A,B)表示。杰卡德相似系数是衡量两个集合的相似度一种指标。
杰卡德相似系数公式为:
J
(
A
,
B
)
=
∣
A
⋂
B
∣
∣
A
⋃
B
∣
J(A,B)=\frac{|A\bigcap B|}{|A\bigcup B|}
J(A,B)=∣A⋃B∣∣A⋂B∣与杰卡德相似系数相反的概念是杰卡德距离:
J
δ
(
A
,
B
)
=
1
−
J
(
A
,
B
)
=
∣
A
⋂
B
∣
−
∣
A
⋃
B
∣
∣
A
⋃
B
∣
J_\delta(A,B)=1-J(A,B)=\frac{|A\bigcap B|-|A\bigcup B|}{|A\bigcup B|}
Jδ(A,B)=1−J(A,B)=∣A⋃B∣∣A⋂B∣−∣A⋃B∣
皮尔逊系数
在统计学中,皮尔逊积矩相关系数用于度量两个变量X和Y之间的相关(线性相关),其值介于-1与1之间。通常情况下通过以下取值范围判断变量的相关强度:
0.8-1.0 极强相关 0.6-0.8 强相关 0.4-0.6 中等程度相关 0.2-0.4 弱相关 0.0-0.2 极弱相关或无相关
简单说来,各种“距离”的应用场景简单概括为:
-
空间:欧氏距离;
-
路径:曼哈顿距离;
-
国际象棋国王:切比雪夫距离。
玩过国际象棋的朋友或许知道,国王走一步能够移动到相邻的8个方格中的任意一个。那么国王从格子 ( x 1 , y 1 ) % (x_1,y_1) (x1,y1)走到格子 ( x 2 , y 2 ) % (x_2,y_2) (x2,y2)最少需要多少步?。你会发现最少步数总是 m a x ( ∣ x 2 − x 1 ∣ , ∣ y 2 − y 1 ∣ ) % max( | x_2-x_1 | , | y_2-y_1 | ) max(∣x2−x1∣,∣y2−y1∣) 步 。有一种类似的一种距离度量方法叫切比雪夫距离。 -
向量差距:夹角余弦;
-
编码差别:汉明距离;
-
集合近似度:杰卡德类似系数与距离;
-
相关:相关系数与相关距离,皮尔逊系数
knn中K值是如何选择的?
- 如果选择较小的K值,就相当于用较小的领域中的训练实例进行预测,“学习”近似误差会减小,只有与输入实例较近或相似的训练实例才会对预测结果起作用,与此同时带来的问题是“学习”的估计误差会增大,换句话说,K值的减小就意味着整体模型变得复杂,容易发生过拟合;
- 如果选择较大的K值,就相当于用较大领域中的训练实例进行预测,其优点是可以减少学习的估计误差,但缺点是学习的近似误差会增大。这时候,与输入实例较远(不相似的)训练实例也会对预测器作用,使预测发生错误,且K值的增大就意味着整体的模型变得简单(容易欠拟合)。
- K=N,则完全不足取,因为此时无论输入实例是什么,都只是简单的预测它属于在训练实例中最多的累,模型过于简单,忽略了训练实例中大量有用信息。
在实际应用中,K值一般取一个比较小的数值,例如采用交叉验证法(简单来说,就是一部分样本做训练集,一部分做测试集)来选择最优的K值。
KNN决策规则?
在KNN分类应用中一般采用多数表决法戒者加权多数表决法。
***KNN分类预测规则 ***
- 多数表决法(图一):每个邻近样本的权重是一样的,也就是说最终 预测的结果为出现类别最多的那个类,比如右图中蓝色圆圈 的最终类别为红色;
- 加权多数表决法(图二):每个邻近样本的权重是丌一样的,一般情 况下采用权重和距离成反比的方式来计算,也就是说最终预 测结果是出现权重最大的那个类别;比如下图中,假设三个 红色点到待预测样本点的距离均为2,两个黄色点到待预测样 本点距离为1,那么蓝色圆圈的最终类别为黄色。
KNN回归预测规则
- 平均值法:每个邻近样本的权重是一样的,也就是说最终预测 的结果为所有邻近样本的目标属性值的均值;比如右图中,蓝色 圆圈的最终预测值为:2.6;
- 加权平均值法:每个邻近样本的权重是丌一样的,一般情况下 采用权重和距离成反比的方式来计算,也就是说在计算均值的时 候迚行加权操作;比如右图中,假设上面三个点到待预测样本点 的距离均为2,下面两个点到待预测样本点距离为1,那么蓝色圆 圈的最终预测值为:2.43。(权重分别为: 1/7和2/7)
KNN算法描述
- 1)计算测试数据与各个训练数据之间的距离;
- 2)按照距离的递增关系进行排序;
- 3)选取距离最小的K个点;
- 4)确定前K个点所在类别的出现频率;
- 5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。
代码如下:
import numpy as np
distance = [] # 保存所有点与样本点的距离
idx = 0 # 索引
k = 3 # K值
data_x = np.array([[6,1],[2,0],[1,2],[5,6],[6,2],[1,8],[1,5],[9,5],[8,5]]) #所有数据
data_y = ['a','v','v','b','b','j','k','v','j'] #所有数据对应的标签
x = np.array([2,2]) #待测样本
# 循环遍历数据
for data in data_x:
# 计算所有点与样本点的距离
distance_data_x = np.linalg.norm(data-x)
# 保存所有点与样本点的距离 以及对应样本的下标 是一个tuple(距离,下标)
distance.append((distance_data_x,idx))
idx +=1
label_y = [] # 保存 前k个距离 对应样本的 label值
# 对所有的距离排序,选取前K个 来预测待测样本
for c,idx in sorted(distance)[:k]:
# 通过下标获取前k个距离对应样本的 label值
labe = data_y[idx]
# 保存前k个距离对应样本的 label值
label_y.append(labe)
count = 0 # 统计label出现的次数
label_to_count = {} # 保存形式 标签:出现次数
y_class = None # 待测样本的预测值 label
# 循环遍历 前k个距离 对应样本的 label值
for num in label_y:
# 判断哪个类别出现的次数
if num in label_to_count:
label_to_count[num] = label_to_count[num] + 1
if label_to_count[num] > count:
y = label_to_count[num]
y_class = num
else:
label_to_count[num] = 1
print(y_class)
KNN优点or缺点
近邻分类器的优点:
- 原理和实现简单,特别适用于大类别问题。
- 性能好:当训练样本数较多时,其错误率的上下界都是在一倍到两倍贝叶斯决策方法的错误率范围内。从这点来说最近邻法是优良的,因此它是模式识别重要方法之一。
近邻分类器的缺点 :
- 由于训练样本数有限,近邻法估计的后验概率往往并不精确,从而导致分类错误率远远大于Bayesian最小错误率。
- 搜索近邻需要遍历每一个样本,计算复杂度较大。
- 需要存储所有样本。
- 受噪声和距离测度的选择影响较大。
KD-Tree的构建!
Kd-树 其实是K-dimension tree的缩写,是对数据点在k维空间中划分的一种数据结构。其实,Kd-树是一种平衡二叉树。
- 假设有六个二维数据点 = {(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},数据点位于二维空间中。为了能有效的找到最近邻,Kd-树采用分而治之的思想,即将整个空间划分为几个小部分。
- 六个二维数据点生成的Kd-树的图为:
- 3D 对应的kd的平面划分图:
二叉查找树:
在介绍Kd-tree的相关算法前,我们先回顾一下二叉查找树(Binary Search Tree)的相关概念和算法。
二叉查找树(Binary Search Tree,BST),是具有如下性质的二叉树:
- 若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树;
例如:图1中是一棵二叉查找树,其满足BST的性质。
-
给定一个1维数据集合,怎样构建一棵BST树呢?根据BST的性质就可以创建,即将数据点一个一个插入到BST树中,插入后的树仍然是BST树,即根结点的左子树中所有结点的值均小于根结点的值,而根结点的右子树中所有结点的值均大于根结点的值。
-
将一个1维数据集用一棵BST树存储后,当我们想要查询某个数据是否位于该数据集合中时,只需要将查询数据与结点值进行比较然后选择对应的子树继续往下查找即可,查找的平均时间复杂度为:O(logN),最坏的情况下是O(N)。
如果我们要处理的对象集合是一个K维空间中的数据集,那么是否也可以构建一棵类似于1维空间中的二叉查找树呢?答案是肯定的,只不过推广到K维空间后,创建二叉树和查询二叉树的算法会有一些相应的变化,这就是下面我们要介绍的Kd-tree算法。
怎么样构建平衡kd树:
对于Kd-tree这样一棵二叉树,我们首先需要确定怎样划分左子树和右子树,即一个K维数据是依据什么被划分到左子树或右子树的。
- 在构造1维BST树时,一个1维数据根据其与树的根结点和中间结点进行大小比较的结果来决定是划分到左子树还是右子树
- 同理,我们也可以按照这样的方式,将一个K维数据与Kd-tree的根结点和中间结点进行比较,只不过不是对K维数据进行整体的比较,而是选择某一个维度 D i % D_i Di,然后比较两个K维数在该维度Di上的大小关系
- 即每次选择一个维度 D i % D_i Di来对K维数据进行划分,相当于用一个垂直于该维度 D i % D_i Di的超平面将K维数据空间一分为二,平面一边的所有K维数据在 D i % D_i Di维度上的值小于平面另一边的所有K维数据对应维度上的值。
- 也就是说,我们每选择一个维度进行如上的划分,就会将K维数据空间划分为两个部分,如果我们继续分别对这两个子K维空间进行如上的划分,又会得到新的子空间,对新的子空间又继续划分,重复以上过程直到每个子空间都不能再划分为止。
KD树中每个节点都是一个向量,和二叉树划分不同的是,kd树每层需要选定向量中 的某一维,然后根据这一维左小右大的方式划分数据。在构建二叉树时,有两个问题需要解决:
(1)选择向量的哪一维进行划分
(2)如何划分数据
解决上述问题的关键是每次选择中位数来进行划分
给定二维数据集合:(2,3), (5,4), (9,6), (4,7), (8,1), (7,2)。左图是Kd-tree对应二维数据集合的一个空间划分,右图是构建的一棵Kd-tree。
- 确定:split域=x。具体是:6个数据点在x,y维度上的数据方差分别为39,28.63,所以在x轴上方差更大,故split域值为x;
- 确定:Node-data = (7,2)。具体是:根据x维上的值将数据排序,6个数据的中值(所谓中值,即中间大小的值)为7,所以Node-data域位数据点(7,2)。这样,该节点的分割超平面就是通过(7,2)并垂直于:split=x轴的直线x=7;
- 确定:左子空间和右子空间。具体是:分割超平面x=7将整个空间分为两部分:x<=7的部分为左子空间,包含3个节点={(2,3),(5,4),(4,7)};另一部分为右子空间,包含2个节点={(9,6),(8,1)};
如上算法所述,kd树的构建是一个递归过程,我们对左子空间和右子空间内的数据重复根节点的过程就可以得到一级子节点(5,4)和(9,6),同时将空间和数据集进一步细分,如此往复直到空间中只包含一个数据点
算法(用kd树的k近邻搜索)
- 输入:已构造的kd树;目标点x;k值;
- 输出:x的最近邻
- 算法过程:
- 构造优先队列L(最大优先队列,距离从小到大的顺序排队)
- 在树中找出包含目标点x的叶结点 从根结点递归访问kd树,若x当前维的坐标小于切分点的坐标,则移动到左子结点,否则移动到右子结点,直到子结点为叶结点
- 将此节点插入队列L如果L长度大于k,则获取并删除队首元素
- 递归地向上回退,在每个结点进行以下操作
- (a) 如果该结点保存的实例点比L队首更近,则将此节点插入队列L,如果L长度大于k,则获取并删除队首元素
- (b) 检查该子结点的父结点的另一子结点对应的区域是否有比L队首更近的点。
- 具体地,检查另一子结点对应的区域是否与以“L队首结点”为球心、以目标点与“L队首结点”间的距离为半径的超球体相交
- 如果相交,可能在另一个子结点对应的区域内存在距离“L队首结点”更近的点,移动到另一个子结点.递归地进行k近邻搜索
- 如果不相交,向上回退
- 当回退到根结点时,搜索结束,最后的L队列中的结点即为x的k近邻点
关于KNN的一些问题
1.在k-means或kNN,我们是用欧氏距离来计算最近的邻居之间的距离。为什么不用曼哈顿距离?
- 答:我们不用曼哈顿距离,因为它只计算水平或垂直距离,有维度的限制。另一方面,欧式距离可用于任何空间的距离计算问题。因为,数据点可以存在于任何空间,欧氏距离是更可行的选择。例如:想象一下国际象棋棋盘,象或车所做的移动是由曼哈顿距离计算的,因为它们是在各自的水平和垂直方向的运动。
2.KD-Tree相比KNN来进行快速图像特征比对的好处在哪里?
- 答:极大的节约了时间成本.点线距离如果 > 最小点,无需回溯上一层,如果<,则再上一层寻找