最近作了一个数据挖掘的项目,挖掘过程当中用到了K-means聚类方法,可是因为根据行业经验肯定的聚类数过多而且并不必定是咱们获取到数据的真实聚类数,因此,咱们但愿能从数据自身出发去肯定真实的聚类数,也就是对数据而言的最佳聚类数。为此,我查阅了大量资料和博客资源,总结出主流的肯定聚类数k的方法有如下两类。python
1.手肘法
1.1 理论
手肘法的核心指标是SSE(sum of the squared errors,偏差平方和),
其中,Ci是第i个簇,p是Ci中的样本点,mi是Ci的质心(Ci中全部样本的均值),SSE是全部样本的聚类偏差,表明了聚类效果的好坏。app
手肘法的核心思想是:随着聚类数k的增大,样本划分会更加精细,每一个簇的聚合程度会逐渐提升,那么偏差平方和SSE天然会逐渐变小。而且,当k小于真实聚类数时,因为k的增大会大幅增长每一个簇的聚合程度,故SSE的降低幅度会很大,而当k到达真实聚类数时,再增长k所获得的聚合程度回报会迅速变小,因此SSE的降低幅度会骤减,而后随着k值的继续增大而趋于平缓,也就是说SSE和k的关系图是一个手肘的形状,而这个肘部对应的k值就是数据的真实聚类数。固然,这也是该方法被称为手肘法的缘由。
1.2 实践
咱们对预处理后数据.csv 中的数据利用手肘法选取最佳聚类数k。具体作法是让k从1开始取值直到取到你认为合适的上限(通常来讲这个上限不会太大,这里咱们选取上限为8),对每个k值进行聚类而且记下对于的SSE,而后画出k和SSE的关系图(毫无疑问是手肘形),最后选取肘部对应的k做为咱们的最佳聚类数。python实现以下:ide
import pandas as pd from sklearn.cluster import KMeans import matplotlib.pyplot as plt df_features = pd.read_csv(r'D:\XXX.csv',encoding='gbk') # 读入数据 '利用SSE选择k' SSE = [] # 存放每次结果的偏差平方和 for k in range(1,9): estimator = KMeans(n_clusters=k) # 构造聚类器 estimator.fit(df_features[['R','F','M']]) SSE.append(estimator.inertia_) X = range(1,9) plt.xlabel('k') plt.ylabel('SSE') plt.plot(X,SSE,'o-') plt.show()
同时还要考虑类间距离的示例程序以下:code
import pandas as pd from sklearn.cluster import KMeans import matplotlib.pyplot as plt targetdict = {'0': 0.9367807502615454, '2': 0.01246450455836198, '1': 0.02669257211179196, '13': 0.00023912718577193245, '3': 0.006396652219399193, '11': 0.0005679270662083396, '5': 0.002959198923927664, '32': 8.967269466447467e-05, '10': 0.0007173815573157974, '18': 0.00014945449110745777, '4': 0.0032581079061425795, '21': 8.967269466447467e-05, '8': 0.0009863996413092214, '20': 0.00014945449110745777, '7': 0.0012554177253026454, '41': 2.9890898221491557e-05, '12': 0.00044836347332237334, '6': 0.002092362875504409, '94': 2.9890898221491557e-05, '14': 0.00038858167687939025, '16': 0.00029890898221491554, '19': 0.000269018083993424, '72': 5.9781796442983113e-05, '23': 8.967269466447467e-05, '33': 0.00011956359288596623, '15': 0.00020923628755044088, '43': 5.9781796442983113e-05, '44': 2.9890898221491557e-05, '25': 0.00014945449110745777, '9': 0.0008369451502017635, '22': 0.00020923628755044088, '30': 0.00011956359288596623, '111': 2.9890898221491557e-05, '37': 5.9781796442983113e-05, '58': 5.9781796442983113e-05, '47': 2.9890898221491557e-05, '48': 2.9890898221491557e-05, '70': 5.9781796442983113e-05, '28': 5.9781796442983113e-05, '71': 2.9890898221491557e-05, '24': 0.00011956359288596623, '89': 2.9890898221491557e-05, '27': 2.9890898221491557e-05, '138': 2.9890898221491557e-05, '35': 2.9890898221491557e-05, '39': 8.967269466447467e-05, '42': 2.9890898221491557e-05, '348': 2.9890898221491557e-05, '17': 8.967269466447467e-05, '46': 2.9890898221491557e-05, '52': 2.9890898221491557e-05, '64': 2.9890898221491557e-05, '69': 2.9890898221491557e-05, '45': 2.9890898221491557e-05, '54': 5.9781796442983113e-05, '75': 2.9890898221491557e-05, '26': 8.967269466447467e-05, '125': 2.9890898221491557e-05, '29': 0.00011956359288596623, '49': 8.967269466447467e-05, '38': 2.9890898221491557e-05, '109': 2.9890898221491557e-05, '65': 8.967269466447467e-05, '50': 2.9890898221491557e-05, '59': 2.9890898221491557e-05, '101': 2.9890898221491557e-05, '53': 2.9890898221491557e-05, '63': 2.9890898221491557e-05, '95': 2.9890898221491557e-05, '93': 2.9890898221491557e-05} targetmat = [] for k,v in targetdict.items(): num = int(10000 * v) key = int(k) for index in range(num): targetmat.append(key) targetmat = pd.DataFrame(targetmat) targetmat.columns = ["target"] '利用SSE选择k' SSE = [] # 存放每次结果的偏差平方和 classsumlist = [] maxclassnum = 20 for k in range(1,maxclassnum): estimator = KMeans(n_clusters=k) # 构造聚类器 estimator.fit(targetmat[['target']]) SSE.append(estimator.inertia_) #计算类间距离和 classsum = 0.0 centers = estimator.cluster_centers_.tolist() for center1 in centers: for center2 in centers: classsum = classsum + abs(center1[0] - center2[0]) classsumlist.append(classsum) #print(centers) X = range(1,maxclassnum) plt.xlabel('k') plt.ylabel('SSE') plt.plot(X,SSE,'o-') plt.plot(X,classsumlist,'o-') plt.show()
上面这个橙色的线表示类间距离随聚类个数上升变化的趋势
咱们要兼顾类内距离 还要看类间距离 合理选取聚类的个数blog