各類聚類(clustering)算法初探


1. 聚類簡介

0x1:聚類是什么?

聚類是一種運用廣泛的探索性數據分析技術,人們對數據產生的第一直覺往往是通過對數據進行有意義的分組,通過對對象進行分組,使相似的對象歸為一類,不相似的對象歸為不同類。

0x2:聚類的悖論

在研究聚類算法原理以及應用聚類算法的時候,我們自己首先要明白,聚類算法並不總是有效,甚至是完全不合理的。我們稱其為”聚類的悖論“,之所以會出現悖論,主要的原因是:

  • ”相似對象歸為一類,不相似對象歸為不同類“這兩個目標在很多情況下是互相沖突的。從數學上講,雖然聚類共享具有等價關系甚至傳遞關系,但是相似性(或距離)不具有傳遞關系。具體而言,假定有一對象序列,X1,....,Xm,所有相鄰元素(Xi-1、Xi+1)兩兩都非常相似,但是X1和Xm非常不相似。這種情況常常發生在cluster超過一定尺寸的時候,元素之間的傳遞性假設在這些場景下不一定100%成立。
  • 聚類是一種無監督學習,即我們不能預測label,因此對於聚類,我們沒有明確的成功評估過程。當然也不是完全沒有任何的聚類效果評價指標,分類效用(category utility)就是一個理論上的評價指標。
  • 對於一個給定的對象集合,可以有多種有意義的划分方式,這可能是因為對象間的距離(或相似性)有多種隱式的定義,例如將演講者的錄音根據演講者的口音聚類或根據內容聚類。所以,給定一個數據集,有多種不同的聚類解決方案

0x3:聚類的公理化描述

對於各種各樣的聚類算法,有沒有一些基本性質是獨立於具體算法或任務的呢?很多人嘗試對聚類提出一個公理化的定義,讓我們討論Kleninberg(2003)提出的嘗試方法:

考慮一個聚類函數F,將任意有限域X及不相似函數d作為輸入,返回X的一個划分

1. 尺度不變性(SI)

對任意的域集 X,不相似函數 d,以及任意的 a > 0,下式成立:

尺度不變性是一種非常自然的要求,因為如果聚類函數輸出的結果依賴於測量點之間的距離測度單元,那將顯得十分奇怪和不合理。

2. 豐富性(Ri)

對任意的有限集 X 和划分 C = (C1,C2,....,Ck)(划分到非空子集),存在多種不相似函數 d 使得下式成立:

豐富性要求主要想說明聚類函數的輸出是由函數 d 全權決定,也是一種十分直觀的特征。

3. 一致性(Co)

如果 d 和 d' 都是 X 上的不相似函數,對任一,根據 F(X,d):

  • 如果 x,y 屬於同一類,則
  • 如果 x,y 屬於不同類,則

一致性要求是和聚類基本定義相關的要求,我們希望相似的點聚到一類,不相似的點分屬不同類,因此共享同類的點更相似,已經分離的點不相似,聚類函數應當對之前的聚類決策有很強的“支撐”作用。

值得注意的是,Kleinberg在2003已經給出了下述“不可能”結論!

不存在一個函數F同時滿足上述三種屬性:尺度不變性,豐富性,一致性

但是,Kleninberg的“不可能”結論可以通過改變屬性的限制范圍來規避。即不用100%滿足上述三條件

例如,如果討論含固定數量參數的聚類函數,很自然地將豐富性改為 k-豐富性(即,將域划分到k個子集,這個限制比豐富性RI原則更松散一些)。k-均值聚類滿足k-豐富性、尺度不變性和一致性,因此能夠達到一致。或者可以放松一致性屬性。

筆者思考

給定一項任務,聚類函數的選取必須考慮該任務的特定屬性(是否可以放松要求,又是否有一些地方是需要強要求)。沒有統一的聚類解決方案,就像沒有一種分類算法能夠對每一項可學習任務都能學習(no free lunch定理)。和其他分類預測一樣,聚類必須考慮特定任務的先驗知識

0x4:數據挖掘對聚類的典型泛化要求

不同的算法有着不同的應用背景,有的適合大數據集,可以發現任意形狀的聚類;有的算法思想簡單直觀,適用於小數據集。總的來說,算法都試圖從不同途徑實現對數據集進行高效、可靠的聚類。數據挖掘對聚類的典型要求包括:

1. 可伸縮性:

當聚類對象由幾百上升到幾百萬,我們希望最后的聚類結果的准確度能保持一致

2. 處理不同類型屬性的能力:

有些聚類算法,其處理對象的屬性的數據類型只能是數值類型,但是在實際應用場景中,我們往往會遇到其他類型的數據(例如二元數據),分類數據等等,雖然我們也可以在預處理數據時將這些其他類型的數據轉換成數值型數據,但是在聚類效率上或者聚類准確度上往往會有折損

3. 發現任意形狀的類簇:

因為許多聚類算法是基於距離(例如歐式距離或曼哈頓距離)來量化實例對象之間的相似度的,基於這種方式,我們往往只能發現相似尺寸和密度的球狀類簇或者凸形類簇。但是在很多場景下,類簇的形狀可能是任意的

4. 對聚類算法初始化參數的知識需求的最小化:

很多算法在分析過程中需要開發者提供一定的參數(例如期望的類簇K個數、類簇初始質心),這導致了聚類結果對這些參數是十分敏感的,這不僅加重了開發者的負擔,也非常影響聚類結果的准確性

5. 處理噪聲數據的能力:

所謂的噪聲數據,可以理解為影響聚類結果的干擾數據,這些噪聲數據的存在會造成聚類結果的“畸變”,最終導致低質量的聚類

6. 增量聚類和對輸入次序的不敏感:

一些聚類算法不能將新加入的數據插入到已有的聚類結果,輸入次序的敏感是指,對於給定的數據對象集合,以不同的次序提供輸入對象時,最終產生的聚類結果的差異會比較大

7. 高維性:

有些算法只適合處理2維或者3維的數據,而對高維數據的處理能力很弱,因為在高維空間中數據的分布可能十分稀疏,而且高度傾斜。

8. 基於約束的聚類:

在實際應用中可能需要在各種條件下進行聚類,因為同一個聚類算法,在不同的應用場景中所帶來的聚類結果也是各異的,因此找到滿足“特定約束”的具有良好聚類特性的數據分組是十分有挑戰的。這里最困難的問題就在於如何是識別我們要解決的問題中隱含的“特定約束”具體是什么,以及該使用什么算法來最好的“適配”這種約束

9. 可解釋性和可用性:

我么希望得到的聚類結果都能用特定的語義、知識進行解釋,和實際的應用場景相聯系

0x5:聚類的大致分類

聚類是將數據對象的集合分成相似的對象類的過程,使得同一個簇(或類)中的對象之間具有較高的相似性,而不同簇中的對象具有較高的相異性。

按照聚類的尺度,聚類方法可被分為以下三種:

  • 基於距離的聚類算法:基於距離的聚類算法是用各式各樣的距離來衡量數據對象之間的相似度
  • 基於密度的聚類方法:基於密度的聚類算法主要是依據合適的密度函數進行類間聚類
  • 基於互連性的聚類算法:基於互連性的聚類算法通常基於圖或超圖模型,將高度連通的對象聚為一類

0x6:信息瓶頸 - 信息論視角下的聚類算法理解

信息瓶頸是由 Tishby,Pereira和 Bialek 提出的聚類技術,其概念來源於信息論。

用一個文本聚類的問題來解釋這個概念,假設我們將每個文本表示為一個詞袋,即,每個文檔都是一個向量

其中 n 是字典的長度,當且僅當第 i 個詞在文檔中出現。給定一個有 m 個文檔的集合,我們可以將 m 個文檔的詞袋表示理解為隨機變量 x 的聯合概率分布,指示文檔的身份,以及一個隨機變量 y,指示單詞在詞典中的身份。

根據這種解釋,信息瓶頸是指:將聚類屬性表示為另一個隨機變量C(歸納到具體的類別 k 中)(其中 k 同樣由方法確定)。一旦將 x,y,C 表述為隨機變量,我們可以使用信息論中的方法來表示聚類目標。

信息瓶頸的目標是:

其中是兩個隨機變量的互信息,在每個點分屬聚類的所有可能概率分布中求取極小值。

直觀上講,我們希望達到兩個矛盾的目標。

  • 一方面,我們希望文檔屬性和聚類屬性的互信息盡可能小,這反映了我們希望對原始數據進行強壓縮。
  • 另一方面,我們希望聚類變量和詞屬性的互信息盡可能大,這反映了保留文檔信息(用詞在文檔中出現來表示)的目標。將參數統計中的最小充分統計量推廣到了任意分布。

解信息瓶頸准則下的最優化問題通常是非常困難的,解決方案思路上類似EM准則。

0x7:分類效用(category utility) - 聚類效果評價指標

分類效用度量的是聚類算法將實例集分隔成聚類的總體質量。需要注意的是,分類效用不是以MDL為基礎的,而是一個類似於定義在條件概率上的二次損失函數,它借助了信息論中互信息的一些思想理念。

  • C1,C2,...,Ck 是 k 個聚類,外層的求和是針對每一個聚類的
  • 內層兩個求和分別是針對每個屬性和每個實例的
  • ai 代表第 i 個屬性,它的值有 vi1,vi2,....,vij,一共要處理 j 個

我們來分析一下上面這個分類效用CU公式。

  • 聚類的意義不僅僅在於分類就完了,而更多是聚類后的結果對數據集的結構的發掘,對后續分類的幫助,即有利於更好地預測聚類中實例的屬性值。
  • 對於聚類結果 Cl 中的某個實例,屬性 ai 的值為 vij 的概率是 Pr[ai=vij | Cl],相對於概率 Pr[ai=vij]來說,是一個更好的估計,因為實例所在的聚類起到降低不確定性的作用,換句話說,聚類結果提供了有價值的信息,提高了分類結果的精確度。公式用兩個概率的平方差來度量。
  • 外部的 Pr[Cl] 以及除以 k 是考量整個聚類結果的復雜性,防止過度擬合。否與,由於概率是累計所有適當的實例獲得的,每個實例單獨作為一個聚類是數學上最好的結果。

Relevant Link:

《深入理解機器學習 - 從原理到算法》
http://blog.csdn.net/itplus/article/details/10087581
http://www.sohu.com/a/193777221_473283

 

2. K-Means算法(K-means clustering K均值聚類算法) - 基於硬划分的聚類

0x1:K-means算法模型

一種流行的聚類算法是首先對可能的聚類定義一個代價函數,聚類算法的目標是尋找一種使代價最小的划分。

在這類范例中,聚類任務轉化為一個優化問題,目標函數是一個從輸入(X,d)和聚類方案 C = (C1,C2,....,Ck)映射到正實數(即損失值)的函數。

給定這樣一個目標函數,我們將其表示為 G,對於給定的一個輸入(X,d),聚類算法的目標被定義為尋找一種聚類 C 使 G((X,d),C) 最小。

其中,Ci 中心點被定義為:

所以上式也可以寫成如下形式:

上述定義的損失函數,將聚類問題轉換為了一個優化問題,但是要注意的是,理論和實際的工程化是存在一定的差距的。

k均值目標函數在實際的聚類應用中很常見。然而,事實證明尋找k均值(k-means)算法的最優解通常是計算不可行的(NP問題)。所以通常會用下面這種簡單的迭代算法作為替代算法

因此,多數情況下,k均值聚類值得是這種算法的結果而不是最小化 k 均值目標函數的結果。

在學習具體的 K-means 算法細節之前,我們需要了解 K-means 原生存在的一些問題:

  • k均值算法的目標函數優化過程是單調非增的(也就是每次的迭代至少不會讓結果更糟),但是 k均值算法本身對達到收斂的迭代次數並沒有給出理論保證
  • 算法給出的 k均值目標函數輸出值和目標函數的最小可能值之差,並沒有平凡下界,實際上,k均值可能會收斂到局部最小值。為了提高 k均值的結果,通常使用不同的隨機初始化中心點,將該程序運行多次,並選取最優的結果。除此之外,有一些無監督的算法可以作為 k均值算法的前置算法,用來選取初始化中心。
  • 在訓練集上根據距離平方總和標准得到的”最佳“聚類,將不可避免地選擇與數據點一樣多的聚類!因為此時損失為0,為了抑制這種傾向,需要應用MDL准則進行模型結構復雜性懲罰,在模型復雜度和損失目標最優化之間尋求一個平衡。

0x2:K-means算法過程

kMeans聚類算法是數據挖掘十大算法之一,算法需要接受參數 k(k 個初始聚類中心)(也可由算法隨機產生指定),即將數據集進行聚類的數目和k個簇的初始聚類“中心”,結果是同一類簇中的對象相似度最高,不同類簇中的數據相似度最低,其聚類過程可以用下圖表示

如圖所示,數據樣本用圓點表示,每個簇的中心點用叉叉表示

1. 聚類中心個數K

聚類中心的個數K需要事先給定,但在實際中這個 K 值的選定是非常難以估計的,很多時候,事先並不知道給定的數據集應該分成多少個類別才最合適。有幾種可能的策略可以緩解這種問題。

1)遍歷嘗試所有k值

這個過程會是一個漫長的調試過程,我們通過設置一個[k, k+n]范圍的K類值,然后逐個觀察聚類結果,最終決定該使用什么K值對當前數據集是最佳的

2)小數據集抽樣試驗

在實際情況中,往往是對特定的數據集有對應一個最佳的K值,而換一個數據集,可能原來的K值效果就會下降。但是同一個項目中的一類數據,總體上來說,通過一個抽樣小數據集確定一個最佳K值后,對之后的所有K值都能獲得較好的效果。

3)啟發式分裂探索策略

另一種可能的方法是開始先找出很少幾個聚類,然后決定是否值得將它們分裂。

我們可以選擇k=2,執行k均值聚類直到它終止,然后考慮分裂每個聚類。

分裂聚類的一種方法是在變化最大的方向、距離聚類中心一個標准差的位置產生一個新的種子,隨后在反方向、等距建立第二個種子。然后基於這兩個新的種子,對聚類中的點進行k均值聚類。

聚類分裂暫時完成時,是否值得保留分裂,或者原來的聚類也是合理的?查看所有點離聚類中心距離的平方和是不合理的,因為量子子聚類的和一定是較小的。這個時候需要引入MDL原則,為每新建一個聚類引入懲罰。在分裂與聚類效果之間尋求最佳平衡。

2. 初始聚類中心(質心)的選擇

剛開始時是原始數據,雜亂無章,沒有label,看起來都一樣,都是綠色的

Kmeans需要人為地確定初始聚類中心,不同的初始聚類中心可能導致完全不同的聚類結果。在實際使用中我們往往不知道我們的待聚類樣本中哪些是我們關注的label,人工事先指定質心基本上是不現實的,在大多數情況下我們采取隨機產生聚類質心這種策略

假設數據集可以分為兩類,令K = 2,隨機在坐標上選兩個點,作為兩個類的中心點(聚類質心)

3. 確定了本輪迭代的質心后,將余下的樣本點根據距離度量標准進行歸類

這一步也非常直觀,計算樣本點和所有質心的“距離”,選取“距離”最小(argmin)的那個質心作為該樣本所屬的類別。

這里要注意的是,特征空間中兩個實例點的距離是兩個實例點相似程度的反映,高維向量空間點的距離求解,可以泛化為Lp距離公式,它在不同的階次數中分為不同的形式

p = 1:Manhattan Distance距離(曼哈頓距離):

p = 2:Euclidean Distance距離(歐拉距離)

p = λ( 3 <= λ <= 正無窮 ):Lp距離

p = 正無窮:距離等於各個坐標點的最大值

為了幫助理解,下圖展示了二維空間中p取不同值時,與原點的Lp距離為1(Lp = 1)的點的圖形

4. 算法收斂(終止/停機)條件是什么?

我們前面說過,計算K-means問題的目標函數最優解是一個NP問題,我們大多數時候都是針對聚類結果施加一些約束,得到一個終止/停止條件,例如一種比較常用的停止條件:

  • 這樣不斷進行"划分—更新—划分—更新",直到每個簇的中心不在移動為止

0x3:Kmeans算法步驟圖示描述

1. 步驟一 - 選取質心

在輸入數據集里面隨機選擇三個向量作為初始中心點(下圖中的紅綠藍三個圓點),這里的K值為3, 也就是一開始從數據集里面選擇了三個向量,這算作第一次迭代

2. 步驟二 - 距離聚類

將每個向量分配到離各自最近的中心點,從而將數據集分成了K個類

3. 步驟三 - 重選新質心

計算得到上步得到聚類中每一聚類觀測值的均值作為新的質心。這里體現的思想是這樣的:因為我們是無監督學習,對於待分類的樣本集群我們沒有任何的先驗知識,完全不知道該怎么分類,那么我們就暴力地、勇敢地、隨機地踏出第一步,然后不斷地去修正我們的分類器,不得不說,這和人生的很多的做人做事的道理是類似的

4. 步驟四(人生就是一個勇敢踏出第一步,然后不斷自我否定和修正成長的過程)

重復步驟三,直至結果收斂,這里的收斂是指所有點到各自中心點的距離的和收斂

用sklearn python 對2維數據點進行kMeans聚類 

# -*- coding: utf-8 -*-

from sklearn.cluster import KMeans
import numpy as np

if __name__ == '__main__':
    X = np.array([
        [1, 2], [1, 4], [1, 0],
        [4, 2], [4, 4], [4, 0]
    ])
    kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
    print kmeans.labels_

    kmeans.predict([[0, 0], [4, 4]])

    print kmeans.cluster_centers_

kMeans這種無監督聚類進行一次無監督聚類后,也可以得到一個分類器(classifier),它是對當前train set的一個特征空間划分,基於這個分類器可以用於之后對新樣本點的分類預測,這種就是有監督聚類

0x4:不同K值、不同的初始化中心點方式對Kmeans分類效果的影響

我們知道,K-mean的3大核心要素是:K值、距離度量公式、初始質心的選擇。我們這個小節用一小代碼來討論下這些值是如何影響算法的分類效果

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D


from sklearn.cluster import KMeans
from sklearn import datasets

if __name__ == '__main__':
    np.random.seed(5)

    centers = [[1, 1], [-1, -1], [1, -1]]
    iris = datasets.load_iris()
    X = iris.data
    y = iris.target

    estimators = {'k_means_iris_3': KMeans(n_clusters=3),
                  'k_means_iris_8': KMeans(n_clusters=8),
                  'k_means_iris_bad_init': KMeans(n_clusters=3, n_init=1, init='random')}

    fignum = 1
    for name, est in estimators.items():
        fig = plt.figure(fignum, figsize=(4, 3))
        plt.clf()
        ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)

        plt.cla()
        est.fit(X)
        labels = est.labels_

        ax.scatter(X[:, 3], X[:, 0], X[:, 2], c=labels.astype(np.float))

        ax.w_xaxis.set_ticklabels([])
        ax.w_yaxis.set_ticklabels([])
        ax.w_zaxis.set_ticklabels([])
        ax.set_xlabel('Petal width')
        ax.set_ylabel('Sepal length')
        ax.set_zlabel('Petal length')
        fignum = fignum + 1

    # Plot the ground truth
    fig = plt.figure(fignum, figsize=(4, 3))
    plt.clf()
    ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)

    plt.cla()

    for name, label in [('Setosa', 0),
                        ('Versicolour', 1),
                        ('Virginica', 2)]:
        ax.text3D(X[y == label, 3].mean(),
                  X[y == label, 0].mean() + 1.5,
                  X[y == label, 2].mean(), name,
                  horizontalalignment='center',
                  bbox=dict(alpha=.5, edgecolor='w', facecolor='w'))
    # Reorder the labels to have colors matching the cluster results
    y = np.choose(y, [1, 2, 0]).astype(np.float)
    ax.scatter(X[:, 3], X[:, 0], X[:, 2], c=y)

    ax.w_xaxis.set_ticklabels([])
    ax.w_yaxis.set_ticklabels([])
    ax.w_zaxis.set_ticklabels([])
    ax.set_xlabel('Petal width')
    ax.set_ylabel('Sepal length')
    ax.set_zlabel('Petal length')
    plt.show()

可以看到,Kmeans這種無監督學習的算法並不能保證聚類出來的"族群"是有"實際意義"的,即Kmeans得到的分類族群可能只是在歐式空間上相近的點集,但是實際上它們並不一定真的就屬於同一個類別。另外一方面,Kmeans的分類結果和K值有強關聯,如果我們傳入了一個"不合理"的K值,有可能導致Kmeans的過擬合,最后得到一個"錯誤"的分類結果

在思考的深層次一些,這其實和Kleinberg對聚類算法的公理化定義有關,標准的聚類公理化定義是需要滿足豐富性(Ri)原則的,但是這個條件太強了,所以k-means是一個滿足k-豐富性原則的算法,k-豐富性原則是一個弱約束,不同的k值下,產生的分類結果也自然是不同的

0x5:K-means在圖像處理上的應用

1. Color Quantization(真彩色降維低彩色) using K-Means

這個例子要求做的是從96615真彩色"降維"到64種色彩,這里我個人理解聚類和降維的本質有共通的地方,聚類的目標是把相似的數據集歸納到同一個類別里,如果歸納完之后直接用這個新的類別代表該類別所有的樣本集,那這個聚類就是一次降維過程。同樣,回到這個例子,如果我們對一副真彩色的高維度像素的圖像進行相似像素色聚類,本質上就是把原始圖像降維成了一個低緯度低彩色圖

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import pairwise_distances_argmin
from sklearn.datasets import load_sample_image
from sklearn.utils import shuffle
from time import time

if __name__ == '__main__':
    n_colors = 64

    # Load the Summer Palace photo
    china = load_sample_image("china.jpg")

    # Convert to floats instead of the default 8 bits integer coding. Dividing by
    # 255 is important so that plt.imshow behaves works well on float data (need to
    # be in the range [0-1])
    china = np.array(china, dtype=np.float64) / 255

    # Load Image and transform to a 2D numpy array.
    w, h, d = original_shape = tuple(china.shape)
    assert d == 3
    image_array = np.reshape(china, (w * h, d))

    # 用1000張圖像來訓練出一個Kmeans分類器
    print("Fitting model on a small sub-sample of the data")
    t0 = time()
    image_array_sample = shuffle(image_array, random_state=0)[:1000]
    kmeans = KMeans(n_clusters=n_colors, random_state=0).fit(image_array_sample)
    print("done in %0.3fs." % (time() - t0))

    # 用訓練好的Kmeans分類器對本例中的"夏宮"圖像進行聚類處理,實際上就是在降維
    # Get labels for all points
    print("Predicting color indices on the full image (k-means)")
    t0 = time()
    labels = kmeans.predict(image_array)
    print("done in %0.3fs." % (time() - t0))

    codebook_random = shuffle(image_array, random_state=0)[:n_colors + 1]
    print("Predicting color indices on the full image (random)")
    t0 = time()
    labels_random = pairwise_distances_argmin(codebook_random,
                                              image_array,
                                              axis=0)
    print("done in %0.3fs." % (time() - t0))


    def recreate_image(codebook, labels, w, h):
        """Recreate the (compressed) image from the code book & labels"""
        d = codebook.shape[1]
        image = np.zeros((w, h, d))
        label_idx = 0
        for i in range(w):
            for j in range(h):
                image[i][j] = codebook[labels[label_idx]]
                label_idx += 1
        return image


    # Display all results, alongside original image
    plt.figure(1)
    plt.clf()
    ax = plt.axes([0, 0, 1, 1])
    plt.axis('off')
    plt.title('Original image (96,615 colors)')
    plt.imshow(china)

    plt.figure(2)
    plt.clf()
    ax = plt.axes([0, 0, 1, 1])
    plt.axis('off')
    plt.title('Quantized image (64 colors, K-Means)')
    plt.imshow(recreate_image(kmeans.cluster_centers_, labels, w, h))

    plt.figure(3)
    plt.clf()
    ax = plt.axes([0, 0, 1, 1])
    plt.axis('off')
    plt.title('Quantized image (64 colors, Random)')
    plt.imshow(recreate_image(codebook_random, labels_random, w, h))
    plt.show()

把原始圖像的96615像素點聚類為64像素點,中間的圖像就是Kmeans聚類后的結果,可以看到,從肉眼視覺角度看,圖像並沒有明顯地失真

0x6:從混合模型和EM算法的角度來談kmeans聚類

實際上,混合模型和EM算法又是另一塊非常龐大的主題,我們這里不深入討論,只討論kmeans更高層次的抽象概括,混合模型除了提供一個構建更復雜的概率分布的框架之外,混合模型也可以用於數據聚類。本質上來說,K均值算法對應於用於高斯混合模型的EM算法的一個特定的非概率極限

1. 用形式化方式描述Kmeasn

引入一組 D 維向量,其中,,且是與第 k 個聚類關聯的一個代表。我們可以認為表示了聚類的中心,我們的目標是找到所有數據點分別屬於的聚類,以及一組向量,使得每個數據點和它最近的向量之間的距離的平方和最小。對於每個數據點,我們引入一組對應的二值指示變量,其中,表示數據點屬於 K 個聚類中的哪一個(指示函數)

有了以上定義,之后我們可以定義一個目標函數,也被稱為失真度量(distortion measure)

(公式9.1)

它表示每個數據點與它被分配的向量之間的距離的平方和。我們的目標是找到的值,使得 J 達到最小值。我們可以用一種迭代的方法完成這件事,其中每次迭代涉及到兩個連續的步驟,分別對應

  • 的最優化(E期望):首先,我們為選擇一些初始值。然后在第一階段,我們保持固定,關於最小化 J
  • 的最優化(M最大化):在第二階段,我們保持固定,關於最小化 J。不斷重復這2個階段優化直到收斂

我們看到,在EM步驟中,每次都是固定其中一個變量,求另一個變量的極值,避免直接對二元變量直接求極值的計算困難問題。為了說明這一點,我們在K均值算法中使用 E步驟和 M步驟的說法

首先考慮最優化,公式(9.1)給出的 J 是的一個線性函數,因此最優化過程可以很容易地進行,得到一個解析解。與不同的 n 相關的項是獨立的,因此我們可以對每個 n 分別進行最優化,只要 k 的值使最小,我們就令等於1。換句話說,我們可以簡單地將數據點的聚類設置為最近的聚類中心,更形式化地,這可以表達為:

(1-of-k)

現在考慮固定時,關於的最優化。目標函數 J 是的一個二次函數,令它關於的導數等於零,即可達到最小值,即

求導結果為:

這個表達式的分母等於單個聚類 k 中數據點的數量,因此這個結果有一個非常簡單直觀的含義,即令等於單個類別 k 的所有數據點的均值

上述兩個步驟合起來稱為K均值(K-means)算法

重新為數據點分配聚類的步驟以及重新計算聚類均值的步驟重復進行,直到聚類的分配不改變(或者直到迭代次數超過了某個最大值)。由於每個階段都減小了目標函數 J 的值,因此算法的收斂性得到了保證,但是要注意的是,算法可能收斂到 J 的一個局部最小值而不是全局最小值 

Relevant Link:

http://blog.itpub.net/12199764/viewspace-1479320/
https://blog.yueyu.io/p/1614
http://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html
http://scikit-learn.org/stable/auto_examples/cluster/plot_cluster_iris.html#sphx-glr-auto-examples-cluster-plot-cluster-iris-py
http://scikit-learn.org/stable/auto_examples/cluster/plot_color_quantization.html#sphx-glr-auto-examples-cluster-plot-color-quantization-py
http://scikit-learn.org/stable/auto_examples/cluster/plot_face_compress.html#sphx-glr-auto-examples-cluster-plot-face-compress-py 
http://blog.csdn.net/gamer_gyt/article/details/51244850
http://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_assumptions.html#sphx-glr-auto-examples-cluster-plot-kmeans-assumptions-py
http://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_digits.html#sphx-glr-auto-examples-cluster-plot-kmeans-digits-py
http://chunqiu.blog.ustc.edu.cn/?p=435#comment-3556
http://f.dataguru.cn/thread-639729-1-1.html
http://www.cnblogs.com/bourneli/p/3645049.html 
http://www.cnblogs.com/bourneli/p/3645049.html
https://en.wikipedia.org/wiki/Silhouette_(clustering)
https://kapilddatascience.wordpress.com/2015/11/10/using-silhouette-analysis-for-selecting-the-number-of-cluster-for-k-means-clustering/
http://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html#sphx-glr-auto-examples-cluster-plot-kmeans-silhouette-analysis-py
http://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_stability_low_dim_dense.html#sphx-glr-auto-examples-cluster-plot-kmeans-stability-low-dim-dense-py
http://scikit-learn.org/stable/modules/clustering.html#mini-batch-kmeans
http://scikit-learn.org/stable/auto_examples/cluster/plot_mini_batch_kmeans.html#sphx-glr-auto-examples-cluster-plot-mini-batch-kmeans-py
http://scikit-learn.org/stable/auto_examples/text/document_clustering.html#sphx-glr-auto-examples-text-document-clustering-py
http://coolshell.cn/articles/7779.htm

 

3. K-Means++算法

0x1:從爬山法問題中切入談kmeans的缺陷以及kmeans++緩解了什么問題

假設我們的目標是到達山頂,我們采用的算法如下

  • 從山上的某個隨機位置出發開始
  • Repeast
  • 每次都都沿着“更高”的方向走一步
  • Until直到某一步發現無論往任何方向走都不會更高 

這個算法看起來十分合理,但是我們考慮下面這個圖上運行上述算法

我們如何從A點出發,只會到達B點而不會到達最高頂點D點,即我們到達的是局部最優點而不是全局最優點。

k-means算法和上面的爬山法類似,不能保證最后能夠找到最優的划分簇。這是因為算法一開始選擇的是隨機質心,基於隨機質心,算法只能找到局部最優化分簇(例如圖像的B點)。對於kmeans這種EM過程來說,最終的聚類結果嚴重依賴於初始中心點的選擇

K-Means主要有兩個最重大的缺陷 - 都和初始值有關

  • K需要事先給定,這個K值的選定是非常難以估計的。很多時候,事先並不知道給定的數據集應該分成多少個類別才最合適
  • K-Means算法需要用初始隨機種子點來啟動優化,這個隨機種子點太重要,不同的隨機種子點會有得到完全不同的結果

但是k-means++算法從一定程度上解決了該問題,k-means++選擇初始seeds的基本思想就是:初始的聚類中心之間的相互距離要盡可能的遠。

0x2:k-Means++算法步驟

  • 從輸入的數據點集合中隨機選擇一個點作為第一個種子點(聚類中心)
  • 對於數據集中的每一個點x,計算它與最近聚類中心(指已選擇的聚類中心)的距離D(x)並保存在一個數組里,然后把這些距離加起來得到Sum(D(x))
  • 選擇一個新的數據點作為新的聚類中心,選擇的原則是: D(x)較大的點被選取作為聚類中心的概率較大(kMeans不同類別的距離越遠越好)
    • 先取一個能落在Sum(D(x))中的隨機值Random
    • 然后用Random -= D(x),直到其結果 <= 0
    • 選取在這個"遞減過程"中D(x)最大的點,此時的點就是下一個"種子點"
  • 重復2和3直到k個聚類中心被選出來
  • 利用這k個初始的聚類中心來運行標准的k-means算法

可以看到算法的第三步選取新中心的方法,這樣就能保證距離D(x)較大的點,會被選出來作為聚類中心了。

同時k-measn這里並不直接用“hard方式”通過遍歷每次選取D(x)最大的值作為下一個中心點,而是引入了隨機過程,通過隨機過程,柔和地體現了”以正比於D(x)的概率(概率由距離決定)隨機選擇一個數據點作為新的中心點“這個思想。

以一段python代碼模擬該過程。假設由包含數據點及其權重的元祖構成列表。roulette函數會基於隨機過程以正比於某個數據點的權重的概率來選擇點。

#-*- coding:utf-8 -*-

import collections
import random
random.seed()

def roulette(datalist):
    i = 0
    soFar = datalist[0][1]
    ball = random.random()
    while soFar < ball:
        i += 1
        soFar += datalist[i][1]
    return datalist[i][0]


if __name__ == "__main__":
    data = [
        ("dp1", 0.25),
        ("dp2", 0.4),
        ("dp3", 0.1),
        ("dp4", 0.15),
        ("dp5", 0.1)
    ]
    results = collections.defaultdict(int)
    for i in range(1000):
        results[roulette(data)] += 1
    print results

我們可以看到,在1000次選擇中,函數按照正比於權重的方式柔和地進行了點的選擇

0x3:Kmeans++算法策略

k-means++聚類的基本思想就是:雖然第一個中心點仍然隨機選擇,但其他的點則優先選擇那些彼此相距很遠的點

Relevant Link:

http://www.csdn.net/article/2012-07-03/2807073-k-means

 

4. 基於鏈接的層次聚類算法 - 基於分層的聚類(自底向上)

層次聚類方法不需要指定最終聚成的簇的數目(例如K值)。取而代之的是,算法一開始將每個實例都看成一個簇,在一個確定的”聚類間度量函數“的驅動下,算法的每次迭代中都將最相似的兩個簇合並在一起,該過程不斷重復直到只剩下一個簇為止。該方法稱為層次聚類,也叫凝聚聚類(agglomerative clustering)

合並過程的記錄會形成一個層次聚類結構,即一個二叉樹狀圖,如下圖

層次聚類的思想並不復雜,引起層次聚類算法區別的核心因素有兩個:

  • 聚類間距離度量:決定怎樣測量(或定義)類間距離
  • 提前終止條件:我們需要確定什么時候終止合並,否則最終只會得到一個單聚類

接下來我們按照這兩條脈絡進行梳理和討論。

0x1:鏈接聚類模型

我們前面說了,對這類鏈接聚類(自下而上聚類)有兩個非常關鍵的因素就是距離度量和終止條件,它們共同決定了鏈接聚類算法的算法模型,我們這節來討論它們。

1. 聚類間距離度量公式

1)單鏈接(single-linkage clustering)

  • 單鏈接最小距離聚類(single-linkage clustering):類間距離定義為兩類元素間的最短距離(取兩兩組合最短距離的兩個)。由於該度量值考慮了兩個聚類中最近的兩個成員間的距離,所以該過程對離群點很敏感,增加單個實例就可能完全改變整個聚類結構。

  • 單鏈接最大鏈接聚類:類間距定義為兩類元素間的最大距離(取兩兩組合最長距離的那個)。在這種度量標准下,單鏈接聚類會產生直徑非常大的聚類。

2)完全鏈接(complete-linkage)

  • 完全鏈接聚類:只有兩個聚類的所有成員都相似時,才認為兩個聚類的距離很近、這種度量標准也對離群點很敏感,並且傾向於尋找緊湊的、直徑較小的聚類。同時,也可能會出現一些實例與其他聚類的距離比與它自己所在聚類內其他點的距離還近很多的情況。

3)中心鏈接(centroid-linkage)

  • 中心鏈接聚類:中心鏈接度量代表了聚類成員間最小和最大距離的一種折中,用聚類成員的中心來代表聚類。

4)平均鏈接(average-linkage clustering)

  • 平均鏈接聚類(average-linkage clustering):類間距離定義為兩類元素之間距離的平均值。當實例位於歐式空間時,中心的定義很明確,該方法效果很好。但是當實例之間只有成對的相似性度量時,由於中心不能用實例表達,它們之間的相似性不能定義,所以該方法不可行。

5)組平均(group-average)

  • 組平均聚類:它使用合並后的聚類中的所有成員間的平均距離。這與平均聚類方法不同,它包含了相同原始聚類的平均值對。

值得注意的是,如果原始數據集中所有的聚類都是緊湊並且分割良好的,那么所有這些度量都會得到同樣的層次聚類結果,否則,它們會得到相當不同的結構。

同時,上述討論的這些距離度量都有一個技術上的缺陷,即它們的結果依賴於距離度量的數值規模。最小和最大距離度量得到的結果強依賴於距離的大小順序(ordering)。如果對所有的距離進行單調變換,即使保持它們的相對順序不變,基於中心和基於平均距離的聚類結果也會改變,其他的也會不同程度受到影響。

筆者思考

我們在工程項目中相似度匹配方法,就是單鏈接最小距離聚類的一種特殊應用。在實際情況中,我們會有一個所謂的黑規則庫,這代表了一個聚類集。對於新的實例我們會將其和這個聚類集進行比較,如果找到了一個”匹配“,即新實例和聚類集中任意某個實例非常接近,則將這個新實例歸入到黑規則聚類集中。這樣,經過一段時間后,黑規則聚類集就會不斷擴大。就像完成了一個自我生長過程一樣

2. 合並終止條件

基於鏈接的聚類算法是凝聚式的,一開始,數據完全是碎片化的,然后逐步構建越來越大的聚類,如果我們沒有加入停止規則,鏈接算法的結果可以用聚類系統樹圖來描述,即,一個域子集構成的樹,其葉子節點是單元素集,根節點為全域。例如下圖所示:

常用的停止准則包括:

  • 固定類的數量:固定參數 k,當聚類數目為 k 時停止聚類。使用這種停止准則需要我們對我們的場景要有較強的領域知識,即預先知道需要聚類的數量
  • 設定距離上限:設定域子集間距最大上限,如果在某一輪迭代中,所有的組件距離都超過該閾值,則停止聚類

使用這種停止准則,實際上隱含了一種假設,即相似的樣本在特征空間上距離很近,且聚集在一個較小的區域內,彼此之間距離較近。而不同類別的樣本在族群上彼此會拉開距離。所以通過設定一定的距離上限,可以在對一個族群聚集完畢后及時收斂停止,開啟新族群的聚集

0x2:單鏈接/平均鏈接/最大鏈接聚類效果對比

# -*- coding:utf-8 -*-

from time import time

import numpy as np
from scipy import ndimage
from matplotlib import pyplot as plt

from sklearn import manifold, datasets

digits = datasets.load_digits(n_class=10)
X = digits.data
y = digits.target
n_samples, n_features = X.shape

np.random.seed(0)

def nudge_images(X, y):
    # Having a larger dataset shows more clearly the behavior of the
    # methods, but we multiply the size of the dataset only by 2, as the
    # cost of the hierarchical clustering methods are strongly
    # super-linear in n_samples
    shift = lambda x: ndimage.shift(x.reshape((8, 8)),
                                  .3 * np.random.normal(size=2),
                                  mode='constant',
                                  ).ravel()
    X = np.concatenate([X, np.apply_along_axis(shift, 1, X)])
    Y = np.concatenate([y, y], axis=0)
    return X, Y


X, y = nudge_images(X, y)


#----------------------------------------------------------------------
# Visualize the clustering
def plot_clustering(X_red, X, labels, title=None):
    x_min, x_max = np.min(X_red, axis=0), np.max(X_red, axis=0)
    X_red = (X_red - x_min) / (x_max - x_min)

    plt.figure(figsize=(6, 4))
    for i in range(X_red.shape[0]):
        plt.text(X_red[i, 0], X_red[i, 1], str(y[i]),
                 color=plt.cm.spectral(labels[i] / 10.),
                 fontdict={'weight': 'bold', 'size': 9})

    plt.xticks([])
    plt.yticks([])
    if title is not None:
        plt.title(title, size=17)
    plt.axis('off')
    plt.tight_layout()

#----------------------------------------------------------------------
# 2D embedding of the digits dataset
print("Computing embedding")
X_red = manifold.SpectralEmbedding(n_components=2).fit_transform(X)
print("Done.")

from sklearn.cluster import AgglomerativeClustering

for linkage in ('ward', 'average', 'complete'):
    clustering = AgglomerativeClustering(linkage=linkage, n_clusters=10)
    t0 = time()
    clustering.fit(X_red)
    print("%s : %.2fs" % (linkage, time() - t0))

    plot_clustering(X_red, X, clustering.labels_, "%s linkage" % linkage)


plt.show()

單純就這個數字聚類的場景來看,平均鏈接聚類的效果最好

0x3:鏈接算法模型

決定鏈接算法具體形式的最重要的因素就是“域間相似性度量函數”,因此可分為單鏈接、平均鏈接、最大鏈接 這3種。

1. 單鏈接聚類算法

單鏈接算法和 Kruskal 算法很相似,目的是在加權圖上找到一個最小生成樹。

從圖的視角來看單鏈接算法的算法運行過程,圖的頂點是 X 中的元素,邊(x,y)的權重是距離 d(x,y)。每次單鏈接算法將兩個聚類進行合並,相當於在一顆樹中添加一條邊。

單鏈接算法得到的邊集合和最小生成樹是一致的。

2. 平均鏈接聚類算法

3. 最大鏈接聚類算法

Relevant Link:

http://scikit-learn.org/stable/auto_examples/cluster/plot_digits_linkage.html#sphx-glr-auto-examples-cluster-plot-digits-linkage-py
http://scikit-learn.org/stable/modules/clustering.html#hierarchical-clustering 

 

5. DBSCAN(Density-Based Spatial Clustering of Application with Noise) - 基於密度的聚類算法

基於密度的聚類方法與其他方法的一個根本區別是:它不是基於各種各樣的距離度量的,而是基於密度的。因此它能克服基於距離的算法只能發現“類圓形”的聚類的缺點。DBSCAN的指導思想是:

用一個點的∈鄰域內的鄰居點數衡量該點所在空間的密度,只要一個區域中的點的密度大過某個閾值,就把它加到與之相近的聚類中去

它可以找出形狀不規則(oddly-shaped)的cluster,且聚類時不需要事先知道cluster的個數

0x1:DBSCAN模型

考慮數據集合,首先引入以下概念與數學記號:

1. ∈鄰域(∈ neighborhood)

,稱為 x 的∈鄰域。顯然,

2. 密度(density)

,稱為 x 的密度。注意,這里的密度是一個整數值,且依賴於半徑

3. 核心點(core point)

,若(核心點閾值 minimum numberof points required to form a cluster),則稱 x 為 X 的核心點。記由 X 中所有核心點構成的集合為,並記表示由 X 中的所有非核心點構成的集合

4. 邊界點(border point)

滿足。即 x 的鄰域中存在核心點,則稱 x 為 X 的邊界點。記由 X 中所有邊界點構成的集合為

此外,邊界點也可以這么定義,若,且 x 落在某個核心點的鄰域內,則稱 x 為 X 的一個邊界點。一個邊界點可能同時落入一個或多個核心點的∈鄰域

5. 噪音點(noise point)

,則稱 x 為噪音點

直觀上來說,核心點對應稠密區域內部的點,邊界點對應稠密區域邊緣的點,而噪音點對應稀疏區域中的點。如下圖所示:

需要注意的是,核心點位於簇的內部,它確定無誤地屬於某個特定的簇;噪音點是數據集中的干擾數據,它不屬於任何一個簇;而邊界點是一類特殊的點,它位於一個或幾個簇的邊緣地帶,它可能屬於一個簇,也可能屬於另外一個簇,其簇歸屬並不明確

6. 直接密度可達(directly density-reachable)

,則稱 y 是從 x 直接密度可達的

7. 密度可達(density-reachable)

,若它們滿足直接密度可達的,,則稱是從密度可達的

值得注意的是,當 m = 2時,密度可達即為直接密度可達。密度可達是直接密度可達的一種推廣。事實上,密度可達是直接密度可達的傳遞閉包

8. 密度相連(density-connected)

,若 y 和 z 均是從 x 密度可達的,則稱 y 和 z 是密度相連的。顯然,密度相連具有對稱性

9. 類(cluster)

稱非空集合是 X 的一個類(cluster),如果它滿足:對於

(1)Maximality:若,且 y 是從 x 密度可達的,則

(2)Connectivity:若,則 x,y 是密度相連的

0x2:DBSCAN算法過程

DBSCAN算法的核心思想如下:從某個選定的核心點出發,不斷向密度可達的區域擴張,從而得到一個包含核心點和邊界點的最大化區域,區域中任意亮點密度相連

考慮數據集合。DBSCAN算法的目標是將數據集合 X 分成 K 個cluster(k由算法自動推斷得到,無需事先指定)及噪音點組成,為此,引入cluster標記數組

由此,DBSCAN算法的目標就是生成標記數組,而 K 即為中互異的非負數的個數

輸入:樣本集D=(x1,x2,...,xm),鄰域參數(ϵ,MinPts), 樣本距離度量方式

輸出: 簇划分C. 

可以看到,DBSCAN在不斷發現新的核心點的同時,還通過直接密度可達,發現核心點鄰域內的核心點,並把這些鄰域內的核心點都歸納到第 k 個聚類中。而噪音點沒每輪 k 聚類中會被全局過濾不會參與下一輪啟發式發現中,只有邊界點在下一次跌打中會被再次嘗試檢驗是否能夠成為新聚類的核心點

0x3:hello world!DBSCAN

# -*- coding:utf-8 -*-

import numpy as np

from sklearn.cluster import DBSCAN
from sklearn import metrics
from sklearn.datasets.samples_generator import make_blobs
from sklearn.preprocessing import StandardScaler


# #############################################################################
# Generate sample data
centers = [[1, 1], [-1, -1], [1, -1]]
X, labels_true = make_blobs(n_samples=750, centers=centers, cluster_std=0.4,
                            random_state=0)

X = StandardScaler().fit_transform(X)

# #############################################################################
# Compute DBSCAN
db = DBSCAN(eps=0.3, min_samples=10).fit(X)
print db.labels_
core_samples_mask = np.zeros_like(db.labels_, dtype=bool)
print core_samples_mask
core_samples_mask[db.core_sample_indices_] = True
labels = db.labels_

# Number of clusters in labels, ignoring noise if present.
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)

print('Estimated number of clusters: %d' % n_clusters_)
print("Homogeneity: %0.3f" % metrics.homogeneity_score(labels_true, labels))
print("Completeness: %0.3f" % metrics.completeness_score(labels_true, labels))
print("V-measure: %0.3f" % metrics.v_measure_score(labels_true, labels))
print("Adjusted Rand Index: %0.3f"
      % metrics.adjusted_rand_score(labels_true, labels))
print("Adjusted Mutual Information: %0.3f"
      % metrics.adjusted_mutual_info_score(labels_true, labels))
print("Silhouette Coefficient: %0.3f"
      % metrics.silhouette_score(X, labels))

# #############################################################################
# Plot result
import matplotlib.pyplot as plt

# Black removed and is used for noise instead.
unique_labels = set(labels)
colors = [plt.cm.Spectral(each)
          for each in np.linspace(0, 1, len(unique_labels))]
for k, col in zip(unique_labels, colors):
    if k == -1:
        # Black used for noise.
        col = [0, 0, 0, 1]

    class_member_mask = (labels == k)

    xy = X[class_member_mask & core_samples_mask]
    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
             markeredgecolor='k', markersize=14)

    xy = X[class_member_mask & ~core_samples_mask]
    plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=tuple(col),
             markeredgecolor='k', markersize=6)

plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()

Relevant Link: 

http://shiyanjun.cn/archives/1288.html
https://en.wikipedia.org/wiki/DBSCAN 
https://www.cnblogs.com/hdu-2010/p/4621258.html
http://blog.csdn.net/itplus/article/details/10088625
https://www.cnblogs.com/pinard/p/6208966.html
http://blog.csdn.net/xieruopeng/article/details/53675906
http://www.cnblogs.com/aijianiula/p/4339960.html
http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html

 

6. Clustering by fast search and find of density peaks(CFSFDP聚類)- 基於密度(Density)的聚類

該算法是Alex Rodriguez和Alessandro Laio在Science上發表的《Clustering by fast search and find of density peaks》所提出的一種新型的基於密度的聚類算法。

0x1:算法思想

該聚類算法的核心思想在於對聚類中心(cluster centers)的刻畫上,算法認為聚類中心同時具有以下兩個特點:

1. 聚類中心本身密度大,即它被密度均不超過它的鄰居包圍,或者說聚類中心是整個簇中密度最大的點;
2. 聚類中心與其他密度更大的數據點之間的“距離”相對更大;

0x2:算法模型

該算法的假設類簇(cluster centers)的中心由一些局部密度比較低的點圍繞,並且這些點距離其他有高局部密度的點的距離都比較大。

對於樣本集中的任何數據點s,可以定義兩個值:局部密度ρi以及到高局部密度點的距離δi,這兩個值僅僅取決於兩點之間的距離dij。

1. 局部密度ρi

包括 Cut-off kernel 和 Gaussian kernel 兩種計算方式

1)Cut-off kernel:階躍統計函數,只關注數據點是否在dc閾值范圍內

其中函數

參數稱為截斷距離(cutoff distance),需要在算法啟動時顯式指定。
從該模型公式中可以看出,局部密度 ρi 表示的是樣本集 S 中與數據點 xi 之間的的距離小於 dc 的數據點。

這里 dc 可以理解為一個邊界閾值,dc 設置的越小,表示希望算法對聚類的敏感度越高,即在盡可能小的區域內發現聚類社區。

2)Gaussian kerne:柔性距離統計函數

和 cut-off kernel一樣,與 x 的距離小於 dc 的數據點越多,pi 的值越大。

對比上面兩式可以看出,cut-off kernel為離散值,Gaussian kernel為連續值,因此,相對來說,Gaussian產生沖突(即不同的數據點具有相同的局部密度值)的概率更小

2. 到高局部密度點的距離δi

表示數據點局部密度的一個降序排列下標序,即它滿足:

則可以定義:

這個公式非常優美,它定義了:

1)當 Xi 具有最大局部密度時,δi 表示 S 中與 Xi 距離最大的數據點與 Xi 之間的距離;
2)否則,δi 表示在所有局部密度大於 Xi 的數據點中(即其他cluster centers),與 Xi 距離最小的那個(或那些)數據點與 Xi 之間的距離。

0x3:聚類過程

至此,對於 S 中的每一個數據點 Xi,可以通過進行抽象表征。考慮下圖的例子,其中包含28個二維數據點,將二元對在平面上畫出來。

我們看到,1號和10號數據點由於同時具有較大的局部密度和類間距離,於是從數據集中“脫穎而出(pop up)”了,而這兩個數據點恰好是左圖中數據集的兩個聚類中心。

此外,26,27,28這三個數據點在原始數據集中是“離群點”,它們在右圖中也很有特點:其局部密度很小,類間距離很大

從直觀上來理解,上面右圖對確定聚類中心(cluster centers)有決定性作用,因此也將這種由對應的圖稱為決策圖(decision graph)

聚類中心確定之后,剩余點被分配給與其具有較高密度的最近鄰居相同的類簇。與其他迭代優化的聚類算法不同,類簇分配在單個步驟中執行。

在聚類分析中, 通常需要確定每個點划分給某個類簇的可靠性。

在該算法中, 可以首先為每個類簇定義一個邊界區域(border region), 亦即划分給該類簇但是距離其他類簇的點的距離小於dc的點,這個區域中的點集可以認為是圈出了聚類中心的整體。然后為每個類簇找到其邊界區域的局部密度最大的點,該類簇中所有局部密度大於該點的局部密度的點被認為是類簇核心的一部分(亦即將該點划分給該類簇的可靠性很大),其余的點被認為是該類簇的光暈, 亦即可以認為是噪音(outlier)。

圖A表示點分布,其中包含非球形點集和雙峰點集。B和C分別表示4000和1000個點按照A中模式的分布,其中點根據其被分配的不同類簇着色,黑色的點屬於類簇光暈。D和E是對應的決策圖,而F表示的是不同點量下不正確聚類點的比率,誤差線代表平均值的標准差。

下圖是分別利用點集和Olivetti臉部圖片集的聚類結果

0x4:算法形式化描述

設待聚類數據集,其包含個cluster

值得注意的是,該聚類算法得到的聚類中心可以作為其他聚類算法(例如k-means)的初始聚類中心。

Relevant Link:

http://science.sciencemag.org/content/344/6191/1492
https://segmentfault.com/a/1190000011337432
https://blog.csdn.net/itplus/article/details/38926837

 

7. SOM(Self-organizing Maps)- 基於模型的聚類(model-based methods)

基於模型的方法給每個聚類假定一個模型(預先設定),然后尋找能夠很好地滿足這個模型的數據集。這樣一個模型可能是數據點在空間中的密度分布函數或者其他。它的一個潛在的假定就是:

目標數據集是由一系列的概率分布所決定的

通常有兩種嘗試方向:統計方案;和神經網絡方案

關於神經網絡方案方面的討論可以參閱我之前的一篇blog

Relevant Link:

http://www.cnblogs.com/LittleHann/p/7101992.html

 

8. GMM(Gaussian Mixture Model, 高斯混合模型)- 基於概率的聚類(probability-based methods)

0x1:傳統硬分類(hard decision)聚類算法存在的挑戰

  • 以分類效用公式為驅動力的聚類算法,為了避免過度擬合必須選擇除數k,即需要提供一個人為的聚類標准差最小值,以及為避免每個實例成為一個聚類的特定的截止值
  • 增量啟發式算法本身存在不確定性:
    • 結果在多大程度上依賴於實例的輸入順序
    • 合並、分裂等局部重建操作是否足以扭轉由於不好的實例次序所帶來的糟糕的初始決定
    • 最終結構是否代表分類效用的局部最大值
    • 無法知道最終的結果離全局最大值到底有多遠
    • 結果的層次性也不能回避哪個是最好的聚類這個問題
  • 互斥的聚類划分引入了脆弱性,位於灰色地帶的樣本很可能會被錯誤地分到錯誤的聚類中。同時不小心引入的離群點可能會極大地破壞原本有效的聚類划分

為了緩解上述問題,一個更為理論性的統計學方法可以克服聚類問題的部分上述缺點。

從概率的角度看,聚類的目標是尋找給定數據的最有可能的集合。由於任何有限數量的證據都不足以對某件事做完全肯定的結論,所以實例甚至是訓練實例也不能絕對地被分在這個聚類或那個聚類。而應當說實例都以一定的可能性分屬於每個聚類。這有助於消除那些硬性而快速的判斷方案引發的脆弱性。

0x2:概率聚類基本概念

統計聚類的基礎是建立在一個稱為有限混合(finite mixture)的統計模型上。

混合是指用k個概率分布代表k個聚類,控制聚類成員的屬性值。換句話說,對某個具體實例,每個分布給出假設已知實例屬於這個聚類,並且它有某組屬性值集合的概率(即 P(v | C))。

每個聚類都有不同的分布,任何具體實例”實際上“屬於且只屬於一個聚類,但不知道是哪個。最后,各個聚類並不是等可能的,存在某種反映它們相對總體數量的概率分布。

以一維情況為例,最簡單的有限混合情況是在一個一維坐標軸上的數值屬性,每個聚類都是一個高斯分布,但有不同的均值和方差。我們的目標是計算每個聚類的平均值和方差,以及聚類之間的總體分布。混合模型將幾個正態分布組合起來,它的概率密度函數看起來就像一組連綿的山脈,每座山峰代表一個高斯分布。

一個二類混合模型

上圖中有兩個聚類A和B,每個都呈正態分布,

  • 聚類A的均值和標准差分別是μA和σA
  • 聚類B的均值和標准差分別是μB和σB
  • 從這些分布中抽樣,聚類A的抽樣概率為pA,聚類B的抽樣概率為pB,pA+pB=1

現在,想象所給的數據集沒有類值,只有數據,要求確定模型的5個參數:(μA,σA,μB,σB,pA),這就是有限混合問題

0x3:概率聚類訓練

關於使用EM算法訓練GMM模型的相關討論,可以參閱另一篇文章

0x4:混合模型預測

如果5個參數一致,要找出某個給定實例來自每種分布的概率是很簡單的。給定實例x,它屬於聚類A的概率是:

這里,是聚類A的正態分布函數,即:

在做比較時,分母Pr[x]會被消除,只要比較分子大小即可。這和朴素貝葉斯分類是一樣的,都是簡單的貝葉斯定理的應用。

Relevant Link: 

https://baike.baidu.com/item/GMM/4258031?fr=aladdin 

 

 

 


免責聲明!

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



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