转自:http://blog.csdn.net/lc013/article/details/55810204
参考文章:
简介
k近邻(KNN)是一种基本分类与回归方法。
其思路如下:给一个训练数据集和一个新的实例,在训练数据集中找出与这个新实例最近的 k 个训练实例,然后统计最近的 k 个训练实例中所属类别计数最多的那个类,就是新实例的类。其流程如下所示:
- 计算训练样本和测试样本中每个样本点的距离(常见的距离度量有欧式距离,马氏距离等);
- 对上面所有的距离值进行排序;
- 选前 k 个最小距离的样本;
- 根据这 k 个样本的标签进行投票,得到最后的分类类别;
KNN的特殊情况是 k=1 的情况,称为最近邻算法。对输入的实例点(特征向量) x ,最近邻法将训练数据集中与 x 最近邻点的类作为其类别。
三要素
- k 值的选择
- 距离的度量(常见的距离度量有欧式距离,马氏距离)
- 分类决策规则(多数表决规则)
k值的选择
- k 值越小表明模型越复杂,更加容易过拟合
- 但是 k 值越大,模型越简单,如果 k=N 的时候就表明无论什么点都是训练集中类别最多的那个类
所以一般 k 会取一个较小的值,然后用过交叉验证来确定
这里所谓的交叉验证就是将样本划分一部分出来为预测样本,比如95%训练,5%预测,然后 k 分别取1,2,3,4,5之类的,进行预测,计算最后的分类误差,选择误差最小的 k
距离的度量
KNN算法使用的距离一般是欧式距离,也可以是更一般的
Lp
距离或者马氏距离,其中
Lp
距离定义如下:
这里 xi=(x(1)i,x(2)i,...x(n)i)T,xj=(x(1)j,x(2)j,...,x(n)j)T ,然后 p≥1 。
当
p=2
,称为欧式距离,即
当 p=1 ,称为曼哈顿距离,即
当 p=∞ ,它是各个坐标距离的最大值,即
马氏距离如下定义:
KNN的回归
在找到最近的 k 个实例之后,可以计算这 k 个实例的平均值作为预测值。或者还可以给这 k 个实例添加一个权重再求平均值,这个权重与度量距离成反比(越近权重越大)。
优缺点
优点
- 思想简单,理论成熟,既可以用来做分类也可以用来做回归;
- 可用于非线性分类;
- 训练时间复杂度为 O(n) ;
- 准确度高,对数据没有假设,对异常值不敏感;
缺点
- 计算量大;
- 样本不平衡问题(即有些类别的样本数量很多,而其它样本的数量很少);
- 需要大量的内存;
KD树
KD树是一个二叉树,表示对K维空间的一个划分,可以进行快速检索(那KNN计算的时候不需要对全样本进行距离的计算了)
构造KD树
在k维的空间上循环找子区域的中位数进行划分的过程。
假设现在有K维空间的数据集
T=x1,x2,x3,…xn,xi=a1,a2,a3..ak
- 首先构造根节点,以坐标 a1 的中位数 b 为切分点,将根结点对应的矩形局域划分为两个区域,区域1中 a1<b ,区域2中 a1>b
- 构造叶子节点,分别以上面两个区域中 a2 的中位数作为切分点,再次将他们两两划分,作为深度1的叶子节点,(如果 中位数a2=中位数 ,则 a2 的实例落在切分面)
- 不断重复2的操作,深度为 j 的叶子节点划分的时候,索取的 ai 的 i=j ,直到两个子区域没有实例时停止
KD树的搜索
- 首先从根节点开始递归往下找到包含 x 的叶子节点,每一层都是找对应的 xi
- 将这个叶子节点认为是当前的“近似最近点”
- 递归向上回退,如果以 x 圆心,以“近似最近点”为半径的球与根节点的另一半子区域边界相交,则说明另一半子区域中存在与 x 更近的点,则进入另一个子区域中查找该点并且更新”近似最近点“
- 重复3的步骤,直到另一子区域与球体不相交或者退回根节点
- 最后更新的”近似最近点“与 x 真正的最近点
KD树进行KNN查找
通过KD树的搜索找到与搜索目标最近的点,这样KNN的搜索就可以被限制在空间的局部区域上了,可以大大增加效率。
KD树搜索的复杂度
当实例随机分布的时候,搜索的复杂度为 log(N) , N 为实例的个数,KD树更加适用于实例数量远大于空间维度的KNN搜索,如果实例的空间维度与实例个数差不多时,它的效率基于等于线性扫描。
代码实现
使用sklearn
的简单代码例子:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
最后,在用KNN前你需要考虑到:
- KNN的计算成本很高
- 所有特征应该标准化数量级,否则数量级大的特征在计算距离上会有偏移。
- 在进行KNN前预处理数据,例如去除异常值,噪音等。