KNN 分类算法原理介绍:
简介:K最近邻(k-Nearest Neighbor,KNN)分类算法是最简单的机器学习算法。KNN算法的指导思想是“近朱者赤,近墨者黑”,由你的邻居来推断出你的类别。采用测量不同特征值之间的距离方法进行分类,主要思想:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
实现原理:为判断未知样本的类别,以所有已知类别的样本作为参照,计算未知样本与所有已知样本的距离,从中选取与未知样本距离最近的K个已知样本,根据少数服从多数的投票法则(majority-voting),将未知样本与K个最邻近样本中所属类别占比较多的归为一类。
我们先举个栗子:
以上图为例,如何来判断绿色圆应该属于哪一类,红色三角形或者蓝色四边形?
- 若选择 k = 1 k = 1 k=1 时,由图可知,距离圆形最近的是红色三角形因此绿色圆形将会被判定为属于红色三角形
- 若选择 k = 3 k = 3 k=3 时,由于红色三角形所占比例为 2 3 \frac{2}{3} 32,因此绿色圆将会被判定为属于红色三角形,
- 若选择 k = 5 k = 5 k=5 时,由于蓝色四边形三角形所占比例为 3 5 \frac{3}{5} 53,因此绿色圆将会被判定为属于蓝色四边形
简例小结:
- 通过上面简单的KNN分类实例中,可知所选择的邻居都是已经正确分类的对象,该方法在定类决策上只依据最邻近的一个或者几个样本的类别来决定待分样本所属的类别。
- 由于KNN方法主要靠周围有限的邻近的样本,而不是靠判别类域的方法来确定所属类别的,因此对于类域的交叉或重叠较多的待分样本集来说,KNN方法较其他方法更为适合。
- 以上的三种情况也可以说成是1-近邻方法、3-近邻方法、5-近邻方法······· 当然,k 还可以取更大的值,当样本足够多,且样本类别的分布足够好的话,那么K值越大,划分的类别就越正确。也可以知道KNN中的 k 表示的就是划分数据时,所取相似样本的个数。
- 需要注意的问题:当 k = 1 时,其抗干扰能力就较差,因为假如样本中出现了某种偶然的类别,那么新的数据很有可能被分错。
- 如果在样本有限的情况下,KNN算法的误判概率和距离的具体测度方法就有了直接关系。即用何种方式判定哪些数据与新数据近邻。不同的样本选择不同的距离测量函数,这能够提高分类的正确率。
算法的实现步骤
-
计算距离:给定测试对象,计算它与训练集中的每个对象的距离。 通常使用的距离函数有:欧氏距离、余弦距离、汉明距离、曼哈顿距离等,一般选欧氏距离作为距离度量,但是这是只适用于连续变量。在文本分类这种非连续变量情况下,汉明距离可以用来作为度量。
通常情况下,KNN可以采用Euclidean(欧几里得)、Manhattan(曼哈顿)、Mahalanobis(马氏距离)等距离用于计算。如果运用一些特殊的算法来计算度量的话,K近邻分类精度可显著提高,如运用大边缘最近邻法或者近邻成分分析法。
距离量度:样本空间内的两个点之间的距离量度表示两个样本点之间的相似程度,距离越短,表示相似程度越高;反之,相似程度越低。在此只以欧氏距离和曼哈顿距离计算平面上两点 A ( x 1 , y 2 ) 、 B ( x 2 , y 2 ) A(x_{1},y_{2})、B(x_{2},y_{2}) A(x1,y2)、B(x2,y2) 间的距离为例:
2. 找邻居:圈定距离最近的 k 个训练对象,作为测试对象的近邻。对于一个需要预测的输入向量x,我们只需要在训练数据集中寻找k个与向量x最近的向量的集合,根据给定的距离量度方法(一般情况下使用欧氏距离)在训练集T中找出与x最相近的k个样本点,并将这 k 个样本点所表示的集合记为N_k(x);
3. 做分类:根据 k 个近邻归属的主要类别,来对测试对象分类;即根据 k 个近邻中的大部分样本所属的类别来决定待分类样本该属于哪个分类。其中K值的确定对拟合结果有着重要的影响,k
值选的太大易引起欠拟合,太小容易过拟合,需交叉验证确定K值。
其中类别的判定方法:
简单投票法:少数服从多数,近邻中哪个类别的点最多就分为该类。 根据如下所示的多数投票的原则确定实例x所属的类别y:
加权投票法:根据距离的远近,对近邻的投票进行加权,距离越近则权重越大(权重为距离平方的倒数)
机器学习中的(硬/软)投票:https://blog.csdn.net/rocling/article/details/93634499
KNN分类算法的不足:
- 当加入某些类别的样本容量很大,而其他类样本容量很小。即已知的样本数量不均衡,有可能当输入一个和小容量类相同的的新样本时,该样本的K个近邻中,大容量类的样本占多数,从而导致误分类。
解决方法:针对此种情况可以采用加权的方法,即和该样本距离小的近邻所对应的权值越大,将权值纳入分类的参考依据。 - 分类时需要先计算待分类样本和全体已知样本的距离,才能求得所需的K近邻点,计算量较大,尤其是样本数量较多时。
解决方法:针对这种情况可以事先对已知样本点进行处理,去除对分类作用不大的样本,特别注意这种处理步骤仅适用于样本容量较大的情况,如果在原始样本数量较少时采用这种处理,反而会增加误分类的概率。
KNN算法中常见问题
-
k 值设定为多大?
k太小,分类结果易受噪声的影响;k太大,近邻中又可能包含太多的其它类别的点。(对距离加权,可以降低k值设定的影响),k值通常是采用交叉检验来确定(以k=1为基准),经验规则:k一般低于训练样本数的平方根。具体解释如下:
-
类别如何判定最合适?
投票法没有考虑近邻的距离的远近,距离更近的近邻也许更应该决定最终的分类,所以加权投票法更恰当一些。在训练集中,有些样本可能是更值得依赖的。,可以给不同的样本施加不同的权重,加强依赖样本的权重,降低不可信赖样本的影响。 -
如何选择合适的距离衡量?
高维度对距离衡量的影响:众所周知当变量数越多,欧式距离的区分能力就越差;变量值域对距离的影响:值域越大的变量常常会在距离计算中占据主导作用,因此应先对变量进行标准化。
K 最近邻分类算法的实现
Step 1: 新建一个 KNN.py 脚本文件,其中主要功能:生成简单数据库和实现 KNN 分类算法
首先,生成一个简单数据库
# create a dataset which contains 6 samples with 3 classes
def createDataSet():
# create a matrix: each row as a sample
group = array([[1.0, 0.9], [1.0, 1.0], [0.1, 0.2], [0.0, 0.1],[-1.0,-3.0],[-0.9,-0.3.1]])
labels = ['A', 'A', 'B', 'B','C','C'] # four samples and three classes
return group, labels
实现 KNN 算法分类的函数
# classify using kNN
def kNNClassify(newInput, dataSet, labels, k):
numSamples = dataSet.shape[0] # shape[0] stands for the num of row
## step 1: calculate Euclidean distance
# tile(A, reps): Construct an array by repeating A reps times
# the following copy numSamples rows for dataSet
diff = tile(newInput, (numSamples, 1)) - dataSet # Subtract element-wise
squaredDiff = diff ** 2 # squared for the subtract
squaredDist = sum(squaredDiff, axis = 1) # sum is performed by row
distance = squaredDist ** 0.5
## step 2: sort the distance
# argsort() returns the indices that would sort an array in a ascending order
sortedDistIndices = argsort(distance)
classCount = {} # define a dictionary (can be append element)
for i in range(k):
## step 3: choose the min k distance
voteLabel = labels[sortedDistIndices[i]]
## step 4: count the times labels occur
# when the key voteLabel is not in dictionary classCount, get()
# will return 0
classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
## step 5: the max voted class will return
maxCount = 0
for key, value in classCount.items():
if value > maxCount:
maxCount = value
maxIndex = key
return maxIndex
保存为 KNN.py 脚本文件,保存至 site-packages (C:\Users\Edward\anaconda3\Lib\site-packages),供后续的调用
Step 2: 调用 KNN 算法,在命令行中输入以下命令:
In [ ]: from numpy import *
import kNN
dataSet, labels = kNN.createDataSet()
testX = array([1.2, 1.0])
k = 1
outputLabel = kNN.kNNClassify(testX, dataSet, labels, 4)
print ("Your input is:", testX, "and classified to class: ", outputLabel)
testX = array([0.1, 0.3])
outputLabel = kNN.kNNClassify(testX, dataSet, labels, 4)
print ("Your input is:", testX, "and classified to class: ", outputLabel)
testX = array([-0.9,-3])
outputLabel = kNN.kNNClassify(testX,dataSet,labels,4)
print("Your input is", testX, "and classified to class: ",outputLabel)
测试结果:
Out[ ]: Your input is: [1.2 1. ] and classified to class: A
Your input is: [0.1 0.3] and classified to class: B
Your input is [-0.9 -3. ] and classified to class: C
KNN算法的简单应用——回归分析
在 scikit-learn 中,内置了若干个玩具数据集(Toy Datasets),以及一些 API 可以自己动手生成一些数据集。使用scikit-learn的make_regression生成数据集来进行实验,演示KNN算法在回归分析中的效果
import matplotlib.pyplot as plt # 导入画图工具
import numpy as np # 导入数组工具
from sklearn.neighbors import KNeighborsRegressor # 导入用于回归分析的KNN模型
from sklearn.model_selection import train_test_split # 导入数据集拆分工具
from sklearn.datasets.samples_generator import make_regression # 导入数据集生成器
from docutils.utils.math.math2html import LineWriter # 生成样本数为200,分类数为2的数据集
X,Y=make_regression(n_samples=100,n_features=1,n_informative=1,noise=50,random_state=8)
# 将生成的数据集进行可视化
# plt.scatter(X,Y,s=80, c='orange', cmap=plt.cm.spring, edgecolors='k')
# plt.show()
reg = KNeighborsRegressor(n_neighbors=5)
reg.fit(X,Y)
# 将预测结果用图像进行可视化
z = np.linspace(-3,3,200).reshape(-1,1)
plt.scatter(X,Y,c='orange',edgecolor='k')
plt.plot(z,reg.predict(z),c='k',Linewidth=3)
plt.title("KNN Regressor")
plt.show()
执行程序,如下图所示为测试结果:
参考链接:
《机器学习算法与Python实践之(一)k近邻(KNN)》:https://blog.csdn.net/iteye_12028/article/details/82550970
《机器学习之KNN最邻近分类算法》:https://blog.csdn.net/pengjunlee/article/details/82713047
参考书籍:《深入浅出 Python 机器学习》