Spark2.0機器學習系列之8: 聚類(k-means,Bisecting k-means,Streaming k-means)

       在Spark2.0版本中(不是基於RDD API的MLlib),共有四種聚類方法:
     (1)K-means
     (2)Latent Dirichlet allocation (LDA)
     (3)Bisecting k-means(二分k均值算法)
     (4)Gaussian Mixture Model (GMM)。
       基於RDD API的MLLib中,共有六種聚類方法:
     (1)K-means
     (2)Gaussian mixture
     (3)Power iteration clustering (PIC)
     (4)Latent Dirichlet allocation (LDA)**
     (5)Bisecting k-means
     (6)Streaming k-means
       多了Power iteration clustering (PIC)和Streaming k-means兩種。這些方法後面都會進行介紹。
本文將介紹三種:K-means、Bisecting k-means與Streaming k-means。其它方法在我Spark機器學習系列裏面都有介紹。

k-means

       k-means算法是最爲經典的基於劃分的聚類方法,是十大經典數據挖掘算法之一。K-means算法的基本思想是:以空間中k個點爲中心進行聚類,對最靠近他們的對象歸類。通過迭代的方法,逐次更新各聚類中心的值,直至得到最好的聚類結果。
       假設要把樣本集分爲c個類別,算法描述如下:
       (1)適當選擇c個類的初始中心;
       (2)在第k次迭代中,對任意一個樣本,求其到c箇中心的距離,將該樣本歸到距離最短的中心所在的類;
       (3)利用均值等方法更新該類的中心值;
       (4)對於所有的c個聚類中心,如果利用(2)(3)的迭代法更新後,值保持不變,則迭代結束,否則繼續迭代。
       該算法的最大優勢在於簡潔和快速。算法的關鍵在於初始中心的選擇和距離公式。
       Spark MLlib K-means 算法的實現在初始聚類點的選擇上,借鑑了一個叫 K-means||的類 K-means++ 實現。K-means++ 算法在初始點選擇上遵循一個基本原則: 初始聚類中心點相互之間的距離應該儘可能的遠。基本步驟如下:
      第一步,從數據集 X 中隨機選擇一個點作爲第一個初始點。
      第二步,計算數據集中所有點與最新選擇的中心點的距離 D(x)。
      第三步,選擇下一個中心點,使得
                  這裏寫圖片描述最大。
      第四部,重複 (二),(三) 步過程,直到 K 個初始點選擇完成。

import org.apache.spark.sql.SparkSession
import org.apache.spark.ml.clustering.KMeans
import org.apache.log4j.{Level, Logger}

object myClusters {
  def main(args:Array[String]){
    val spark=SparkSession
            .builder()
            .appName("myClusters")
            .master("local[4]")
            .config("spark.sql.warehouse.dir","/home/Spark/spark-warehouse" )
            .getOrCreate();
    val dataset=spark.read.format("libsvm")
                          .load("/home/spark-2.0.0-bin-hadoop2.6/data/mllib/sample_kmeans_data.txt")

    //屏蔽日誌
    Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)

    //訓練kmean模型
    val kmeans=new KMeans()
                    .setK(2)//表示期望的聚類的個數
                    .setMaxIter(100)//表示方法單次運行最大的迭代次數
                    .setSeed(1L)//集羣初始化時的隨機種子
    val model=kmeans.fit(dataset)

    // 評估聚類結果誤差平方和(Sum of the Squared Error,簡稱SSE).
    val SSE=model.computeCost(dataset)
    println(s"within set sum of squared error = $SSE")

    println("Cluster Centers: ")
    model.clusterCenters.foreach(println) 

  }  

}

如何選擇K

       K 的選擇是 K-means 算法的關鍵,computeCost 方法,該方法通過計算所有數據點到其最近的中心點的平方和來評估聚類的效果。一般來說,同樣的迭代次數和算法跑的次數,這個值越小代表聚類的效果越好。但是在實際情況下,我們還要考慮到聚類結果的可解釋性,不能一味的選擇使 computeCost 結果值最小的那個 K。

KMeans優缺點

優點:
      原理比較容易理解,容易實現,並且聚類效果良好,有着廣泛的使用
缺點:
       (1)K-means算法不適用於非球形簇的聚類,而且不同尺寸和密度的類型的簇,也不太適合。
       (2)可能收斂到局部值。

Bisecting k-means(二分K均值算法)

       二分k均值(bisecting k-means)是一種層次聚類方法,算法的主要思想是:首先將所有點作爲一個簇,然後將該簇一分爲二。之後選擇能最大程度降低聚類代價函數(也就是誤差平方和)的簇劃分爲兩個簇。以此進行下去,直到簇的數目等於用戶給定的數目K爲止。
       以上隱含着一個原則是:因爲聚類的誤差平方和能夠衡量聚類性能,該值越小表示數據點月接近於它們的質心,聚類效果就越好。所以我們就需要對誤差平方和最大的簇進行再一次的劃分,因爲誤差平方和越大,表示該簇聚類越不好,越有可能是多個簇被當成一個簇了,所以我們首先需要對這個簇進行劃分。

       bisecting k-means通常比常規K-Means方法運算快一些,也和K-Means聚類方法得到結果有所不同。
    Bisecting k-means is a kind of hierarchical clustering using a divisive (or “top-down”) approach: all observations start in one cluster, and splits are performed recursively as one moves down the hierarchy.
    Bisecting K-means can often be much faster than regular K-means, but it will generally produce a different clustering.
       二分k均值算法的僞代碼如下:

將所有的點看成一個簇
當簇數目小於k時
       對每一個簇:
              計算總誤差
              在給定的簇上面進行k-均值聚類k=2
              計算將該簇一分爲二後的總誤差
       選擇使得誤差最小的那個簇進行劃分操作
//BisectingKMeans和K-Means API基本上是一樣的,參數也是相同的
//模型訓練
val bkmeans=new BisectingKMeans()
                        .setK(2)
                        .setMaxIter(100)
                        .setSeed(1L)
val model=bkmeans.fit(dataset)

//顯示聚類中心    
model.clusterCenters.foreach(println)

//SSE(sum of squared error)結果評估    
val WSSSE=model.computeCost(dataset)
println(s"within set sum of squared error = $WSSSE")

Bisecting k-means優缺點
       同k-means算法一樣,Bisecting k-means算法不適用於非球形簇的聚類,而且不同尺寸和密度的類型的簇,也不太適合。

Streaming k-means 流式k-means

       Streaming k-means仍在Mllib RDD-based API中。
       翻譯參考文獻(1)和(4)。
      在streaming環境中,我們的數據是分批到來的,每一批可能包含許多點(樣本)的數據。標準k-means算法在streaming環境中最簡單的擴展方式是:(a)一開始以隨機位置作爲聚類的中心,因爲這時候我們還沒有看到任何的數據。(b)對於新到的每一批數據點,運用前面k-means算法中的(2)、(3)兩步驟更新中心點。(c)然後我們就可以用更新後的中心點作爲下一批數據更新時的初始中心點,以此反覆,隨着時間持續運行。
      In the streaming setting, our data arrive in batches, with potentially many data points per batch. The simplest extension of the standard k-means algorithm would be to begin with cluster centers — usually random locations, because we haven’t yet seen any data — and for each new batch of data points, perform the same two-step operation described above. Then, we use the new centers to repeat the procedure on the next batch. Above is a movie showing the behavior of this algorithm for two-dimensional data streaming from three clusters that are slowly drifting over time. The centers track the true clusters and adapt to the changes over time.
以一個二維特徵的數據流爲例,下面的動畫展示了這個算法的特點,具有三個中心的數據流在隨着時間緩慢漂移,計算出來的三個聚類中心也隨之發生改變。
這裏寫圖片描述

參考文獻:
(1)Spark document
http://spark.apache.org/docs/latest/mllib-clustering.html#streaming-k-means
(2)Spark 實戰,第 4 部分: 使用 Spark MLlib 做 K-means 聚類分析 王 龍, 軟件開發工程師, IBM,寫的非常詳細,建議閱讀。
http://www.ibm.com/developerworks/cn/opensource/os-cn-spark-practice4/
(3)Bisecting k-means聚類算法實現 http://shiyanjun.cn/archives/1388.html
(4)Introducing streaming k-means in Apache Spark 1.2 by Jeremy Freeman https://databricks.com/blog/2015/01/28/introducing-streaming-k-means-in-spark-1-2.html
(5)Mahout StreamingKMeans algorithm
http://mahout.apache.org/users/clustering/streaming-k-means.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章