顧名思義,k均值聚類是一種對數據進行聚類的技術,即將數據分割成指定數量的幾個類,揭示數據的內在性質及規律。
我們知道,在機器學習中,有三種不同的學習模式:監督學習、無監督學習和強化學習:
- 監督學習,也稱為有導師學習,網絡輸入包括數據和相應的輸出標簽信息。例如,在 MNIST 數據集中,手寫數字的每個圖像都有一個標簽,代表圖片中的數字值。
- 強化學習,也稱為評價學習,不給網絡提供期望的輸出,但空間會提供給出一個獎懲的反饋,當輸出正確時,給網絡獎勵,當輸出錯誤時就懲罰網絡。
- 無監督學習,也稱為無導師學習,在網絡的輸入中沒有相應的輸出標簽信息,網絡接收輸入,但既沒有提供期望的輸出,也沒有提供來自環境的獎勵,神經網絡要在這種情況下學習輸入數據中的隱藏結構。無監督學習非常有用,因為現存的大多數數據是沒有標簽的,這種方法可以用於諸如模式識別、特征提取、數據聚類和降維等任務。
k 均值聚類是一種無監督學習方法。
還記得哈利波特故事中的分院帽嗎?那就是聚類,將新學生(無標簽)分成四類:格蘭芬多、拉文克拉、赫奇帕奇和斯特萊林。
人是非常擅長分類的,聚類算法試圖讓計算機也具備這種類似的能力,聚類技術很多,例如層次法、貝葉斯法和划分法。k 均值聚類屬於划分聚類方法,將數據分成 k 個簇,每個簇有一個中心,稱為質心,k 值需要給定。
k 均值聚類算法的工作原理如下:
- 隨機選擇 k 個數據點作為初始質心(聚類中心)。
- 將每個數據點划分給距離最近的質心,衡量兩個樣本數據點的距離有多種不同的方法,最常用的是歐氏距離。
- 重新計算每個簇的質心作為新的聚類中心,使其總的平方距離達到最小。
- 重復第 2 步和第 3 步,直到收斂。
准備工作
使用 TensorFlow 的 Estimator 類 KmeansClustering 來實現 k 均值聚類,具體實現可參考https://github.com/tensorflow/tensorflow/blob/r1.3/tensorflow/contrib/learn/python/learn/estimators/kmeans.py,可以直接進行 k 均值聚類和推理。根據 TensorFlow 文檔,KmeansClustering 類對象可以使用以下__init__方法進行實例化:
TensorFlow 文檔對這些參數的定義如下:
- num_clusters:要訓練的簇數。
- model_dir:保存模型結果和日志文件的目錄。
- initial_clusters:指定如何對簇初始化,取值請參閱 clustering_ops.kmeans。
- distance_metric:聚類的距離度量方式,取值請參閱 clustering_ops.kmeans。
- random_seed:Python 中的整數類型,用於初始化質心的偽隨機序列發生器的種子。
- use_mini_batch:如果為 true,運行算法時分批處理數據,否則一次使用全部數據集。
- mini_batch_steps_per_iteration:經過指定步數后將計算的簇中心更新回原數據。更多詳細信息參見 clustering_ops.py。
- kmeans_plus_plus_num_retries:對於在 kmeans++ 方法初始化過程中采樣的每個點,該參數指定在選擇最優值之前從當前分布中提取的附加點數。如果指定了負值,則使用試探法對 O(log(num_to_sample)) 個附加點進行抽樣。
- relative_tolerance:相對誤差,在每一輪迭代之間若損失函數的變化小於這個值則停止計算。有一點要注意就是,如果將 use_mini_batch 設置為 True,程序可能無法正常工作。
配置:請參閱 Estimator。
TensorFlow 支持將歐氏距離和余弦距離作為質心的度量,KmeansClustering 類提供了多種交互方法。在這里使用 fit()、clusters() 和 predict_clusters_idx() 方法:

根據 TensorFlow 文檔描述,需要給 fit() 提供 input_fn() 函數,cluster 方法返回簇質心,predict_cluster_idx 方法返回得到簇的索引。
具體做法
- 與以前一樣,從加載必要的模塊開始,這里需要 TensorFlow、NumPy 和 Matplotlib。這里使用鳶尾花卉數據集,該數據集分為三類,每類都是指一種鳶尾花卉,每類有 50 個實例。可以從https://archive.ics.uci.edu/ml/datasets/iris上下載 .csv 文件,也可以使用 sklearn 庫的數據集模塊(scikit-learn)來加載數據:
- 加載數據集:
- 繪出數據集查看一下:
- 可以看到數據中並沒有明顯可見的分類。定義 input_fn 來給 fit() 方法輸入數據,函數返回一個 TensorFlow 常量,用來指定x的值和維度,類型為 float。
- 開始使用 KmeansClustering 類,分為 3 類,設置 num_clusters=3。通常情況下事先並不知道最優的聚類數量,在這種情況下,常用的方法是采用肘部法則(elbow method)來估計聚類數量:
- 使用 clusters() 方法找到這些簇,使用 predict_cluster_idx() 方法為每個輸入點計算分配的簇索引:
- 對創建的簇進行可視化操作,創建一個包裝函數 ScatterPlot,它將每個點的 X 和 Y 值與每個數據點的簇和簇索引對應起來:
其中“+”號代表三個簇的質心。
解讀分析
上面的案例中使用 TensorFlow Estimator 的 k 均值聚類進行了聚類,這里是提前知道簇的數目,因此設置 num_clusters=3。但是在大多數情況下,數據沒有標簽,我們也不知道有多少簇存在,這時候可以使用肘部法則確定簇的最佳數量。
肘部法則選擇簇數量的原則是減少距離的平方誤差和(SSE),隨着簇數量 k 的增加,SSE 是逐漸減小的,直到 SSE=0,當k等於數據點的數量時,每個點都是自己的簇。
這里想要的是一個較小的 k 值,而且 SSE 也較小。在 TensorFlow 中,可以使用 KmeansClustering 類中定義的 score() 方法計算 SSE,該方法返回所有樣本點距最近簇的距離之和:

對於鳶尾花卉數據,如果針對不同的 k 值繪制 SSE,能夠看到 k=3 時,SSE 的變化是最大的;之后變化趨勢減小,因此肘部 k 值可設置為 3:

k 均值聚類因其簡單、快速、強大而被廣泛應用,當然它也有不足之處,最大的不足就是用戶必須指定簇的數量;其次,算法不保證全局最優;再次,對異常值非常敏感。