【机器学习】Kmeans聚类
寫在篇前
??Kmeans算法是一種經典的聚類算法,屬于無監督學習的范疇。所謂聚類,即指對于給定的一個樣本集,按照樣本之間的距離大小,將樣本集劃分為K個簇,且讓簇內的點盡量緊密的連在一起,而讓簇間的距離盡量的大。
優點:
- 原理簡單
- 速度快
- 對大數據集有比較好的伸縮性
缺點:
- 需要指定聚類數量K
- 對異常值敏感
- 對初始值敏感
原理概述
算法流程
?????????????????????????以下描述基于 Lloyd’s 算法
評價準則
??The k-means algorithm divides a set of N samples X into K disjoint clusters C, each described by the mean μj\mu_jμj? of the samples in the cluster. The means are commonly called the cluster “centroids”; note that they are not, in general, points from X, although they live in the same space. The K-means algorithm aims to choose centroids that minimise the inertia, or within-cluster sum of squared criterion:
E=∑i=1k∑x∈Ci∣∣x?μi∣∣22E = \sum\limits_{i=1}^k\sum\limits_{x \in C_i} ||x-\mu_i||_2^2 E=i=1∑k?x∈Ci?∑?∣∣x?μi?∣∣22?
attention, μj\mu_jμj? is just the so-called centroids:
μi=1∣Ci∣∑x∈Cix\mu_i = \frac{1}{|C_i|}\sum\limits_{x \in C_i}x μi?=∣Ci?∣1?x∈Ci?∑?x
??值得注意的是:
-
Inertia假設聚類是凸的和各向同性的(convex and isotropic),但它對細長簇或具有不規則形狀數據聚類不佳;
-
Inertia不是標準化的度量標準:我們只知道較低的值更好,零是最佳的;
算法改進
Kmeans ++
?
??k個初始化的質心的位置選擇對最后的聚類結果和運行時間都有很大的影響,因此需要選擇合適的k個質心。K-Means++算法就是對K-Means隨機初始化質心的方法的優化:
-
從輸入的數據點集合中隨機選擇一個點作為第一個聚類中心\mu_1
-
對于數據集中的每一個點x_i,計算它與已選擇的聚類中心中最近聚類中心的距離
D(xi)=arg  min∣∣xi?μr∣∣22    r=1,2,...kselectedD(x_i) = arg\;min||x_i- \mu_r||2^2\;\;r=1,2,...k{selected} D(xi?)=argmin∣∣xi??μr?∣∣22r=1,2,...kselected -
選擇一個新的數據點作為新的聚類中心,選擇的原則是:D(x)較大的點,被選取作為聚類中心的概率較大
-
重復b和c直到選擇出k個聚類質心
-
利用這k個質心來作為初始化質心去運行標準的K-Means算法
?
elkan
?
??在傳統的K-Means算法中,我們在每輪迭代時,要計算所有的樣本點到所有的質心的距離,這樣會比較的耗時。elkan K-Means算法就是從這塊入手加以改進。它的目標是減少不必要的距離的計算。elkan K-Means利用了兩邊之和大于等于第三邊,以及兩邊之差小于第三邊的三角形性質,來減少距離的計算。利用上邊的兩個規律,elkan K-Means比起傳統的K-Means迭代速度有很大的提高。但是如果我們的樣本的特征是稀疏的,有缺失值的話,這個方法就不使用了,此時某些距離無法計算,則不能使用該算法。
?
mini-batch
?
?MiniBatch-KMeans是KMeans算法的一種變體,它使用mini-batch來減少計算時間,同時仍試圖優化相同的目標函數。mini-batch是輸入數據集的子集,在每次訓練迭代中隨機采樣。它大大減少收斂到局部最優值所需的計算量,并達到大致相同的效果。
算法實現
??在本篇主要借助sklearn包提供的接口來實現kmeans算法,具體的實現當然我們可以直接看源碼啦~首先看一下構造函數:
def __init__(self,n_clusters=8, # 即理論部分的k值init='k-means++', # 質心初始化方法n_init=10, # 質心初始化次數,最后結果取結果最好的一個max_iter=300, # 最大迭代次數tol=1e-4, # 容忍度,即kmeans運行準則收斂的條件precompute_distances='auto', # 是否需要提前計算距離,并將其放入內存verbose=0, # 冗長模式,深入看源碼你會發現和操作系統底層有關,個人認為與算法本身無關random_state=None, # 實際上是種子,改參數會傳入check_random_state()函數copy_x=True, # 當并行計算時,必須為True,為數據建立copyn_jobs=1, # 并行計算進程數,-1時表示占滿cpualgorithm='auto' # ‘auto’, ‘full’, ‘elkan’, 其中 'full’表示用EM方式實現,即傳統的kmeans算法計算距離)??上面這些參數可以一一對應到上面講的理論部分,為了進一步了解我們繼續深入,看看一個Kmeans對象有哪些屬性和方法,同樣直接看代碼:
#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery'import numpy as np from sklearn.cluster import KMeansdata = np.random.rand(100, 3) # 生成一個隨機數據,shape(100, 3) estimator = KMeans(n_clusters=3,init='k-means++',n_init=10,max_iter=300,tol=1e-4,precompute_distances='auto', verbose=0,random_state=None,copy_x=False,n_jobs=1,algorithm='auto') # 對于非稀疏數據,會選擇elkan算法estimator.fit(data) # 聚類# --------------------屬性------------------------- # 獲取estimator構造函數中設置的屬性 print('n_clusters:', estimator.n_clusters) print('init:', estimator.init) print('max_iter:', estimator.max_iter) print('tol:', estimator.tol) print('precompute_distances:', estimator.precompute_distances) print('verbose:', estimator.verbose) print('random_state:', estimator.random_state) print('copy_x:', estimator.copy_x) print('n_jobs:', estimator.n_jobs) print('algorithm:', estimator.algorithm) print('n_init:', estimator.n_init)# 其他重要屬性 print('n_iter_:', estimator.n_iter_) # 實際迭代次數 print('cluster_centers_:', estimator.cluster_centers_) # 獲取聚類中心點結果 print('inertia_:', estimator.inertia_) # 獲取聚類準則的總和,越小越好 print('labels_:', estimator.labels_) # 獲取聚類標簽結果 # --------------------函數------------------------- print('get_params:', estimator.get_params(deep=True)) # 與set_params()相對# 這里的介紹先不講 fit()、transform()、fit_transform()、fit_predict()、predict()、score()等函數 # 這些函數放在案例里面案例
??這個示例來源于官網,這個示例旨在說明k-means的一些不合適的場景:在前三個圖中,輸入數據不符合k-means所產生的一些隱含假設,結果產生了不希望的聚類結果;在最后一個圖中,k-means返回直觀、合理的簇,盡管大小不均勻。這個示例很簡單,但是一定要充分看到kmeans的應用關鍵,比如k選取的重要性、聚類各向異性數據的局限性
#! /usr/bin/python # _*_ coding: utf-8 _*_ __author__ = 'Jeffery' __date__ = '2018/11/11 13:55'import numpy as np import matplotlib.pyplot as pltfrom sklearn.cluster import KMeans from sklearn.datasets import make_blobsplt.figure(figsize=(12, 12))n_samples = 1500 random_state = 170 X, y = make_blobs(n_samples=n_samples, random_state=random_state)# Incorrect number of clusters y_pred = KMeans(n_clusters=2, random_state=random_state).fit_predict(X)plt.subplot(221) plt.scatter(X[:, 0], X[:, 1], c=y_pred) plt.title("Incorrect Number of Blobs")# Anisotropicly distributed data transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]] X_aniso = np.dot(X, transformation) y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_aniso)plt.subplot(222) plt.scatter(X_aniso[:, 0], X_aniso[:, 1], c=y_pred) plt.title("Anisotropicly Distributed Blobs")# Different variance X_varied, y_varied = make_blobs(n_samples=n_samples,cluster_std=[1.0, 2.5, 0.5],random_state=random_state) y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(X_varied)plt.subplot(223) plt.scatter(X_varied[:, 0], X_varied[:, 1], c=y_pred) plt.title("Unequal Variance")# Unevenly sized blobs X_filtered = np.vstack((X[y == 0][:500], X[y == 1][:100], X[y == 2][:10])) y_pred = KMeans(n_clusters=3,random_state=random_state).fit_predict(X_filtered)plt.subplot(224) plt.scatter(X_filtered[:, 0], X_filtered[:, 1], c=y_pred) plt.title("Unevenly Sized Blobs")plt.show()寫在篇后
??如果有足夠的時間,K-means將最終收斂,但這可能是局部最優值,這很大程度上取決于質心的初始化;另外,對于大數據集,可以先做PCA等降維處理(PCA請參考降維技術-PCA),然后再進行聚類,以減少計算資源的消耗以及可能的提升聚類效果。
總結
以上是生活随笔為你收集整理的【机器学习】Kmeans聚类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【机器学习】降维技术-PCA
- 下一篇: 【机器学习】层次聚类