FuzzyKmeans,mahout實現

首先介紹一下,FuzzyKMeans算法的主要思想。

模糊 C 均值聚類(FCM),即衆所周知的模糊 ISODATA,是用隸屬度確定每個數據點屬於某個聚類的程度的一種聚類算法。1973 年,Bezdek 提出了該算法,作爲早期硬 C 均值聚類(HCM)方法的一種改進。FCM 把 n 個向量 xi(i=1,2,...,n)分爲 c 個模糊組,並求每組的聚類中心,使得非相似性指標的價值函數達到最小。FCM 使得每個給定數據點用值在 0,1 間的隸屬度來確定其屬於各個組的程度。與引入模糊劃分相適應,隸屬矩陣 U 允許有取值在 0,1 間的元素。不過,加上歸一化規定,一個數據集的隸屬度的和總等於 1:

那麼,FCM 的價值函數(或目標函數)就是下式一般化形式:

這裏 uij 介於 0,1 間;ci 爲模糊組 i 的聚類中心,dij=||ci-xj||爲第 i 個聚類中心與第 j 個數據點間的歐幾里德距離;且 m (屬於1到無窮) 是一個加權指數。
構造如下新的目標函數,可求得使下式達到最小值的必要條件:其實就是拉格朗日乘子法

對上式所有輸入參量求導,使上式達到最小的必要條件爲:

 

由上述兩個必要條件,模糊 C 均值聚類算法是一個簡單的迭代過程。在批處理方式運行時,
FCM 用下列步驟確定聚類中心 ci 和隸屬矩陣 U[1]:
步驟 1:用值在 0,1 間的隨機數初始化隸屬矩陣 U
步驟 2:用式(3)計算 c 個聚類中心 ci,i=1,...,c。
步驟 3:根據式(1)計算價值函數。如果它小於某個確定的閥值,或它相對上次價
值函數值的改變量小於某個閥值,則算法停止。
步驟 4:用(4)計算新的 U 矩陣和。返回步驟 2。
上述算法也可以先初始化聚類中心,然後再執行迭代過程。由於不能確保 FCM 收斂於一個最優解。算法的性能依賴於初始聚類中心。因此,我們要麼用另外的快速算法確定初始
聚類中心,要麼每次用不同的初始聚類中心啓動該算法,多次運行 FCM。

notes: 上面討論不難看出二個參數比較重要:1.聚類的數目,2.控制算法的柔軟參數m,如果m過大,則聚類的效果很差,如果m過小,則算法接近Kmeans算法。

 

mahout實現:

在mahout中,控制參數m=2;定義如下:private double m = 2.0; // default value

其整個代碼如下:

複製代碼
 1 public class FuzzyKMeans{
 2     
 3     public static void main(String args[]) throws Exception {
 4         int k = 3;
 5         List<Vector> sampleData = new ArrayList<Vector>();
 6         RandomPointsUtil.generateSamples(sampleData, 400, 1, 1, 3);
 7         RandomPointsUtil.generateSamples(sampleData, 300, 1, 0, 0.5);
 8         RandomPointsUtil.generateSamples(sampleData, 300, 0, 2, 0.1);
 9         List<Vector> randomPoints = RandomPointsUtil.chooseRandomPoints(
10                 sampleData, k);
11         List<SoftCluster> clusters = new ArrayList<SoftCluster>();
12         int clusterId = 0;
13         for (Vector v : randomPoints) {
14             clusters.add(new SoftCluster(v, clusterId++,
15                     new EuclideanDistanceMeasure()));
16         }
17         List<List<SoftCluster>> finalClusters = FuzzyKMeansClusterer
18                 .clusterPoints(sampleData, clusters,
19                         new EuclideanDistanceMeasure(), 0.01, 3, 10);
20         for (SoftCluster cluster : finalClusters.get(finalClusters.size() - 1)) {
21             System.out.println("Fuzzy Cluster id: " + cluster.getId()
22                     + " center: " + cluster.getCenter().asFormatString());
23         }
24     }
25 }
複製代碼

 對上面幾行代碼進行說明:

類RandomPointsUtil中靜態方法generateSamples是產生隨機樣本,並存在sampleData中。
類RandomPointsUtil中靜態方法chooseRandomPoints是隨機選擇k個樣本作爲初始點。
其類RandomPointsUtil代碼如下:
複製代碼
 1 public class RandomPointsUtil {
 2     public static List<Vector> chooseRandomPoints(List<Vector> srcVector, int k) {
 3         List<Vector> destVector = new ArrayList<Vector>();
 4         for (int i = 0; i < k; i++) {
 5             int index = (int) (Math.random() * srcVector.size());
 6             destVector.add(srcVector.get(index));
 7         }
 8         return destVector;
 9     }
10 
11     private  static void generateSamples(List<Vector> sampleData, int num, double mx,
12             double my, double sd, int card) {
13         for (int i = 0; i < num; i++) {
14             DenseVector v = new DenseVector(card);
15             for (int j = 0; j < card; j++) {
16                 v.set(j, UncommonDistributions.rNorm(mx, sd));
17             }
18             sampleData.add(v);
19         }
20     }
21 
22     /**
23      * Generate 2-d samples for backwards compatibility with existing tests25      * @param numint number of samples to generate
27      * @param mx double x-value of the sample mean
29      * @param mydouble y-value of the sample mean
31      * @param sddouble standard deviation of the samples
33      */
34     public static void generateSamples(List<Vector> sampleData, int num, double mx,
35             double my, double sd) {
36         
37         generateSamples(sampleData, num, mx, my, sd, 2);
38     }
39 }
複製代碼
所以mahout算法實現fuzzyKmeans最核心的函數爲FuzzyKMeansClusterer.clusterPoints, 下面對方法FuzzyKMeansClusterer.clusterPoints進行分析。

以上是我個人的理解,如有錯誤,請留言告訴我,本人感激不盡。作者:BIGBIGBOAT/Liqizhou

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