K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
KNN方法虽然从原理上也依赖于极限定理,但在类别决策时,只与极少量的相邻样本有关。由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
K 近邻算法使用的模型实际上对应于对特征空间的划分。K 值的选择,距离度量和分类决策规则是该算法的三个基本要素:
1.K 值的选择会对算法的结果产生重大影响。K值较小意味着只有与输入实例较近的训练实例才会对预测结果起作用,但容易发生过拟合;如果 K 值较大,优点是可以减少学习的估计误差,但缺点是学习的近似误差增大,这时与输入实例较远的训练实例也会对预测起作用,使预测发生错误。在实际应用中,K 值一般选择一个较小的数值,通常采用交叉验证的方法来选择最优的 K 值。随着训练实例数目趋向于无穷和 K=1 时,误差率不会超过贝叶斯误差率的2倍,如果K也趋向于无穷,则误差率趋向于贝叶斯误差率。
2.该算法中的分类决策规则往往是多数表决,即由输入实例的 K 个最临近的训练实例中的多数类决定输入实例的类别
3.距离度量一般采用 Lp 距离,当p=2时,即为欧氏距离,在度量之前,应该将每个属性的值规范化,这样有助于防止具有较大初始值域的属性比具有较小初始值域的属性的权重过大。
以上是摘自百度百科的一些概念,以下是我个人见解.
KNN是一种分类方法,所谓KNN就是在训练样本数据集中取距离最近的前K项数据,并将他们之中出现最多次数的标签即认为是待预测数据的标签.
我们分析KNN算法的优缺点,
优点一:算法思想简单而有效,KNN算法的思路可以说得上是非常简单了,但是很有效,我对MNIST数据集上使用K值为20的KNN算法,预测的正确率几乎100%.有什么优点能比算法的有效性更重要呢?
优点二:该算法对有outlier(离群值)的数据也有效.
缺点一:庞大的计算量与空间占用,为了提高准确性,所有的机器学习算法大多要求较高的训练样本以支持算法的正确率,KNN也是如此,由于需要对所有训练样本计算带预测与之的距离,这将耗费较高的时间成本和空间成本.
缺点二:对于训练数据集的依赖性.训练数据集的质量会影响KNN算法的正确率,当数据集数量趋近于无穷,KNN的正确性趋近于100%,但是我们的训练数据一定是有限的,甚至可能是不均匀的,这些会影响KNN算法的正确性.当然,大多数机器学习算法都依赖训练数据集的质量.
此外,该有两个点需要说明,一个是为了防止各维度数据对结果的影响不均匀(例如A维度的差值是100,B维度的差值是0.01,A维度对结果的影响程度明显远高于B维度,但是在事实上A,B维度应该是相同的),我们可以对所有维度的距离进行归一化处理,使其取值范围相同,这样可以消除维度差值数量级差异的问题.
二是距离的测量,我们常用的是欧式距离,即两点之间的直线距离,对距离的测量还有曼哈顿距离,名氏距离,切比雪夫距离等,这些距离有着各自的意义和计算方式,可根据问题的性质选择.此外,如果各个维度因素真的对结果的影响是不同的,你也可以自己构造距离的计算方式.
以下附KNN算法在python语言上的实现代码及对MNIST数据集使用KNN算法的结果,MNIST数据集是一个手写数字的灰度值矩阵的数据集,其数据为28*28的灰度值矩阵,标签为0-9的是个数字.
# -*- coding: utf-8 -*-
# @Time : 2018/10/27 16:45
# @Author : Zy
# @Software: PyCharm
import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
xdata = mnist.train.images
ydata = mnist.train.labels
xd = mnist.test.images
yd = mnist.test.labels
xb, yb = mnist.test.next_batch(50)
# 该方法用于统计数组中出现的所有元素及其数量
def element_num(narry):
tu = sorted([(np.sum(narry == i), i) for i in set(narry.flat)])
return tu
# 该方法用于获取numpy数组中出现次数最多的元素及其数量
# 该方法返回一个元组,元组第一位表示数量,第二位表示元素
def get_max_num_element(narry):
tu = element_num(narry)
return tu[-1]
class KNN(object):
# sdata和slabel表示训练数据及训练标签
# adata表示带预测数据
# K_num表示k值,
# 即取前k项距离最大的训练数据的标签
# 作为待预测数据标签的参考条件
def __init__(self, sdata, slabel, adata=None, K_num=20):
self.source_data = sdata
self.source_label = slabel
self.aim_data = adata
self.K_num = K_num
# 获取标记数据集合
# 获取待预测数据
def set_aim_data(self, data):
self.aim_data = data
# 数据预处理 如归一化 本例子中不需要这个步骤
# 计算距离数组
def distance(self):
sdata = self.source_data
slabel = self.source_label
adata = self.aim_data
adistance = np.empty((len(adata), len(sdata)))
for ai in range(len(adata)):
aitem = adata[ai]
for si in range(len(sdata)):
sitem = sdata[si]
adistance[ai][si] \
= (np.square(aitem - sitem)) \
.sum()
return adistance, slabel
# 排序,少数服从多数分类
def prediction(self):
dis, label = knn.distance()
ydi = 0
pre_labels = np.array([])
for i in dis:
ind = np.argsort(i)
order_dis_list = i[ind[0:self.K_num]]
order_label_list = label[ind[self.K_num]]
pre_label = get_max_num_element(order_label_list)[1]
pre_labels = np.append(pre_labels, pre_label)
ydi += 1
return pre_labels
# 给出实验结果
knn = KNN(xdata, ydata)
knn.set_aim_data(xd[0:10])
pre_labels = knn.prediction()
real_labels = yd[0:10]
print(pre_labels)
print(real_labels)