1. 程式人生 > >K-Means實戰與調優詳解

K-Means實戰與調優詳解

在K-Means聚類演算法原理(機器學習(25)之K-Means聚類演算法詳解)中對K-Means的原理做了總結,本文來討論用scikit-learn來學習K-Means聚類。重點講述如何選擇合適的k值。

K-Means類概述

在scikit-learn中,包括兩個K-Means的演算法,一個是傳統的K-Means演算法,對應的類是KMeans。另一個是基於取樣的Mini Batch K-Means演算法,對應的類是MiniBatchKMeans。一般來說,使用K-Means的演算法調參是比較簡單的。用KMeans類的話,一般要注意的僅僅就是k值的選擇,即引數n_clusters;如果是用MiniBatchKMeans的話,也僅僅多了需要注意調參的引數batch_size,即我們的Mini Batch的大小。當然KMeans類和MiniBatchKMeans類可以選擇的引數還有不少,但是大多不需要怎麼去調參。

K-Means類主要引數
KMeans類的主要引數有:
1) n_clusters: 即k值,一般需要多試一些值以獲得較好的聚類效果。k值好壞的評估標準在下面會講。
2)max_iter: 最大的迭代次數,一般如果是凸資料集的話可以不管這個值,如果資料集不是凸的,可能很難收斂,此時可以指定最大的迭代次數讓演算法可以及時退出迴圈。
3)n_init:用不同的初始化質心執行演算法的次數。由於K-Means是結果受初始值影響的區域性最優的迭代演算法,因此需要多跑幾次以選擇一個較好的聚類效果,預設是10,一般不需要改。如果你的k值較大,則可以適當增大這個值。
4)init: 即初始值選擇的方式,可以為完全隨機選擇’random’,優化過的’k-means++’或者自己指定初始化的k個質心。一般建議使用預設的’k-means++’。
5)algorithm:有“auto”, “full” or “elkan”三種選擇。”full”就是我們傳統的K-Means演算法, “elkan”是(機器學習(25)之K-Means聚類演算法詳解)原理篇講的elkan K-Means演算法。預設的”auto”則會根據資料值是否是稀疏的,來決定如何選擇”full”和“elkan”。一般資料是稠密的,那麼就是 “elkan”,否則就是”full”。一般來說建議直接用預設的”auto”

MiniBatchKMeans類主要引數

MiniBatchKMeans類的主要引數比KMeans類稍多,主要有:
1) n_clusters: 即k值,和KMeans類的n_clusters意義一樣。
2)max_iter:最大的迭代次數, 和KMeans類的max_iter意義一樣。
3)n_init:用不同的初始化質心執行演算法的次數。這裡和KMeans類意義稍有不同,KMeans類裡的n_init是用同樣的訓練集資料來跑不同的初始化質心從而執行演算法。而MiniBatchKMeans類的n_init則是每次用不一樣的取樣資料集來跑不同的初始化質心執行演算法。
4)batch_size:即用來跑Mini Batch KMeans演算法的取樣集的大小,預設是100.如果發現數據集的類別較多或者噪音點較多,需要增加這個值以達到較好的聚類效果。
5)init: 即初始值選擇的方式,和KMeans類的init意義一樣。
6)init_size: 用來做質心初始值候選的樣本個數,預設是batch_size的3倍,一般用預設值就可以了。
7)reassignment_ratio: 某個類別質心被重新賦值的最大次數比例,這個和max_iter一樣是為了控制演算法執行時間的。這個比例是佔樣本總數的比例,乘以樣本總數就得到了每個類別質心可以重新賦值的次數。如果取值較高的話演算法收斂時間可能會增加,尤其是那些暫時擁有樣本數較少的質心。預設是0.01。如果資料量不是超大的話,比如1w以下,建議使用預設值。如果資料量超過1w,類別又比較多,可能需要適當減少這個比例值。具體要根據訓練集來決定。
8)max_no_improvement:即連續多少個Mini Batch沒有改善聚類效果的話,就停止演算法, 和reassignment_ratio, max_iter一樣是為了控制演算法執行時間的。預設是10.一般用預設值就足夠了。

K值的評估標準
不像監督學習的分類問題和迴歸問題,無監督聚類沒有樣本輸出,也就沒有比較直接的聚類評估方法。但是可以從簇內的稠密程度和簇間的離散程度來評估聚類的效果。常見的方法有輪廓係數Silhouette Coefficient和Calinski-Harabasz Index。個人比較喜歡Calinski-Harabasz Index,這個計算簡單直接,得到的Calinski-Harabasz分數值s越大則聚類效果越好。Calinski-Harabasz分數值s的數學計算公式是:
這裡寫圖片描述
其中m為訓練集樣本數,k為類別數。Bk為類別之間的協方差矩陣,Wk為類別內部資料的協方差矩陣。tr為矩陣的跡。也就是說,類別內部資料的協方差越小越好,類別之間的協方差越大越好,這樣的Calinski-Harabasz分數會高。在scikit-learn中, Calinski-Harabasz Index對應的方法是metrics.calinski_harabaz_score.

應用例項
用一個例項來講解用KMeans類和MiniBatchKMeans類來聚類,觀察在不同的k值下Calinski-Harabasz分數。

首先隨機建立一些二維資料作為訓練集,選擇二維特徵資料,主要是方便視覺化。程式碼如下:

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets.samples_generator import make_blobs

X為樣本特徵,Y為樣本簇類別, 共1000個樣本,每個樣本4個特徵,共4個簇,簇中心在[-1,-1], [0,0],[1,1], [2,2], 簇方差分別為[0.4, 0.2, 0.2]

X, y = make_blobs(n_samples=1000, n_features=2, centers=[[-1,-1], [0,0], [1,1], [2,2]], cluster_std=[0.4, 0.2, 0.2, 0.2], 
                  random_state =9)
plt.scatter(X[:, 0], X[:, 1], marker='o')
plt.show()

這裡寫圖片描述
現在用K-Means聚類方法來做聚類,首先選擇k=2,程式碼如下:

from sklearn.cluster import KMeans
y_pred = KMeans(n_clusters=2, random_state=9).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()

k=2聚類的效果圖輸出如下:
這裡寫圖片描述

看看用Calinski-Harabasz Index評估的聚類分數:

from sklearn import metrics
metrics.calinski_harabaz_score(X, y_pred)  

輸出如下:
3116.1706763322227
現在k=3來看看聚類效果,程式碼如下:

from sklearn.cluster import KMeans
y_pred = KMeans(n_clusters=3, random_state=9).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()  

k=3聚類的效果圖輸出如下:
這裡寫圖片描述
用Calinski-Harabaz Index評估的k=3時候聚類分數:

from sklearn import metrics
metrics.calinski_harabaz_score(X, y_pred)  

輸出如下:
2931.625030199556
可見此時k=3的聚類分數比k=2還差。

現在看看k=4時候的聚類效果:

from sklearn.cluster import KMeans
y_pred = KMeans(n_clusters=4, random_state=9).fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()

k=4聚類的效果圖輸出如下:
這裡寫圖片描述
用Calinski-Harabasz Index評估的k=4時候聚類分數:

from sklearn import metrics
metrics.calinski_harabaz_score(X, y_pred)  

輸出如下:
5924.050613480169
可見k=4的聚類分數比k=2和k=3都要高,這也符合我們的預期,我們的隨機資料集也就是4個簇。當特徵維度大於2,我們無法直接視覺化聚類效果來肉眼觀察時,用Calinski-Harabaz Index評估是一個很實用的方法。

再看看用MiniBatchKMeans的效果,將batch size設定為200. 由於4個簇都是凸的,所以其實batch size的值只要不是非常的小,對聚類的效果影響不大。對於k=2,3,4,5對應的輸出圖為:
這裡寫圖片描述
可見使用MiniBatchKMeans的聚類效果也不錯,當然由於使用Mini Batch的原因,同樣是k=4最優,KMeans類的Calinski-Harabasz Index分數為5924.05,而MiniBatchKMeans的分數稍微低一些,為5921.45。

K-Means小結
優點
1)原理比較簡單,實現也是很容易,收斂速度快。
2)聚類效果較優。
3)演算法的可解釋度比較強。
4)主要需要調參的引數僅僅是簇數k。

缺點
1)K值的選取不好把握
2)對於不是凸的資料集比較難收斂
3)如果各隱含類別的資料不平衡,比如各隱含類別的資料量嚴重失衡,或者各隱含類別的方差不同,則聚類效果不佳。
4) 採用迭代方法,得到的結果只是區域性最優。
5) 對噪音和異常點比較的敏感。