加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

K-MEANS聚类算法,K值最优取值

(2018-06-09 15:15:57)
分类: 机器学习
K-means算法是一种典型的无监督学习算法,它有一下几种有点:
1、无需进行模型的训练,因为是无监督学习,所以 省去了训练的步骤,因而效率比较高 。
2、对处理大数据集,该算法保持可伸缩性和高效性
3、当簇接近高斯分布时,它的效果较好。

缺点:
1、在 K-means 算法中 K 是事先给定的,这个 K 值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适;
2、在 K-means 算法中,首先需要根据初始聚类中心来确定一个初始划分,然后对初始划分进行优化。这个初始聚类中心的选择对聚类结果有较大的影响,一旦初始值选择的不好,可能无法得到有效的聚类结果;
3、该算法需要不断地进行样本分类调整,不断地计算调整后的新的聚类中心,因此当数据量非常大时,算法的时间开销是非常大的;
4、若簇中含有异常点,将导致均值偏离严重(即:对噪声和孤立点数据敏感);
5、不适用于发现非凸形状的簇或者大小差别很大的簇。

K值的选择经决定分类是否合理 ,通常来说K值是通过人为自定义的,需要不断地调整K值来达到最优,这样虽然有效,但是效率底下。那么有没有什么方法可以算出最优K值呢。经过翻阅资料,总结出两个常用的方法:
1、手肘法
1.1基本原理:
手肘法的核心指标是SSE(sum of the squared errors,误差平方和),公式为:

其中,Ci是第i个簇,p是Ci中的样本点,mi是Ci的质心(Ci中所有样本的均值),SSE是所有样本的聚类误差,代表了聚类效果的好坏。

手肘法的核心思想是:随着聚类数k的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于真实聚类数时,由于k的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当k到达真实聚类数时,再增加k所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的真实聚类数。当然,这也是该方法被称为手肘法的原因。

1.2 实现代码

我们对数据.csv中的数据利用手肘法选取最佳聚类数k。具体做法是让k从1开始取值直到取到你认为合适的上限(一般来说这个上限不会太大,这里我们选取上限为10),对每一个k值进行聚类并且记下对于的SSE,然后画出k和SSE的关系图(毫无疑问是手肘形),最后选取肘部对应的k作为我们的最佳聚类数。python实现如下:

  1. import pandas as pd  
  2. from sklearn.cluster import KMeans  
  3. import matplotlib.pyplot as plt  
  4.   
  5. df_features pd.read_csv(r'D:\数据.csv',encoding='gbk'读入数据  
  6. '利用SSE选择k'  
  7. SSE []  存放每次结果的误差平方和  
  8. for in range(1,11):  
  9.     estimator KMeans(n_clusters=k)  构造聚类器  
  10.     estimator.fit(df_features[['R','F','M']])  
  11.     SSE.append(estimator.inertia_)  
  12. range(1,11 
  13. plt.xlabel('k' 
  14. plt.ylabel('SSE' 
  15. plt.plot(X,SSE,'o-' 
  16. plt.show() 
画出的k与SSE的关系图:(k为横坐标,sse为纵坐标)

http://s10/mw690/002aDypHzy7l7P6NhH369&690

我们可以看到当k=4时,sse趋于平稳,即我们选择4作为最佳k值

2、轮廓系数

2.1 基本原理

方法的核心指标是轮廓系数(Silhouette Coefficient),某个样本点Xi的轮廓系数定义如下:

                                                            https://img-blog.csdn.net/20180111193714917?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMTU3Mzg1MDE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

其中,a是Xi与同簇的其他样本的平均距离,称为凝聚度,b是Xi与最近簇中所有样本的平均距离,称为分离度。而最近簇的定义是

                                                     https://img-blog.csdn.net/20180111204015193?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMTU3Mzg1MDE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast

其中p是某个簇Ck中的样本。事实上,简单点讲,就是用Xi到某个簇所有样本平均距离作为衡量该点到该簇的距离后,选择离Xi最近的一个簇作为最近簇。

       求出所有样本的轮廓系数后再求平均值就得到了平均轮廓系数。平均轮廓系数的取值范围为[-1,1],且簇内样本的距离越近,簇间样本距离越远,平均轮廓系数越大,聚类效果越好。那么,很自然地,平均轮廓系数最大的k便是最佳聚类数。

2.2 代码实现

我们同样使用2.1中的数据集,同样考虑k等于1到8的情况,对于每个k值进行聚类并且求出相应的轮廓系数,然后做出k和轮廓系数的关系图,选取轮廓系数取值最大的k作为我们最佳聚类系数,python实现如下:

  1. import pandas as pd  
  2. from sklearn.cluster import KMeans  
  3. from sklearn.metrics import silhouette_score  
  4. import matplotlib.pyplot as plt  
  5.   
  6. df_features pd.read_csv(r'C:\Users\61087\Desktop\项目\爬虫数据\预处理后数据.csv',encoding='gbk' 
  7. Scores []  存放轮廓系数  
  8. for in range(2,11):  
  9.     estimator KMeans(n_clusters=k)  构造聚类器  
  10.     estimator.fit(df_features[['R','F','M']])  
  11.     Scores.append(silhouette_score(df_features[['R','F','M']],estimator.labels_,metric='euclidean'))  
  12. range(2,11 
  13. plt.xlabel('k' 
  14. plt.ylabel('轮廓系数' 
  15. plt.plot(X,Scores,'o-' 
  16. plt.show()
得到聚类数k与轮廓系数的关系图如下:

上图可以看到,轮廓系数最大的k值是2,这表示我们的最佳聚类数为2。但是从k和SSE的手肘图可以看出,当k取2时,SSE非常大,所以这是一个不太合理的聚类数,我们退而求其次,考虑轮廓系数第二大的k值4,这时候SSE已经处于一个较低的水平,因此最佳聚类系数应该取4而不是2。

       但是,k=2时轮廓系数最大,聚类效果应该非常好,那为什么SSE会这么大呢?从定义上看,轮廓系数大,不一定是凝聚度a(样本与同簇的其他样本的平均距离)小,而可能是b和a都很大的情况下b比a大得多,这么一来,a也是有可能取得比较大的。a值大,表示样本与同簇的其他样本的平均距离就大,簇的紧凑程度就弱,那么簇内样本离质心的距离也大,从而导致SSE较大。所以,虽然轮廓系数引入了分离度b而限制了聚类划分的程度,但是同样会引来最优结果的SSE比较大的问题,这一点也是值得注意的。

总结

从以上两个例子可以看出,轮廓系数法确定出的最优k值不一定是最优的,有时候还需要根据SSE去辅助选取,这样一来相对手肘法就显得有点累赘。因此,如果没有特殊情况的话,建议优先考虑手肘法。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有