前言
KNN和K-means是不同的哦,小伙伴们不要搞混!
KMeans算法是一种无监督的聚类方法,其工作流程如下:
(1)在一群无标签的数据中,随机选择k个数据作为簇中心(k是人为选择的)
(2)依照某种距离度量,计算除掉这k个数据点的其他数据点到这k个簇中心的距离,将该点划分到离他最近距离的簇中心所属的簇。
(3)计算划分好的簇的质心,使其作为新的簇的中心。
(4)重复(2)到(3)步,直到新的质心与原来的簇的中心相等或者两者的距离小于阈值就停止重新划分
KNN算法是一种监督学习算法,其工作流程如下:
(1)当有新的测试样本出现时,计算其到训练集中每个数据点的距离。
(2)根据距离选择与测试样本距离最小的前k个训练样本。
(3)基于这k个训练样本的类别来划分新样本的类别,通常选择这k个训练样本中出现次数最多的标签作为新样本的类别。
KMeans与KNN的区别:
(1)KMeans是无监督学习算法,KNN是监督学习算法。
(2)KMeans算法的训练过程需要反复迭代的操作(寻找新的质心),但是KNN不需要。
(3)KMeans中的K代表的是簇中心,KNN的K代表的是选择与新测试样本距离最近的前K个训练样本数。
(4)Kmeans只能做分类,而KNN既可以做分类又可以做回归
优点:
- 思想简单、理论成熟
- 既可以用来做分类、也可以用来做回归
- 训练时间复杂度为O(n)
- 输入数据没有前提假设
- 对离群值不敏感
缺点:
- 计算量大
- 没法处理样本不平衡问题
- 需要大量的内存
1. 工作原理
简单的一句话就可以说明KNN的工作原理“近朱者赤,近墨者黑”。
K近邻算法的过程是给定一个训练数据集,对新输入的实例,在训练数据集中找到与该实例最邻近的K个实例, 这K个实例的多数属于某个类, 就把该输入实例分为这个类。
看上面这个图:有两类不同的样本数据, 分别用蓝色的正方形和红色的三角形表示, 而正中间的绿色圆表示待分类数据 下面我们根据K近邻思想给绿色圆点分类:
- 如果k=3, 绿色圆点的最近邻的3个点是2个红色三角和1个蓝色小正方形, 少数服从多数, 基于统计的方法,判定绿色的这个待分类点属于红色三角形一类
- 如果k=5, 绿色圆点的最近邻的5个点是2个红色三角和3个蓝色小正方形,还是少数服从多数, 基于统计的方法,判定这个待分类点属于蓝色的正方形一类
从上面例子可以看出, k近邻算法的思想非常简单, 对新来的点如何归类?【只要找到离它最近的k个实例, 哪个类别最多即可】
所以,KNN的工作原理大致分为三步:
- 计算待分类物体与其他物体之间的距离;
- 统计距离最近的 K 个邻居;
- 对于 K 个最近的邻居,它们属于哪个分类最多,待分类物体就属于哪一类。
但是下面就引出了2个问题:
- 怎么度量距离,锁定最近的K个邻居?(不同的度量方法可能导致K个邻居不同)
- 怎么确定这个K值(K值不同,最后的结果可能不同,像上面那样)
度量距离有下面的五种方式:
- 欧式距离欧氏距离是我们最常用的距离公式,也叫做欧几里得距离。在二维空间中,两点的欧式距离就是:
同理,我们也可以求得两点在n维空间中的距离:
- 曼哈顿距离曼哈顿距离在几何空间中用的比较多。曼哈顿距离等于两个点在坐标系上绝对轴距总和。用公式表示就是:
闵可夫斯基距离闵可夫斯基距离不是一个距离,而是一组距离的定义。对于 n 维空间中的两个点 x(x1,x2,…,xn) 和 y(y1,y2,…,yn) , x 和 y 两点之间的闵可夫斯基距离为:
其中 p 代表空间的维数,当 p=1 时,就是曼哈顿距离;当 p=2 时,就是欧氏距离;当 p→∞时,就是切比雪夫距离。下面给出了不同的p值情况下,与原来Lp距离为1的点的图形,直观感受一下p值的不同,距离的变化:
切比雪夫距离那么切比雪夫距离怎么计算呢?二个点之间的切比雪夫距离就是这两个点坐标数值差的绝对值的最大值,用数学表示就是:max(|x1-y1|,|x2-y2|)。
k值选取不当会造成过拟合和欠拟合两种效果
- 如果 K 值比较小,就相当于未分类物体与它的邻居非常接近才行。这样产生的一个问题就是,如果邻居点是个噪声点,那么未分类物体的分类也会产生误差,这样 KNN 分类就会产生过拟合。就比如下面这个情况(K=1, 绿色点为分类点):
- 如果 K 值比较大,相当于距离过远的点也会对未知物体的分类产生影响,虽然这种情况的好处是鲁棒性强,但是不足也很明显,会产生欠拟合情况,也就是没有把未分类物体真正分类出来。就比如下面这个情况:
工程上,一般采用交叉验证的方式选取K值。
★交叉验证的思路就是,把样本集中的大部分样本作为训练集,剩余的小部分样本用于预测,来验证分类模型的准确性。所以在 KNN 算法中,我们一般会把 K 值选取在较小的范围内,同时在验证集上准确率最高的那一个最终确定作为 K 值。
- 先将数据集D划分为k个大小相似的互斥子集,即D=D1并D2并D3…并Dk,每个子集之间没有交集。
- 然后每次用k-1个子集的并集作为训练集,余下的那个作为测试集,这样得到k组训练和测试集。
- 可以进行k次训练和测试,最终返回的是这k个结果的均值。
- 可以随机使用不同的划分多次,比如10次10折交叉验证 通常把交叉验证法称为“k折交叉验证”(k-fold cross validation),k最常用的取值是10,为10折交叉验证
Python代码实现
#coding:utf-8
from numpy import *
##给出训练数据以及对应的类别
def createDataSet():
group = array([[1.0,2.0],[1.2,0.9],[0.1,0.4],[0.3,0.5]])
labels = ['A','A','B','B']
return group,labels
###通过KNN进行分类
def classify(input,dataSe t,label,k):
dataSize = dataSet.shape[0]
####计算欧式距离
diff = tile(input,(dataSize,1)) - dataSet
sqdiff = diff ** 2
squareDist = sum(sqdiff,axis = 1)###行向量分别相加,从而得到新的一个行向量
dist = squareDist ** 0.5
####曼哈顿距离
# diff = tile(input, (dataSize, 1)) - dataSet
# squarediff = sum(diff, axis = 1)
# dist = squarediff ** 0.5
##对距离进行排序
sortedDistIndex = argsort(dist)##argsort()根据元素的值从大到小对元素进行排序,返回下标
classCount={}
for i in range(k):
voteLabel = label[sortedDistIndex[i]]
###对选取的K个样本所属的类别个数进行统计
classCount[voteLabel] = classCount.get(voteLabel,0) + 1
###选取出现的类别次数最多的类别
maxCount = 0
for key,value in classCount.items():
if value > maxCount:
maxCount = value
classes = key
return classes
Reference
https://blog.youkuaiyun.com/JasonZhangOO/article/details/69053350 https://blog.youkuaiyun.com/weixin_42234472/article/details/85062142