Python實現(xiàn)K-Means聚類算法
直接上代碼^_^
思路:
我們的數(shù)據(jù)可能是多維的,所以我們把數(shù)據(jù)當(dāng)作向量對待。
首先我們需要了解這個算法的特點——需要手動設(shè)分類的數(shù)量(k)值。
此時類的編號為0~k-1。
然后我們考慮整體的過程。每個類有一個聚類中心(centroid),中心的坐標(biāo)就是該類每個元素坐標(biāo)的平均值,對于每一個數(shù)據(jù)而言,它離哪個中心最近,它就屬于哪個類。因此,每次迭代(在KMeansAlgorithm.Iterate方法中實現(xiàn))時,首先計算每個數(shù)據(jù)屬于哪個類,此時每個類的成員發(fā)生了變化,因此需要重新計算每個類的中心(如果不變就說明我們的迭代已經(jīng)完成了)。
這里我們要注意一下我們選取的距離函數(shù)(KMeansAlgorithm.distsquare),它計算兩個向量之間歐氏距離的平方:
其中為數(shù)據(jù)的維數(shù)。我們知道,向量點乘它自己就是其模長的平方,這就不難理解代碼中對該函數(shù)的實現(xiàn)了。
那么問題來了:一開始每個類的情況是怎樣的呢?沒有初始值就無法進行迭代。這里,我們使用clusmap來表示每個數(shù)據(jù)屬于哪個類,clusmap[3]=0代表第三個元素屬于第0類。在setk方法里,我們隨機分配每個元素屬于的類,用np.random.randint實現(xiàn)。然后計算每個類的中心,這樣就完成了初始化,之后就可以開始迭代了。
最后,怎么判斷是否結(jié)束了呢?我們定義“畸變函數(shù)”KMeansAlgorithm.GetDistortion,它等于每個數(shù)據(jù)到它所在的類的中心的距離的平方和。顯然,這個值越低,分類越準(zhǔn)確。我們迭代時,如果發(fā)現(xiàn)這個值隨著迭代的變化小于一定程度(Compute方法的threshold參數(shù)),就基本可以判斷迭代結(jié)束了。threshold代表這一次迭代與上一次迭代相比“畸變”(distortion)的比例,這個值越低,迭代結(jié)束的條件越苛刻,運行時間就越長。