KMeans評估(如何選擇最佳的k)

2021-03-01 鴻煊的學習筆記

原本準備自己總結一篇關於KMeans評估的文章,發現網上這篇已經總結的很全面了,所以收藏下。如果有其他方法也歡迎留言交流。原文來自微信公眾號:非凡wang咖

在Kmenas算法中,如何確定簇數K值是一個至關重要的問題,為了解決這個問題,通常會選用探索法,即給定不同的k值下,對比某些評估指標的變動情況,進而選擇一個比較合理的k值。本篇文章總結三種常用的k值選擇方法:簇內離差平方和拐點法,輪廓係數法和間隔統計量法)

拐點法

簇內離差平方和拐點法的思想是:在不同的k值下計算簇內離差平方和,然後通過可視化的方法找到「拐點」所對應的k值。隨著簇數量的增加,簇中的樣本量會越來越少,通過可視化方法,重點關注曲線斜率的變化,當斜率由大突然變小時,並且之後的斜率變化緩慢,則認為突然變化的點就是拐點,也就是最佳的k值,因為繼續隨著簇數K的增加,聚類效果不再有大的變化。

接下來我們驗證這個方法,隨機生成三組二元正態分布數據,首先基於該數據繪製散點圖,如下代碼:

np.random.seed(1234)mean1 = [0.5, 0.5]cov1 = [[0.3, 0], [0, 0.3]]x1, y1 = np.random.multivariate_normal(mean1, cov1, 1000).T
mean2 = [0, 8]cov2 = [[0.3, 0], [0, 0.3]]x2, y2 = np.random.multivariate_normal(mean2, cov2, 1000).T
mean3 = [8, 4]cov3 = [[1.5, 0], [0, 1]]x3, y3 = np.random.multivariate_normal(mean3, cov3, 1000).T
plt.scatter(x1, y1)plt.scatter(x2, y2)plt.scatter(x3, y3)plt.show()

如上圖,虛擬出來的數據呈現出三個簇,接下來基於這個虛擬數據,使用拐點法繪製簇的個數與總的簇內離差平方和之間的折線圖,確定最終的k值,代碼如下:

def k_SSE(X, clusters):    """    拐點法    繪製不同的k值和對應總的簇內離差平方和的折線圖    """        K = range(1, clusters+1)        TSSE = []    for k in K:                SSE = []        kmeans = KMeans(n_clusters=k)        kmeans.fit(X)                labels = kmeans.labels_                centers = kmeans.cluster_centers_                for label in set(labels):            SSE.append(np.sum((X.loc[labels == label, ]-centers[label, :])**2))                TSSE.append(np.sum(SSE))
        plt.rcParams['font.sans-serif'] = 'SimHei'    plt.rcParams['axes.unicode_minus'] =False        plt.style.use('ggplot')        plt.plot(K, TSSE, 'b*-')    plt.xlabel('簇的個數')    plt.ylabel('簇內離差平方和之和') plt.show()

X = pd.DataFrame(np.concatenate([np.array([x1, y1]), np.array([x2, y2]), np.array([x3, y3])], axis=1).T)k_SSE(X, 15)

如上圖,當簇的個數為3時,形成了一個明顯的「拐點」,因為K值從1到3時,折線的斜率都比較大,但是k值為4時斜率突然就降低了很多,並且之後的簇對應的斜率都變動很小,所以,合理的k值應該為3,與虛擬數據集的三個簇相吻合。

輪廓係數法

輪廓係數法綜合考慮了簇的密集性和分散性,如果數據集被分割為理想的K個簇,那麼對應的簇內樣本會很密集,而簇間樣本會很分散。其公式如下:

其中,a(i) 是樣本i與同簇內其他樣本點距離的平均值,體現了簇內的密集性;b(i) 是樣本i與其他非同簇樣本點距離的平均值,然後從平均值中挑選出最小值,反映了簇間的分散性。

通過公式可知當S(i)接近於-1時,說明樣本i分配的不合理,需要將其分配到其他簇中;當S(i)近似為0時,說明樣本i落在了模糊地帶,即簇的邊界處;當S(i)近似為1時,說明樣本i的分配是合理的。

接下來我們就看看如何用輪廓係數解決我們的k取值問題,由於輪廓係數計算較複雜,所以我們直接使用sklearn中的metrics中的silhouette_score方法,需要注意的是該方法需要接受的聚類簇數必須大於等於2。代碼如下:
def k_silhouette(X, clusters):    """    輪廓係數法    """    K = range(2, clusters+1)        S = []    for k in K:        kmeans = KMeans(n_clusters=k)        kmeans.fit(X)        labels = kmeans.labels_                S.append(metrics.silhouette_score(X, labels, metric='euclidean'))        plt.rcParams['font.sans-serif'] = 'SimHei'    plt.rcParams['axes.unicode_minus']  =False        plt.style.use('ggplot')        plt.plot(K, S, 'b*-')    plt.xlabel('簇的個數')    plt.ylabel('輪廓係數')    plt.show()

k_silhouette(X, 15)

如上圖,利用之前構造的虛擬數據,繪製了不同K值下對應的輪廓係數圖,當k取值為3時輪廓係數最大,且比較接近於1,說明應該把虛擬數據聚為3類比較合理。

間隔統計量法

2000年Hastie等人提出了間隔統計量法(Gap Statistic方法),該方法可以適用與任何聚類算法,公式如下:

詳情參考地址:

https://blog.csdn.net/baidu_17640849/article/details/70769555

接下來我們構造自定義函數,繪製不同K值對應的間隙統計量折線圖:

def short_pair_wise_D(each_cluster):    """    計算簇內任意倆樣本之間的歐式距離Dk    """    mu = each_cluster.mean(axis=0)    Dk = sum(sum((each_cluster - mu) ** 2 * each_cluster.shape[0]))    return Dk

def compute_Wk(data, classfication_result): """ 計算簇內的Wk值 """ Wk = 0 label_set = set(classfication_result) for label in label_set: each_cluster = data[classfication_result == label, :] Wk = Wk + short_pair_wise_D(each_cluster) / (2.0 * each_cluster.shape[0]) return Wk

def gap_statistic(X, B=10, K=range(1, 11), N_init=10): """ 間隔統計法 計算GAP統計量 """ X = np.array(X) shape = X.shape tops = X.max(axis=0) bots = X.min(axis=0) dists = np.matrix(np.diag(tops - bots)) rands = np.random.random_sample(size=(B, shape[0], shape[1])) for i in range(B): rands[i, :, :] = rands[i, :, :] * dists + bots
gaps = np.zeros(len(K)) Wks = np.zeros(len(K)) Wkbs = np.zeros((len(K), B)) for idxk, k in enumerate(K): k_means = KMeans(n_clusters=k) k_means.fit(X) classfication_result = k_means.labels_ Wks[idxk] = compute_Wk(X, classfication_result)
for i in range(B): Xb = rands[i, :, :] k_means.fit(Xb) classfication_result_b = k_means.labels_ Wkbs[idxk, i] = compute_Wk(Xb, classfication_result_b)
gaps = (np.log(Wkbs)).mean(axis=1) - np.log(Wks) sd_ks = np.std(np.log(Wkbs), axis=1) sk = sd_ks * np.sqrt(1 + 1.0 / B) gapDiff = gaps[:-1] - gaps[1:] + sk[1:]
plt.rcParams['font.sans-serif'] = 'SimHei' plt.rcParams['axes.unicode_minus'] = False plt.style.use('ggplot') plt.bar(np.arange(len(gapDiff)) + 1, gapDiff, color='steelblue') plt.xlabel('簇的個數') plt.ylabel('k的選擇標準') plt.show()

gap_statistic(X)

如上圖,x軸代表了不同的簇數k,y軸代表k值選擇的判斷指標gapDiff,gapDiff首次出現正值時對應的k為3,所以對於虛擬的數據集來說,將其劃分為三個簇是比較合理的。

完整代碼連結:

https://github.com/jpegbert/MachineLearning/tree/master/kmeans/kmeans_evaluation


歡迎關注,一起學習

參考https://blog.csdn.net/baidu_17640849/article/details/70769555

相關焦點

  • 改良的kmeans與K近鄰算法特性分析
    摘要:kmeans算法作為無監督算法的一種,對初始點的選擇比較敏感;而k近鄰作為一種惰性且有監督的算法,對k值和樣本間距離度量方式的選擇也會影響結果。同時很多的學者投入到對kmeans算法本身特性的研究中 [4-5],目前kmeans算法已經成為機器學習,數據挖掘等領域比較重要的方法之一。而k近鄰算法是圖像以及文本分類領域應用比較廣泛的算法之一 [6-7],對k近鄰算法而言,k值的選擇以及樣本間距離的度量方式都會影響到分類的精確度。
  • 數學推導+純 Python 實現機器學習算法:Kmeans 聚類
    下面我們基於numpy按照前述算法流程來實現一個kmeans算法。回顧上述過程,我們可以先思考一下對算法每個流程該如何定義。首先要定義歐式距離計算函數,然後類中心初始化、根據樣本與類中心的歐式距離劃分類別並獲取聚類結果、根據新的聚類結果重新計算類中心點、重新聚類直到滿足停止條件。
  • 教程 | matlab實現kmeans聚類算法
    kmeans聚類算法是一種簡單實用的聚類算法,matlab自帶函數kmeans可直接對數據進行kmeans聚類。
  • 基於matlab的RBFNN的kmeans算法研究
    聚類算法有多種實現方法,其中kmeans算法是基於距離劃分 的方法來實現聚類。本文首先對kmeans算法進行深入的研究和學習,簡單介紹了其思想及其具體操作步驟,因其算法簡單、快速高效 的處理大數據集而被人們廣泛應用。但其初始聚類中心是隨機選擇的,所以結果具有不確定性。利用層次聚類的算法對其進行改進, 使其初始聚類中心穩定,彌補了kmeans算法的缺點。
  • Kmeans中的K值確定*
    上篇文章為大家介紹了我們常用的聚類算法Kmenas算法,也為大家整理了一點小案例,今天為大家繼續分享我們Kmenas算法,對Kmenas算法來說,如何確定簇數K值是一個至關重要的問題,為了解決這個問題,通常會選用探索法,即給定不同的k值下,對比某些評估指標的變動情況,進而選擇一個比較合理的k值,在這我們上篇文章給大家推薦了三種方法(簇內離差平方和拐點法,輪廓係數法和間隔統計量法
  • 【源碼】Kmeans聚類算法(超快速、簡潔的設計方法)
    這是一種超快速MATLAB實現的kmeans聚類算法。
  • 使用K-means 算法進行客戶分類
    在本部分中,你將理解並學習到如何實現K-Means聚類。:選擇集群的數量K。步驟3:選擇K並運行算法選擇K上面描述的算法找到一個特定的預先選擇=KMeans(n_clusters=i, init='k-means++', max_iter= 300, n_init= 10, random_state= 0)  kmeans.fit(X)  wcss.append(kmeans.inertia_)plt.plot(
  • 機器學習之基於sklearn的KMeans聚類
    import sklearn.cluster as sc #導入聚類算法包n_clusters = 3 #質心數設定為3#訓練數據cluster = sc.KMeans(n_clusters=n_clusters, random_state=0).fit(X)y_pred = cluster.labels_ #獲取結果print(y_pred) #列印結果三、基於sklearn的kmeans
  • 你需要的最全面的K-means聚類指南
    這是我們可以利用評估指標的地方。讓我們討論其中的一些,並了解我們如何使用它們來評估簇的質量。a. Inertia回想一下上面介紹的簇的第一個屬性。這就是Inertia評估。Inertia實際上計算簇內所有點到該簇的質心的距離的總和。
  • R語言做K均值聚類的一個簡單小例子
    /k均值聚類是一種比較常用的聚類方法,R語言裡做k均值聚類比較常用的函數是kmeans(),需要輸入3個參數,第一個是聚類用到的數據,第二個是你想將數據聚成幾類k,第三個參數是nstarthttps://www.datanovia.com/en/lessons/k-means-clustering-in-r-algorith-and-practical-examples
  • 如何使用K-Means對用戶進行分群
    所以可以看到,在 K-Means 中有一個重要的環節,那就是如何放置初始質心,初始質心放置的位置不同,聚類的結果很可能不一樣。一個好的初始質心可以避免更多的計算,讓算法收斂穩定且更快。算法的第一步是在 n 個樣本中隨機抽取 K 個對象作為初始聚類中心,在初始的時候可能會生成在一起,導致算法運算慢且不收斂,對於此類問題可以採用 K-means++ 作為優化,其核心就是選擇離已選中心點最遠的點,初始質心相互間離得儘可能遠。如何確定K值?
  • Kmeans聚類算法
    讀取數據並可視化原始數據能夠可視化的儘量可視化,原始數據可視化最大的好處就是非常直觀的看到數據分布,猜到最佳聚類的數目和最後的大致效果。初始化K個質心實踐表明第一步K個質心的選擇好壞直接關係到最終的收斂效果和收斂步數,在初始質心的選擇上面有兩個關鍵因素需要考慮一個是隨機性隨機性是指初始質心的選擇可以有很多種可能,可以是原樣本點,也可以是非原樣本點,一般選擇原樣本點比較好
  • 聚類算法之Kmeans
    一、對於簇心初值敏感問題1、二分kmeans算法:其核心在於二分法。  具體流程:先以所有樣本為一個簇,然後進行kmeans劃分,將一個簇一分為二劃分為兩個簇。然後,再選擇一個簇進行kmeans算法劃分,再次將該簇一分為二,劃分為兩個簇。
  • 數據分析入門系列教程-K-Means原理
    下面我們運行下函數,看看結果如何result, core = self_kmeans(X, 3)colors = ['r', 'g', 'b', 'y', 'c', 'm']fig, ax = plt.subplots()for i in range(3):        points = np.array([X[j] for j in
  • k均值聚類算法原理和(TensorFlow)實現(無師自通)
    k 均值聚類屬於劃分聚類方法,將數據分成 k 個簇,每個簇有一個中心,稱為質心,k 值需要給定。k 均值聚類算法的工作原理如下:隨機選擇 k 個數據點作為初始質心(聚類中心)。將每個數據點劃分給距離最近的質心,衡量兩個樣本數據點的距離有多種不同的方法,最常用的是歐氏距離。重新計算每個簇的質心作為新的聚類中心,使其總的平方距離達到最小。
  • k-means算法
    k-means算法流程1.選擇聚類的個數k(kmeans算法傳遞超參數的時候,只需設置最大的K值)2.任意產生k個聚類,然後確定聚類中心,或者直接生成k個中心。3.對每個點確定其聚類中心點。4.再計算其聚類新中心。5.重複以上步驟直到滿足收斂要求。(通常就是確定的中心點不再改變。)
  • 機器學習之分類算法K-Means介紹與代碼分析(篇四)
    物品傳輸優化使用K-means算法的組合找到無人機最佳發射位置和遺傳算法來解決旅行商的行車路線問題,優化無人機物品傳輸過程。這是關於電信運營商如何將預付費客戶分為充值模式、發送簡訊和瀏覽網站幾個類別的白皮書。對客戶進行分類有助於公司針對特定客戶群制定特定的廣告。球隊狀態分析分析球員的狀態一直都是體育界的一個關鍵要素。隨著競爭越來愈激烈,機器學習在這個領域也扮演著至關重要的角色。
  • 機器學習之確定最佳聚類數目的10種方法
    ,然後聚類數目從2遍歷到15(自己設定),然後通過這些指標看分別在聚類數為多少時達到最優,最後選擇指標支持數最多的聚類數目就是最佳聚類數目。library(NbClust)set.seed(1234) #因為method選擇的是kmeans,所以如果不設定種子,每次跑得結果可能不同nb_clust <- NbClust(dataset,  distance = "euclidean",        min.nc=2, max.nc=15, method = "km
  • 使用sklearn評估器構建聚類模型
    常用在市場分析人員對消費者在資料庫中的具體情況分類成不同的消費群體,從而評估出不同類消費人群的一個消費模式和消費習慣。聚類算法在數據分析算法中也可以作為其預處理步驟,例如異常值識別。iris.feature_names得到數據樣本後生成規則:Scaler=MinMaxScaler().fit(irisData)應用Scaler:irisDataScaler=Scaler.transform(irisData)構建模型後訓練模型:即先構建KMeans模型後,利用fit方法將生成的數據規則樣本傳入訓練模型,輸出模型進行查看檢驗kmeans
  • R語言之實現K-mean聚類算法
    利用R語言的K均值聚類函數kmeans(),進行聚類,首先我們介紹下kmeans()的構成官方的解釋查看代碼:?kmeans如圖:我們主要用的參數是:X:我們要用來聚類的數據,作為一個矩陣輸入。Centers:我們要聚類的數量,需要自己進行填寫。