所谓聚类算法是指将一堆没有标签的数据自动划分成几类的方法,这个方法要保证同一类的数据有相似的特征,比如这样的数据:
聚类是无监督算法中最基础的一类,而K-Means Cluster算法又是聚类中最简单实用的一个。
它是一个循环迭代的算法:
- 假定我们要对N个样本观测做聚类,要求聚为K类,首先选择K个点作为初始中心点;
- 接下来,按照距离初始中心点最小的原则,把所有观测分到各中心点所在的类中;
- 每类中有若干个观测,计算K个类中所有样本点的均值,作为第二次迭代的K个中心点;
- 然后根据这个中心重复第2、3步,直到收敛(中心点不再改变或达到指定的迭代次数),聚类过程结束。
K-Means算法有个很著名的解释,叫做牧师-村民模型:
有四个牧师去郊区布道,一开始牧师们随意选了几个布道点,并且把这几个布道点的情况公告给了郊区所有的居民,于是每个居民到离自己家最近的布道点去听课。
听课之后,大家觉得距离太远了,于是每个牧师统计了一下自己的课上所有的居民的地址,搬到了所有地址的中心地带,并且在海报上更新了自己的布道点的位置。
牧师每一次移动不可能离所有人都更近,有的人发现A牧师移动以后自己还不如去B牧师处听课更近,于是每个居民又去了离自己最近的布道点……
就这样,牧师每个礼拜更新自己的位置,居民根据自己的情况选择布道点,最终稳定了下来。
K-Means算法的特点是类别的个数是人为给定的,如果让机器自己去找类别的个数,它不适用。
K-Means的一个重要的假设是:数据之间的相似度可以使用”距离“度量,距离越小,两个数据相似度越高。当然这个”距离“有很多种,最最常见的是欧式距离(体现数值上的绝对差异),除此之外还有余弦距离(体现方向上的相对差异)
这里看下伪代码大概长这样:
function K-Means(输入数据,中心点个数K)`` ``获取输入数据的维度Dim和个数N`` ``随机生成K个Dim维的点`` ``while``(算法未收敛)`` ``对N个点:计算每个点属于哪一类。`` ``对于K个中心点:`` ``1``,找出所有属于自己这一类的所有数据点`` ``2``,把自己的坐标修改为这些数据点的中心点坐标`` ``end`` ``输出结果:``end
关于K-Means这里有几个关键问题:
- 初始中心点怎么确定
- K值怎么确定
- 如何评价算法是否收敛
- 算法不收敛怎么办
- 能不能给每个点设置权重
问题1:初始中心点怎么确定
方法有很多,最粗暴的方式就是随便选K个点,然后等待算法在循环中自己慢慢收敛(不过这样有可能找到的是局部最优而不是全局最优)
再譬如先随便选个点作为第1个初始中心C1,接下来计算所有样本点与C1的距离,距离最大的被选为下一个中心C2,直到选完K个中心。这个算法叫做K-Means++,可以理解为K-Means的改进版,它可以能有效地解决初始中心的选取问题,但无法解决离群点问题。
或者初始化的时候,不妨先估计一下数据的中心在哪里,数据的尺度有多大,总的而言还是要多尝试。
问题2:K值怎么确定
首先我们了解一个概念:目标函数。
数据给分成不同的簇,目标是同一个簇中的差异小,不同簇之间的差异大,这个目标怎么用数学语言描述呢?我们一般用误差平方和作为目标函数,记为SSE。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mrtY8vy-1673366027097)(null)]
其中C表示聚类中心,如果x属于Ci这个簇,则计算两者的欧式距离,将所有样本点到其中心点距离算出来,并加总,就是K-Means的目标函数。实现同一个簇中的样本差异小,就是最小化SSE。
容易知道,K设置得越大,样本划分得就越细,每个簇的聚合程度就越高。极限情况下,K足够大,每个点都是一类,当然这样分类就没有意义了。
确定K值有一个主流方法叫“手肘法”。
我们从一个比较小的K,譬如K=2开始尝试
- K每增大一个单位,就会大幅增加每个簇的聚合程度,这时SSE的下降幅度会很大;
- 到了某个阶段,再增加K所得到的聚合程度回报会迅速变小,SSE的下降幅度也会减小;
- K继续增大,SSE的变化会趋于平缓。
大概这个感觉:
因为SSE和K的关系图就像是手肘的形状,而肘部对应的K值就被认为是数据的真实聚类数。这里我们可以取4作为K的值。
当然,很多时候聚类的簇数量是比较主观的,下图所示,我们聚成3类或聚成2类都可。
问题3、如何评价算法是否收敛
看代价函数**
**
问题4、算法不收敛怎么办
我也不懂(-。-)
问题5、能不能给每个点设置权重
先回答:可以。
首先明确一个问题:为什么要设置权重?
设置权重一般发生在两种情况下:
1,数据集中有大量的重复点,而且数据量比较大计算非常的烧CPU;
2,数据点之间的重要程度不一样,某些点我们认为更重要,就可以为其分配高权重来影响聚类结果。
总结
K-Means优点在于原理简单,容易实现,聚类效果好。
当然,也有一些缺点:
- K值、初始点的选取不好确定;
- 得到的结果只是局部最优;
- 受离群值影响大。
附代码实现
因为K-Means思路很明确,自己手撸也是可以的,不过也有很成熟的现成方案,比如sklearn中就有算法包,直接调即可
# 导入算法包
import pandas as pd
from sklearn.cluster import KMeans
# 读文件数据
data=pd.read_excel("kmeans.xlsx")
# 瞅一眼数据
data
# 设定训练集
train_x=data.iloc[0:10,1:4]
# 建模预测
kmeans = KMeans(n_clusters=3)#n_clusters=3即指定划分为3个类型
kmeans.fit(train_x)#模型训练
y_kmeans = kmeans.predict(train_x)#模型预测
# 查看聚类结果
y_kmeans