K-means聚類最優k值的選取

最近作了一個數據挖掘的項目,挖掘過程當中用到了K-means聚類方法,可是因爲根據行業經驗肯定的聚類數過多而且並不必定是咱們獲取到數據的真實聚類數,因此,咱們但願能從數據自身出發去肯定真實的聚類數,也就是對數據而言的最佳聚類數。爲此,我查閱了大量資料和博客資源,總結出主流的肯定聚類數k的方法有如下兩類。python

1.手肘法
1.1 理論
手肘法的核心指標是SSE(sum of the squared errors,偏差平方和),
K-means聚類最優k值的選取
其中,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()

K-means聚類最優k值的選取

同時還要考慮類間距離的示例程序以下: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()

K-means聚類最優k值的選取
上面這個橙色的線表示類間距離隨聚類個數上升變化的趨勢
咱們要兼顧類內距離 還要看類間距離 合理選取聚類的個數blog

相關文章
相關標籤/搜索