肘部法則–Elbow Method
我們知道k-means是以最小化樣本與質點平方誤差作為目標函數,將每個簇的質點與簇內樣本點的平方距離誤差和稱為畸變程度(distortions),那么,對於一個簇,它的畸變程度越低,代表簇內成員越緊密,畸變程度越高,代表簇內結構越松散。 畸變程度會隨着類別的增加而降低,但對於有一定區分度的數據,在達到某個臨界點時畸變程度會得到極大改善,之后緩慢下降,這個臨界點就可以考慮為聚類性能較好的點。
import pandas as pd from sklearn.cluster import KMeans import matplotlib.pyplot as plt df_features = pd.read_csv(r'11111111.csv',encoding='gbk') # 讀入數據 #print(df_features) '利用SSE選擇k' SSE = [] # 存放每次結果的誤差平方和 for k in range(1,9): estimator = KMeans(n_clusters=k) # 構造聚類器 estimator.fit(df_features[['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31','32']]) SSE.append(estimator.inertia_) # estimator.inertia_獲取聚類准則的總和 X = range(1,9) plt.xlabel('k') plt.ylabel('SSE') plt.plot(X,SSE,'o-') plt.show()
如上圖所示,在k=xxxxxx時,畸變程度(y值)得到大幅改善,可以考慮選取k=xxxxx作為聚類數量 顯然,肘部對於的k值為xxxxxx(曲率最高),故對於這個數據集的聚類而言,最佳聚類數應該選xxxxxxxx。
輪廓系數–Silhouette Coefficient
對於一個聚類任務,我們希望得到的簇中,簇內盡量緊密,簇間盡量遠離,輪廓系數便是類的密集與分散程度的評價指標,公式表達如下: s=b−amax(a,b)s=b−amax(a,b) 其中a代表同簇樣本到彼此間距離的均值,b代表樣本到除自身所在簇外的最近簇的樣本的均值,s取值在[-1, 1]之間。 如果s接近1,代表樣本所在簇合理,若s接近-1代表s更應該分到其他簇中。
判斷: 輪廓系數范圍在[-1,1]之間。該值越大,越合理。 si接近1,則說明樣本i聚類合理; si接近-1,則說明樣本i更應該分類到另外的簇; 若si 近似為0,則說明樣本i在兩個簇的邊界上。 所有樣本的s i 的均值稱為聚類結果的輪廓系數,是該聚類是否合理、有效的度量。 使用輪廓系數(silhouette coefficient)來確定,選擇使系數較大所對應的k值
sklearn.metrics.silhouette_score sklearn中有對應的求輪廓系數的API
import numpy as np from sklearn.cluster import KMeans from pylab import * import codecs import matplotlib.pyplot as plt from sklearn.metrics import calinski_harabaz_score import pandas as pd from numpy.random import random from sklearn import preprocessing from sklearn import metrics import operator data = [] labels = [] number1=10 with codecs.open("red_nopca_nolabel.txt", "r") as f: for line in f.readlines(): line1=line.strip() line2 = line1.split(',') x2 = [] for i in range(0,number1): x1=line2[i] x2.append(float(x1)) data.append(x2) x2 = [] #label = line2[number1-1] #labels.append(float(label)) datas = np.array(data) ''' kmeans_model = KMeans(n_clusters=3, random_state=1).fit(datas) labels = kmeans_model.labels_ a = metrics.silhouette_score(datas, labels, metric='euclidean') print(a) ''' silhouette_all=[] for k in range(2,25): kmeans_model = KMeans(n_clusters=k, random_state=1).fit(datas) labels = kmeans_model.labels_ a = metrics.silhouette_score(datas, labels, metric='euclidean') silhouette_all.append(a) #print(a) print('這個是k={}次時的輪廓系數:'.format(k),a) dic={} #存放所有的互信息的鍵值對 mi_num=2 for i in silhouette_all: dic['k={}時輪廓系數'.format(mi_num)]='{}'.format(i) mi_num=mi_num+1 #print(dic) rankdata=sorted(dic.items(),key=operator.itemgetter(1),reverse=True) print(rankdata)
實驗結果部分插圖