python大戰機器學習——聚類和EM算法


  注:本文中涉及到的公式一律省略(公式不好敲出來),若想了解公式的具體實現,請參考原著。

1、基本概念

  (1)聚類的思想:

    將數據集划分為若干個不想交的子集(稱為一個簇cluster),每個簇潛在地對應於某一個概念。但是每個簇所具有現實意義由使用者自己決定,聚類算法僅僅會進行划分。

  (2)聚類的作用:

    1)可以作為一個單獨的過程,用於尋找數據的一個分布規律

    2)作為分類的預處理過程。首先對分類數據進行聚類處理,然后在聚類結果的每一個簇上執行分類過程。

  (3)聚類的性能度量:

    1)外部指標:該指標是由聚類結果與某個參考模型進行比較而獲得的。這些外部指標性能度量的結果都在[0,1]之間,這些值越大,說明聚類的性能越好。

      Jaccard系數:它刻畫了所有屬於同一類的樣本對同時在C和C*中隸屬於同一類的樣本對的概率  JC=a/(a+b+c)

      FM指數:它刻畫了在C中屬於同一類的樣本對中,同時屬於C*的樣本對的比例為p1;在C*中屬於同一類的樣本對中,同時屬於C的樣本對比例為p2,FMI               就是p1和p2的幾何平均  FMI=sqrt((a/(a+b))*(a/(a+c)))

      Rand指數:它刻畫的是同時隸屬於C,C*的樣本對於既不隸屬於C,又不隸屬於C*的樣本對之和占所有樣本對的比例  RI=2*(a+d)/(N*(N-1))

      ARI指數:對於隨機聚類,RI指數不保證接近0。而ARI指數就可通過利用個隨機聚類情況下的RI(即E[RI])來解決這個問題。

    2)內部指標:該指標直接由考察聚類結果而得到的,並不利用任何參考模型

      DB指數:它刻畫的是,給定兩個簇,每個簇樣本之間平均值之和比上兩個簇的中心點之間的距離作為作為度量。然后考察該度量對所有簇的平均值。顯                 然DBI越小越好。如果每個簇樣本之間的平均值越小(即簇內樣本距離都很近),則DBI越小;如果簇間中心點的距離越大(即簇間樣本距離相互越遠),則                 DBI越小

      Dunn指數:它刻畫的是任意兩個簇之間最近的距離的最小值,除以任意一個簇內距離最遠的兩個點的距離的最大值。DI越大越好。      

   (4)距離度量:

    1)閔可夫斯基距離 

    2)VDM距離:它刻畫的是屬性取值在各簇上的頻率分布之間的差異(當屬性取值為非數值類時)

  通過高斯分布,隨機生成聚類簇的樣本數據,代碼如下:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 from sklearn.datasets.samples_generator import make_blobs
 4 from sklearn import cluster
 5 from sklearn.metrics import adjusted_rand_score
 6 from sklearn import mixture
 7 
 8 def create_data(centers,num=100,std=0.7):
 9     X,labels_true=make_blobs(n_samples=num,centers=centers,cluster_std=std)
10     return X,labels_true
11 
12 def plot_data(*data):
13     X,labels_true=data
14     labels=np.unique(labels_true) #the diffrent cluster(K numbers)
15     fig=plt.figure()
16     ax=fig.add_subplot(1,1,1)
17     colors='rgbyckm'
18     for i,label in enumerate(labels):
19         position=labels_true==label
20         ax.scatter(X[position,0],X[position,1],label="cluster %d"%label,color=colors[i%len(colors)])
21 
22     ax.legend(loc="best",framealpha=0.5)
23     ax.set_xlabel("X[0]")
24     ax.set_ylabel("Y[1]")
25     ax.set_title("data")
26     plt.show()
27 
28 X,labels_true=create_data([[1,1],[2,2],[1,2],[10,20]],1000,0.5)
29 plot_data(X,labels_true)
View Code

  結果如下:

2、k均值算法

  輸入:樣本集D,聚類簇數K

  輸出:簇划分C

  算法步驟:

    1)從D中隨機選擇K個樣本作為初始簇均值向量u

    2)重復迭代直到算法收斂(迭代內容參考書中內容)

  注:K均值算法總能夠收斂,但是其收斂情況高度依賴於初始化的均值,有可能收斂到局部極小值。因此通常都是用多組初始均值向量來計算若干次,選擇其中最優的一次。而k-means++策略選擇的初始均值向量可以在一定程度上解決這個問題。

  實驗代碼一:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 from sklearn.datasets.samples_generator import make_blobs
 4 from sklearn import cluster
 5 from sklearn.metrics import adjusted_rand_score
 6 from sklearn import mixture
 7 
 8 def create_data(centers,num=100,std=0.7):
 9     X,labels_true=make_blobs(n_samples=num,centers=centers,cluster_std=std)
10     return X,labels_true
11 
12 def test_Kmeans(*data):
13     X,labels_true=data
14     clst=cluster.KMeans()
15     clst.fit(X)
16     predicted_labels=clst.predict(X)
17     print("ARI:%s"%adjusted_rand_score(labels_true,predicted_labels))
18     print("Sum center distance %s"%clst.inertia_)
19 
20 def plot_data(*data):
21     X,labels_true=data
22     labels=np.unique(labels_true) #the diffrent cluster(K numbers)
23     fig=plt.figure()
24     ax=fig.add_subplot(1,1,1)
25     colors='rgbyckm'
26     for i,label in enumerate(labels):
27         position=labels_true==label
28         ax.scatter(X[position,0],X[position,1],label="cluster %d"%label,color=colors[i%len(colors)])
29 
30     ax.legend(loc="best",framealpha=0.5)
31     ax.set_xlabel("X[0]")
32     ax.set_ylabel("Y[1]")
33     ax.set_title("data")
34     plt.show()
35 
36 X,labels_true=create_data([[1,1],[2,2],[1,2],[10,20]],1000,0.5)
37 #plot_data(X,labels_true)
38 test_Kmeans(X,labels_true)
View Code

  實驗結果一:

  其中ARI指標越大越好

  實驗代碼二:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 from sklearn.datasets.samples_generator import make_blobs
 4 from sklearn import cluster
 5 from sklearn.metrics import adjusted_rand_score
 6 from sklearn import mixture
 7 
 8 def create_data(centers,num=100,std=0.7):
 9     X,labels_true=make_blobs(n_samples=num,centers=centers,cluster_std=std)
10     return X,labels_true
11 
12 def test_Kmeans_nclusters(*data):
13     X,labels_true=data
14     nums=range(1,50)
15     ARIs=[]
16     Distances=[]
17     for num in nums:
18         clst=cluster.KMeans(n_clusters=num)
19         clst.fit(X)
20         predicted_labels=clst.predict(X)
21         ARIs.append(adjusted_rand_score(labels_true,predicted_labels))
22         Distances.append(clst.inertia_)
23     fig = plt.figure()
24     ax = fig.add_subplot(1, 2, 1)
25     ax.plot(nums,ARIs,marker="+")
26     ax.set_xlabel("n_clusters")
27     ax.set_ylabel("ARI")
28     ax=fig.add_subplot(1,2,2)
29     ax.plot(nums,Distances,marker='o')
30     ax.set_xlabel("n_clusters")
31     ax.set_ylabel("inertia_")
32     fig.suptitle("KMeans")
33     plt.show()
34 
35 X,labels_true=create_data([[1,1],[2,2],[1,2],[10,20]],1000,0.5)
36 #plot_data(X,labels_true)
37 #test_Kmeans(X,labels_true)
38 test_Kmeans_nclusters(X,labels_true)
View Code

  實驗結果二:

  該結果顯示了聚類簇的數目對ARI和inertial_的影響

 

3、高斯混合聚類

  其通過概率模型來表示聚類原型。若已知高斯混合分布,則高斯混合聚類的原理是:如果樣本xi最優可能是Z=k產生的,則可將該樣本划歸到簇Ck。即通過最大后驗概率確定樣本所屬的聚類。現在的問題是,如何學習高斯混合分布的參數。由於涉及隱變量Z,故可以采用EM算法求解。

  輸入:觀察數據D,高斯混合成分個數K

  輸出:高斯混合模型參數

  算法步驟:

    1)取參數的初始值

    2)迭代直至算法收斂。迭代過程如下:

      E步:根據當前模型參數,計算分模型k對觀測數據xj的響應度:Υjk

      M步:計算新一輪迭代的模型參數:uk<i+1>,Σk<i+1>,αk<i+1>

  實驗代碼:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 from sklearn.datasets.samples_generator import make_blobs
 4 from sklearn import cluster
 5 from sklearn.metrics import adjusted_rand_score
 6 from sklearn import mixture
 7 
 8 def create_data(centers,num=100,std=0.7):
 9     X,labels_true=make_blobs(n_samples=num,centers=centers,cluster_std=std)
10     return X,labels_true
11 
12 def test_GMM_n_componets(*data):
13     X,labels_true=data
14     nums=range(1,50)
15     ARIs=[]
16     for num in nums:
17         clst=mixture.GMM(n_components=num)
18         predicted_labels=clst.fit_predict(X)
19         ARIs.append(adjusted_rand_score(labels_true,predicted_labels))
20     fig=plt.figure()
21     ax=fig.add_subplot(1,1,1)
22     ax.plot(nums,ARIs,marker='+',color='r')
23     ax.set_xlabel("n_componnents")
24     ax.set_ylabel("ARI")
25     fig.suptitle("GMM")
26     plt.show()
27 
28 centers=[[1,1],[2,2],[1,2],[10,20]]
29 X,labels_true=create_data(centers,1000,0.5)
30 test_GMM_n_componets(X,labels_true)
View Code

  實驗結果:

  奇怪的是這里所得到的結果與所想並不一致,和書中給的結果也不相同,但不知道原因在哪。

 

4、密度聚類

  其假設聚類結構能夠通過樣本分布的緊密程度來確定。DBSCAN是常用的密度聚類算法

  DBSCAN算法的定義:給定領域參數(ε,MinPts),一個簇C∈D是滿足下列性質的非空樣本子集:1)最大連接性  2)最大性     即一個簇是由密度可達關系導出的最大的密度相連樣本集合

  DBSCAN算法的思想:若x為核心對象,則x密度可達的所有樣本組成的集合記作X,可以證明X就是滿足連接性與最大性的簇。

   輸入:數據集D,領域參數(ε,MinPts)

  輸出:簇划分C

  算法步驟:

    1)初始化核心對象集合為空集

    2)尋找核心對象

    3)迭代:以任一未訪問過的核心對象為出發點,找出有密度可達的樣本生成的聚類簇,直到所有核心對象都被訪問為止

  實驗代碼:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 from sklearn.datasets.samples_generator import make_blobs
 4 from sklearn import cluster
 5 from sklearn.metrics import adjusted_rand_score
 6 from sklearn import mixture
 7 
 8 def create_data(centers,num=100,std=0.7):
 9     X,labels_true=make_blobs(n_samples=num,centers=centers,cluster_std=std)
10     return X,labels_true
11 
12 def test_DBSCAN(*data):
13     X,labels_true=data
14     clst=cluster.DBSCAN()
15     predicted_labels=clst.fit_predict(X)
16     print("ARI:%s"%adjusted_rand_score(labels_true,predicted_labels))
17     print("Core sample num:%d"%len(clst.core_sample_indices_))
18 
19 
20 X,labels_true=create_data([[1,1],[2,2],[1,2],[10,20]],1000,0.5)
21 test_DBSCAN(X,labels_true)
View Code

  實驗結果:

5、層次聚類

  其可在不用層上對數據集進行划分,形成樹狀的聚類結構。AGNES是一種常用的層次聚類算法

  AGNES算法原理:AGNES首先將數據集中的每個樣本看作一個初始的聚類簇,然后再不斷地找出距離最近的兩個聚類簇進行合並。就這樣不斷地合並直到達到預設的聚類簇的個數。

  依據選擇不同的距離計算方式,算法名不同。

  輸入:數據集D,聚類簇距離度量函數d,聚類簇數量K

  輸出:簇划分C

  算法步驟:

    1)初始化:每個樣本都作為一個簇

    2)迭代:終止條件為聚類簇的數量K(計算聚類簇之間的距離,找出距離最近的兩個簇,將這兩個簇合並)

  代碼如下:

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 from sklearn.datasets.samples_generator import make_blobs
 4 from sklearn import cluster
 5 from sklearn.metrics import adjusted_rand_score
 6 from sklearn import mixture
 7 
 8 def create_data(centers,num=100,std=0.7):
 9     X,labels_true=make_blobs(n_samples=num,centers=centers,cluster_std=std)
10     return X,labels_true
11 
12 def test_AgglomerativeClustering(*data):
13     X,labels_true=data
14     nums=range(1,50)
15     linkages=['ward','complete','average']
16     markers="+o*"
17     fig=plt.figure()
18     ax=fig.add_subplot(1,1,1)
19 
20     for i,linkage in enumerate(linkages):
21 
22         ARIs=[]
23         for num in nums:
24             clst=cluster.AgglomerativeClustering(n_clusters=num,linkage=linkage)
25             predicted_labels=clst.fit_predict(X)
26             ARIs.append(adjusted_rand_score(labels_true,predicted_labels))
27         ax.plot(nums,ARIs,marker=markers[i],label="linkage=%s"%linkage)
28 
29     ax.set_xlabel("n_clusters")
30     ax.set_ylabel("ARI")
31     ax.legend(loc="best")
32     fig.suptitle("AgglomerativeClustering")
33     plt.show()
34 
35 centers=[[1,1],[2,2],[1,2],[10,20]]
36 X,labels_true=create_data(centers,1000,0.5)
37 test_AgglomerativeClustering(X,labels_true)
View Code

  實驗結果:

  可以看到,三種鏈接方式隨分類簇的數量的總體趨勢相差無幾。但是單鏈接方式ward的峰值最大,且峰值最大的分類簇的數量剛好等於實際上生成樣本的簇的數量

 

6、EM算法

  也稱為期望極大算法,它是一種迭代算法,用於含有隱變量的概率模型參數估計。

  輸入:觀測變量數據Y,隱變量數據Z,聯合分布P(Y,Z;θ),條件分布P(Z|Y;θ)    

  輸出:模型參數θ

  算法步驟:

    1)選擇參數的初值θ0

    2)反復迭代直到收斂

  注:1)EM算法的收斂性蘊含了兩層意義:對數似然函數序列L(θi)收斂;參數估計序列θi收斂。前者並不蘊含后者。

    2)EM算法的初值的選擇非常重要,常用的辦法是給出一批初值,然后分別從每個初值開始使用EM算法。最后對得到的各個估計值加以比較,從中選擇對數似然函數最大的那個。

7、實際中的聚類要求

  (1)可伸縮性

  (2)不同類型屬性的處理能力

  (3)發現任意形狀的類簇

  (4)初始化參數

  (5)算法的抗噪能力

  (6)增量聚類和對輸入次序的敏感度

  (7)高維處理能力

  (8)結果的可解釋性和可用性

8、各種聚類算法的使用情況對比

模型 關鍵參數 使用場景
K均值算法 簇的數量

通用聚類方法,用於均勻的簇的大小,簇的數量

不多的情況

DBSCAN ε,MinPts

用於不均勻的簇大小,以及非平坦的集合結構

 

AgglometativeClustering算法 簇的數量,鏈接類型 用於簇的數量較多,有鏈接約束等情況
GMM算法 一些 用於平坦的集合結構,對密度估計很合適

  在實際應用中,聚類簇的數量的選取通常結合性能度量指標和具體問題分析。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM