1、KNN算法概论
kNN算法的核心思想是:如果一个样本在特征空间中的k个最相邻的样本中的大多数属于某一个类别,则该样本也属于这个类别,并具有这个类别上样本的特性。该方法在确定分类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。 K 的一般取值有 3, 5, 7。
2、KNN算法详解
KNN是通过测量不同特征值之间的距离进行分类。它的的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。K通常是不大于20的整数。KNN算法中,所选择的邻居都是已经正确分类的对象。该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
下面通过一个简单的例子说明一下:如下图,绿色圆 要被决定赋予哪个类,是红色三角形还是蓝色四方形?如果K=3,由于红色三角形所占比例为2/3,绿色圆将被赋予红色三角形那个类,如果K=5,由于蓝色四方形比例为3/5,因此绿色圆被赋予蓝色四方形类, 算法就是这么简单粗暴感人,但是不少场景确实非常有效,后边我们会有实例说明。
KNN 具体的数学体现就是测算邻近k 个点的距离, 这里将会列出三个个常用的距离公式,但是在一定应用场景下,需要实验去验证确认哪一个距离公式是最佳的。
a.欧式距离(即从小学学到大学的那个距离公式)
b.曼哈顿距离(得名于曼哈顿街区整齐排列的区块距离,有兴趣可以网上搜索一下)
c.明氏距离(p =2 时不就是欧式距离?这算是欧式距离在不同应用场景的优化公式)
3、KNN算法优缺点
KNN算法的优点:
1)简单、有效。
2)重新训练的代价较低
3)计算时间和空间线性于训练集的规模(在一些场合不算太大)。
4)由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
5)该算法比较适用于样本容量比较大的类域的自动分类,而那些样本容量较小的类域采用这种算法比较容易产生误分。
KNN算法缺点:
1)KNN算法是懒散学习方法(lazy learning,基本上不学习),一些积极学习的算法要快很多。
2)类别评分不是规格化的(不像概率评分)。
3)输出的可解释性不强,例如决策树的可解释性较强。
4)该算法在分类时有个主要的不足是,当样本不平衡时,如一个类的样本容量很大,而其他类样本容量很小时,有可能导致当输入一个新样本时,该样本的K个邻居中大容量类的样本占多数。该算法只计算“最近的”邻居样本,某一类的样本数量很大,那么或者这类样本并不接近目标样本,或者这类样本很靠近目标样本。无论怎样,数量并不能影响运行结果。可以采用权值的方法(和该样本距离小的邻居权值大)来改进。
5)计算量较大。目前常用的解决方法是事先对已知样本点进行剪辑,事先去除对分类作用不大的样本。
当然,此时谈优缺点可能会让你觉得一脸懵逼,接下来且看一个实例,再回头思考上面讲的优缺点也许会有不一样的感悟!
4、KNN 实现
首先形式化的说一下流程:
1)准备数据(鸢尾花数据集,具体数据请自行print查看理解,网上很多解释,就不赘述了)
2)创建KNeighborsClassifier对象
3)调用fit函数
4)调用predict函数进行预测
#! /usr/bin/python
# _*_ coding: utf-8 _*_
__author__ = 'Jeffery'
__date__ = '2018/3/31 8:38'
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
np.random.seed(0)
iris = datasets.load_iris()
iris_x = iris.data # 150*4
iris_y = iris.target # 150
indices = np.random.permutation(len(iris_x)) # 产生 0-149 的随机index
# 后十个作为训练集, 其余作为测试集
iris_x_train = iris_x[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_x_test = iris_x[indices[-10:]]
iris_y_test = iris_y[indices[-10:]]
# print('iris_x_train:', iris_x_train)
# print('iris_y_train:', iris_y_train)
knn = KNeighborsClassifier() # 创建一个knn 分类器
knn.fit(iris_x_train, iris_y_train) # 给分类器填充 训练数据
iris_y_predict = knn.predict(iris_x_test) # 使用分类器knn 对训练集 进行预测, 返回预测结果
probability = knn.predict_proba(iris_x_test) # # 使用分类器knn 对训练集 进行预测每个类型概率
score = knn.score(iris_x_test, iris_y_test, sample_weight=None) # 计算模型准确率
print('预测结果iris_y_predict = ', iris_y_predict)
# print('实际结果iris_y_test = ', iris_y_test)
# 输出准确率计算结果
print('Accuracy:', score)
print('probility:', probability)
运行结果为:10个测试集中, 9个预测正确, 1个预测错误, 准确率90%。在这个例子中这个准确率已经算高了,因为样本本身就不多,所以我们基本可以不做其他优化。
5、KNN 优化
但是,如果数据量大的时候, 准确率又不太高,这时候我们一定要学会 优化。 怎么优化呢?具体的这里就不做了,但是就KNN 而言,优化方法有以下方式:
1、改变 k 的取值,别告诉我你还不知道 k 应该放在哪,在代码中我也确实没有写 k 的值,因为我使用的是默认参数 5 。
你不妨试试3 试试7 ,看看效果如何
2、而且你会发现 KNeighborsClassifier()中还有很多参数,比如 algorithm,, 默认参数是 auto , 它会尝试去寻找一种最佳算法。
3、合理设计一下训练集和测试集的比例,一半遵循 2:8 原则吧,合理发挥。
4、换一种算法,因为也许最合适的并不是你眼前的它,而是另一个它。不妨参考scikit-learn官方图:
---------------------------------------------------简陋分割线---------------------------------------------------
今天在网上偶遇网友绘制了一张中文版本的scikit-learn的算法索引图,贴在这里共需要的人参考一下: