【機器學習(六)】聚類算法一篇就夠。無監督聚類算法:層次聚類、Kmeans聚類、模糊聚類(FCM/模糊Cmeans),從原理、案例和代碼詳細講解。

目錄算法

1.聚類概念app

2.類似度或距離度量dom

2.1 閔可夫斯基距離(Minkowski distance)機器學習

2.2 歐式距離(Euclidean distance)ide

2.3 曼哈頓距離(Manhattan distance)函數

2.4 馬哈拉諾比斯距離(Mahalanobis distance)學習

2.5 相關係數測試

2.6 夾角餘弦優化

2.7 度量方式idea

3. 類或簇的基本概念

3.1 聚類分類

3.2 類或簇

3.3 類的中心

3.4 類的直徑

3.5 類的散佈矩陣

3.6 類的協方差

3.7 類之間最短距離或單鏈接

3.8 類之間最長距離或徹底鏈接

3.9 中心距離

3.10 平均距離

4 層次聚類

4.1 層次聚合

4.2 算法流程:

4.3 案例

5. K均值聚類(Kmeans)

5.1 K均值的聚類策略

5.2 算法流程

5.3 實際案例

5.4 Kmeans的k值選擇

5.5 程序

5.6  K均值聚類特性

6. 模糊聚類(FCM/模糊Cmeans)

6.1 算法流程

6.2 案例


1.聚類概念

聚類是指:把給定樣本,依據它們之間的距離或類似度,劃分爲若干個「類」或「簇」。使得類似度較高的樣本彙集在同一個類,不類似的樣本分散在不一樣的類。

聚類屬於無監督學習,方法不少,最經常使用的是:層次聚類、K均值聚類(Kmeans)、模糊聚類(模糊Cmeans)。在聚類中十分重要的概念就是距離或者類似度度量。

2.類似度或距離度量

聚類的輸入是樣本數據,每一個樣本又由m個屬性的特徵組成,因此輸入能夠定義爲X=\begin{bmatrix} x_1_1 x_1_2 ...x_1_n \\ x_2_1 x_2_2 ...x_2_n \\ ... ......\\ x_m_1 x_m_2 ...x_m_n \end{bmatrix},其中,行數是維度的個數,列數是樣本的個數。在計算距離或類似度的時候,有多種方法,通常是距離、相關係數夾角餘弦。一般狀況下:

距離越小,類似度越高;距離越大,類似度越低。

相關係數越接近1,類似度越高;相關係數越接近0,類似度越低。

夾角餘弦越接近1,類似度越高;夾角餘弦越接近0,類似度越低。

2.1 閔可夫斯基距離(Minkowski distance)

d_i_j=(\sum_{k=1}^{m}|x_k_i-x_k_j|)^\frac{1}{p},其中(p\geq 1

2.2 歐式距離(Euclidean distance)

當p=2的時候,即爲歐式距離:d_i_j=(\sum_{k=1}^{m}|x_k_i-x_k_j|)^\frac{1}{2}

2.3 曼哈頓距離(Manhattan distance)

當p=1的時候,即爲曼哈頓距離:d_i_j=\sum_{k=1}^{m}|x_k_i-x_k_j|

2.4 馬哈拉諾比斯距離(Mahalanobis distance)

馬哈拉諾比斯距離簡稱爲馬氏距離,考慮各個份量之間的相關性與各個份量的尺度相關性。馬氏距離越大,則類似度越小;馬氏距離越小,則類似度越大。

定義輸入樣本X的協方差矩陣爲S,則樣本x_ix_j的馬氏距離爲:d_i_j=((x_i-x_j)^TS^-^1(x_i-x_j))^\frac{1}{2},其中x_i=(x_1_i,x_2_i,...,x_m_i)^T即第i列特徵值,x_j=(x_1_j,x_2_j,...,x_m_j)^T,即第j列特徵值。

2.5 相關係數

樣本之間的類似度除了用距離度量外,還可使用相關係數(correlation coefficient)來表示。與距離度量不一樣,相關係數越接近1,則表示樣本越類似;相關係數越接近於0,表示樣本越不類似。

通常x_ix_j的相關係數定義爲:r_i_j=\frac{\sum_{k=1}^{m}(x_k_i-\bar{x}_i)(x_k_j-\bar{x}_j)}{[\sum_{k=1}^{m}(x_k_i-\bar{x}_i)^2(x_k_j-\bar{x}_j)^2]^\frac{1}{2}},其中\bar{x}_i=\frac{1}{m}\sum_{k=1}^{m}x_k_i\bar{x}_j=\frac{1}{m}\sum_{k=1}^{m}x_k_j

2.6 夾角餘弦

樣本之間的類似度還能夠用夾角餘弦表示,夾角餘弦值越接近1,表示樣本越類似;夾角預餘弦值越接近0,表示樣本越不類似。

夾角餘弦能夠定位爲:s_i_j=\frac{\sum_{k=1}^{m}x_k_ix_k_j}{[\sum_{k=1}^{m}x_k_i^2\sum_{k=1}^{m}x_k_j^2]^\frac{1}{2}}

2.7 度量方式

不一樣度量方式獲得的結果不必定一致,具體採用哪一種度量方式,須要結合本身實際狀況出發。例以下圖

從距離上看,A與B的距離更近,所以A和B比A和C更類似;從夾角餘弦上看,A和C比A和B更類似。

 

3. 類或簇的基本概念

經過聚類,能夠獲得類或簇,它是輸入樣本的子集。瞭解距離和類似度量的方式後,就須要瞭解聚類中經常使用的一些概念,這樣在後續的計算中,可以不使得概念混淆。

3.1 聚類分類

硬聚類:假定一個樣本智能屬於一個類,或類的交集爲空集,這種聚類屬於硬聚類。本文中的層次聚類、K均值聚類和模糊聚類屬於硬聚類

軟聚類:若是一個樣本能夠屬於多個類,或類的交集不爲空集,那麼這種方法稱爲軟聚類。

3.2 類或簇

G表示類或簇,x_ix_j表示勒種的樣本,n_G表示G中樣本的個數。d_i_j表示x_ix_j的距離。

哪怎樣算是一個類或簇?

給定一個正數T,若d_i_j\leq T,則能夠稱G爲一個類或簇

給定一個正數T,若\frac{1}{n_G-1}\sum d_i_j\leq T,能夠稱G爲一個類或簇

給定一個正數T,若\frac{1}{n_G(n_G-1)}\sum\sum d_i_j\leq T能夠稱G爲一個類或簇

因此,當某個集合中內,任意樣本之間距離小於等於給定的正數,那麼就能夠認爲這個集合是一個類或簇。

3.3 類的中心

類的中心指的就是類的均值,定義爲:\bar{x}_G=\frac{1}{n_G}\sum_{i=1}^{n_G}x_i

3.4 類的直徑

類的直徑是指任意兩個樣本之間最大的距離,定義爲:D_G=max\{d_i_j\}

3.5 類的散佈矩陣

定義爲:A_G=\sum_{i=1}^{n_G}(x_i-\bar{x}_G)(x_i-\bar{x}_G)^T,衡量類中樣本的分散狀況,相似方差。

3.6 類的協方差

定義爲:S_G=\frac{1}{m-1}\sum_{i=1}^{n_G}(x_i-\bar{x}_G)(x_i-\bar{x}_G)^T,衡量樣本之間的相關性。

3.7 類之間最短距離或單鏈接

G_p與類G_p樣本之間的最短距離定義爲兩個類之間的最短距離:D_p_q=min\{d_i_j|x_i\epsilon G_p,x_j\epsilon G_q\}

3.8 類之間最長距離或徹底鏈接

G_p與類G_p樣本之間的最短距離定義爲兩個類之間的最短距離:D_p_q=max\{d_i_j|x_i\epsilon G_p,x_j\epsilon G_q\}

3.9 中心距離

G_p與類G_p的類中心\bar{x_p}\bar{x_p}之間的距離爲兩個類之間的中心距離:D_p_q=d_{\bar{x}_p}_{\bar{x}_q}

3.10 平均距離

G_p與類G_p的任意兩個樣本之間的平均距離爲兩個類之間的平均距離:D_p_q=\frac{a}{n_pn_q}\sum_{x_i\epsilon G_p}\sum_{x_i\epsilon G_q} d_i_j

 

4 層次聚類

瞭解聚類的距離和類似度以及基礎概念,就能夠開始進行聚類分析。

所謂層次聚類,是指按照層次的方法找類之間的層次關係,有層次聚合(自下而上)、層次分裂(自上而下)兩種方法。

以下圖,層次聚合是指,初始的時候,每一個樣本單獨屬於一個類,而後按照類之間距離最小合併的原則,迭代合併類,直至合併到指定類的個數,或者只有1個類。層次分裂聚類與層次聚合相反,咱們僅介紹聚合聚類。

4.1 層次聚合

輸入:n個樣本組成的樣本集合X

輸出:對X的一個層次化聚類

4.2 算法流程:

  1. 計算n個樣本兩兩之間的歐式距離,記作距離矩陣D=[d_i_j]_{nn}
  2. 構造n個類,每個類只包含一個樣本
  3. 合併類間距離最小的兩個類,構建一個新的類;
  4. 計算新的類與當前各種的距離。若類的個數爲1,或者指定個數,則終止計算;不然回到3

4.3 案例

隨機生成100個二維數據,按照層次聚類進行聚類。當K=4的時候,獲得的聚類效果以下。

這100個樣本的類標籤:cluster labels:[1 0 0 1 3 0 0 3 0 0 1 0 0 0 0 0 0 0 0 0 0 1 3 0 1 3 1 0 0 0 3 0 0 0 3 0 2 0 1 1 0 0 0 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0]

代碼以下:

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import pdist
from scipy.cluster.hierarchy import linkage
from scipy.cluster.hierarchy import dendrogram
from sklearn.cluster import AgglomerativeClustering

colo = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
# x = np.random.randint(0, 10, [100, 2])
x = 10 * np.random.rand(100, 2)
shape = x.shape
K = 4  # 簇個數

# 分析層次聚類
row_clusters = linkage(pdist(x, metric='canberra'), method='complete')
'''
pdist:計算樣本距離,其中參數metric表明樣本距離計算方法
(euclidean:歐式距離、minkowski:明氏距離、chebyshev:切比雪夫距離、canberra:堪培拉距離)
linkage:聚類,其中參數method表明簇間類似度計算方法
(single:  MIN、ward:沃德方差最小化、average:UPGMA、complete:MAX)
'''
row_dendr = dendrogram(row_clusters)
plt.tight_layout()
plt.title('canberra-complete')
plt.show()
# 層次聚類
clf = AgglomerativeClustering(n_clusters=K, affinity='canberra', linkage='complete')
labels = clf.fit_predict(x)
print('cluster labels:%s' % labels)
for k, col in zip(range(0, K), colo):
    X = labels == k
    plt.plot(x[X, 0], x[X, -1], col + 'o')
plt.xlabel('x')
plt.ylabel('y')
plt.title('hierarchical_clustering')
plt.show()

 

5. K均值聚類(Kmeans)

K均值聚類是最經常使用的聚類方法,這是一種基於集合劃分的聚類算法。

K均值聚類把樣本集合劃分爲k個子集,構成k個類,將n個樣本分配到k個類中,每一個樣本到所屬類的中心距離最小。

5.1 K均值的聚類策略

k均值聚類是經過最小化損失函數選取最優的劃分或函數C^*,即採用歐式距離做爲樣本之間的距離度量d_i_j=||x_i-x_j||^2,而後定義樣本與述所類的中心的距離總和損失函數:W(C)=\sum_{l=1}^{k}\sum_{C(i)=l}^{}|||x_i-\bar{x}_l||^2,其中l表明聚類的中心。因此K均值聚類就是最優化W(C)的問題,在實現中,解決這類

問題的方法是經過迭代方法求解

5.2 算法流程

輸入:n個樣本的集合X

輸出:樣本的聚類C^*

  1. 初始化,令t=0,隨機選擇k個樣本做爲初始類中心m^{(0)}=(m^{(0)}_1,m^{(0)}_2,...,m^{(0)}_k)
  2. 樣本聚類:計算每一個樣本到每一個類中心的距離,將每一個樣本指派到與其最近的類,構成聚類結果C^{(t)}
  3. 計算新的類中心:對聚類結果C^{(t)},計算類中全部樣本的均值,做爲新的聚類中心;
  4. 若是迭代收斂,或者符合中止條件,輸出C^*=C^{(t)};不然,令t=t+1,返回第2步。

5.3 實際案例

利用k均值聚算法求5個樣本的二維數據集合

 

5.4 Kmeans的k值選擇

K均值的類別數,一般狀況下是人爲指定的。在實際應用應用中,每每不知道K取多少是最合適,所以一般是使用嘗試的方法,即令k=2到x(x本身設定,少於樣本個數的一半便可)。可使用手肘法選擇k值,即經過每一個k值下的均方差曲線的手肘點做爲最優的k值。也能夠選擇使用輪廓係數法做爲依據,選擇使輪廓最大的值對應的k值爲最優k值。

5.5 程序

下面程序實現的是,隨機選擇100個二維樣本,對其進行聚類,k值的從2依次遞增到7。

下圖是k取不一樣值時候的均方偏差曲線,從圖中能夠看出,手肘點在k=4的時候。要是以此爲選擇依據的話,K=4時有最優的聚類結果

下圖是輪廓係數法求出的值,能夠看出,當K=4的時候,輪廓係數最大。若以輪廓係數爲選擇依據,那麼K=4的時候有最優的聚類結果。

代碼以下:

import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt

# colo = [[0, 0, 255], [0, 255, 0], [255, 0, 0], [0, 255, 255], [255, 255, 0], [255, 0, 255], [255, 255, 255]]
colo = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
# x = np.random.randint(0, 10, [100, 2])
x = 10 * np.random.rand(100, 2)
shape = x.shape
sse = []
score = []
K = 8
for k in range(2, K):
    clf = KMeans(n_clusters=k)
    clf.fit(x)
    sse.append(clf.inertia_)
    lab = clf.fit_predict(x)
    score.append(silhouette_score(x, clf.labels_, metric='euclidean'))
    for i in range(shape[0]):
        plt.xlabel('x')
        plt.ylabel('y')
        plt.title('k=' + str(k))
        plt.plot(x[i, 0], x[i, -1], colo[lab[i]] + 'o')
    plt.show()

X = range(2, K)
plt.xlabel('k')
plt.ylabel('sse')
plt.title('sum of the squared errors')
plt.plot(X, sse, 'o-', )
plt.show()

plt.xlabel('k')
plt.ylabel('Score')
plt.title('Silhouette Coefficient')
plt.plot(X, score, 'o-', )
plt.show()

5.6  K均值聚類特性

  • K均值聚類每每是事先指定k值,以歐式距離做爲衡量樣本距離的方法。以樣本到所屬類中心距離總和做爲目標函數。算法是使用迭代計算,每每不能獲得全局最優。
  • K均值聚類屬於啓發式方法,初始中心的選擇會直接影響到聚類的結果
  • K均值聚類如何選擇K,一般須要嘗試不一樣的k值,經過手肘法或者輪廓係數法肯定最優k值。

 

6. 模糊聚類(FCM/模糊Cmeans)

模糊聚類是指模糊C均值聚類(Fuzzy Cmeans),簡寫爲FCM或者模糊Cmeans,同Kmeans同樣,是一種被普遍應用的聚類算法。經過測試,發現,模糊Cmeans的聚類效果比Kmeans要優秀。

模糊聚類引入一個隸屬度矩陣u,它是衡量當前樣本屬於某個類的可能性大小。當前樣本可能屬於類1,也可能屬於累2,所以這種聚類成爲模糊聚類。

若數據集X被劃分紅c個類,那麼有c個類中心,樣本x_j與類中心c_i的隸屬度爲u_i_j,因而就有約束函數:

J=\sum_{i=1}^{c}\sum_{j=1}^{n}u_i_j^m||x_j-c_i||^2,其中m是隸屬度因子。

接下來就是利用約束函數求解u_i_jc_i,採用的拉格朗日乘數法(具體推導,點擊:聚類之詳解FCM算法原理及應用,這裏就不作詳細介紹),獲得u_i_jc_i相互關聯的。在算法開始的時候,假設其中一個值(例如u_i_j),經過迭代計算,u_i_jc_i經過對方得計算本身。

能夠簡單u_i_j是樣本屬於摸個類的可能性大小,c_i是樣本與貢獻度乘積的結果。

6.1 算法流程

輸入:樣本X,類的個數c,隸屬度因子m(通常取2),迭代次數

輸出:模糊Cmeans聚類結果

  1. 肯定分類個數c,指數m的值,肯定迭代次數(這是結束的條件,固然結束的條件能夠有多種)。
  2. 初始化一個隸屬度u_i_j(和爲1);
  3. 根據u_i_j計算聚類中心c_i
  4. 這個時候能夠計算目標函數J
  5. 根據c_i返回去計算u_i_j,回到步驟3,一直循環直到結束。

6.2 案例

隨機取100個二維樣本,分類樣本個數爲4,隸屬度因子爲2.

獲得分類結果:cluster labels:[1 2 2 2 2 0 1 1 0 2 2 2 1 0 0 1 2 3 2 3 1 0 1 2 0 2 1 2 1 0 1 0 0 1 1 3 0 3 2 0 0 0 2 1 0 1 3 1 0 2 0 0 1 3 1 2 1 1 0 0 0 3 3 0 3 3 3 1 3 0 0 0 3 1 1 0 2 3 2 2 1 3 1 0 2 0 1 3 1 1 1 1 2 0 1 1 1 0 1 3]

代碼:

import numpy as np
import matplotlib.pyplot as plt

colo = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
# x = np.random.randint(0, 10, [100, 2])
x = 10 * np.random.rand(100, 2)
shape = x.shape
K = 4  # 簇個數


def FCM(X, c_clusters=3, m=2, eps=10):
    membership_mat = np.random.random((len(X), c_clusters))
    membership_mat = np.divide(membership_mat, np.sum(membership_mat, axis=1)[:, np.newaxis])

    while True:
        working_membership_mat = membership_mat ** m
        Centroids = np.divide(np.dot(working_membership_mat.T, X),
                              np.sum(working_membership_mat.T, axis=1)[:, np.newaxis])

        n_c_distance_mat = np.zeros((len(X), c_clusters))
        for i, x in enumerate(X):
            for j, c in enumerate(Centroids):
                n_c_distance_mat[i][j] = np.linalg.norm(x - c, 2)

        new_membership_mat = np.zeros((len(X), c_clusters))

        for i, x in enumerate(X):
            for j, c in enumerate(Centroids):
                new_membership_mat[i][j] = 1. / np.sum((n_c_distance_mat[i][j] / n_c_distance_mat[i]) ** (2 / (m - 1)))
        if np.sum(abs(new_membership_mat - membership_mat)) < eps:
            break
        membership_mat = new_membership_mat
    return np.argmax(new_membership_mat, axis=1)


labels = FCM(x, c_clusters=K, m=2, eps=10)
print('cluster labels:%s' % labels)
for k, col in zip(range(0, K), colo):
    X = labels == k
    plt.plot(x[X, 0], x[X, -1], col + 'o')
plt.xlabel('x')
plt.ylabel('y')
plt.title('FCM')
plt.show()

下面是使用機器學習庫實現的模糊Cmeans算法,能夠直觀看出,在聚類效果上要比Kmeans要優秀些。

代碼:

import numpy as np
from skfuzzy.cluster import cmeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt

# colo = [[0, 0, 255], [0, 255, 0], [255, 0, 0], [0, 255, 255], [255, 255, 0], [255, 0, 255], [255, 255, 255]]
colo = ['b', 'g', 'r', 'c', 'm', 'y', 'k']
# x = np.random.randint(0, 10, [100, 2])
x = 10 * np.random.rand(100, 2)
shape = x.shape
FPC = []
K = 8
labels = []

for k in range(2, K):
    center, u, u0, d, jm, p, fpc = cmeans(x.T, m=2, c=k, error=0.5, maxiter=10000)
    '''
    注意輸入數據是kemans數據的轉置
    center是聚類中心、u是最終的隸屬度矩陣、u0是初始化隸屬度矩陣
    d是每一個數據到各個中心的歐式距離矩陣,jm是目標函數優化、p是迭代次數
    fpc是評價指標,0最差,1最好
    '''

    label = np.argmax(u, axis=0)
    for i in range(shape[0]):
        plt.xlabel('x')
        plt.ylabel('y')
        plt.title('c=' + str(k))
        plt.plot(x[i, 0], x[i, -1], colo[label[i]] + 'o')
    plt.show()
    print('%d c\'s FPC is:%0.2f' % (k, fpc))
    FPC.append(fpc)

X = range(2, K)
plt.xlabel('c')
plt.ylabel('FPC')
plt.title('FCM-cmeans')
plt.plot(X, FPC, 'o-', )
plt.show()

注意skfuzzy.cluster的安裝方法pip install -U scikit-fuzzy

相關文章
相關標籤/搜索