1. 程式人生 > >Python 用凝聚層次聚類進行資料分組

Python 用凝聚層次聚類進行資料分組

本文主要參考《Python機器學習經典例項》

    在介紹凝聚層次聚類之前,我們需要先理解層次聚類(hierarchical clustering)。層次聚類是一組聚類演算法,通過不斷地分解或合併叢集來構建樹狀叢集(tree-like clusters)。層次聚類的結構可以用一顆樹表示。層次聚類演算法可以是自下而上的,也可以是自上而下的。具體是什麼含義呢?在自下而上的演算法中,每個資料點都被看作是一個單獨的叢集。這些叢集不斷地合併,直到所有的叢集都合併成一個巨型叢集。這被稱為凝聚層次聚類。與之相反的是,自上而下層次的演算法是從一個巨大的叢集開始,不斷地分解,直到所有的叢集變成一個單獨的資料點。

你可以在http://nlp.stanford.edu/IR-book/html/htmledition/hierarchical-agglomerative-clustering-1.html學習更多的內容。

詳細步驟

(1) 首先建立agglomerative.py檔案,然後匯入一些需要用到的程式包:

import numpy as np  
import matplotlib.pyplot as plt  #用於畫圖工具
from sklearn.cluster import AgglomerativeClustering #層次聚類
from sklearn.neighbors import kneighbors_graph #最鄰近搜尋

(2) 定義一個實現凝聚層次聚類的函式:

def perform_clustering(X, connectivity, title, num_clusters=3, linkage='ward'):
    plt.figure()
    # 定義凝聚層次聚類模型
    model = AgglomerativeClustering(linkage=linkage,connectivity=connectivity, n_clusters=num_clusters)
    model.fit(X)  # 訓練模型

(3) 提取標記,然後指定不同聚類在圖形中的標記:

labels = model.labels_  # 提取標記
markers = '.vx' # 為每種叢集設定不同的標記

(4) 迭代資料,用不同的標記把聚類的點畫在圖形中:

for i, marker in zip(range(num_clusters), markers):
    # 畫出屬於某個叢集中心的資料點
    plt.scatter(X[labels==i, 0], X[labels==i, 1], s=50,marker=marker, color='k', facecolors='none')
plt.title(title)

注意:看到這裡可能會有些有些疑問函式zip()是什麼?如果有疑問可點選此連結有詳細介紹pythonzip()函式

如果對plt.scatter()有遲疑的話此處有詳細介紹點選開啟鏈,由於篇幅問題這裡就不詳細解釋。

(5) 為了演示凝聚層次聚類的優勢,我們用它對一些在空間中是連線在一起、但彼此卻非常
接近的資料進行聚類。我們希望連線在一起的資料可以聚成一類,而不是在空間上非常接近的點
聚成一類。下面定義一個函式來獲取一組呈螺旋狀的資料點:

# 定義函式獲取螺旋狀的資料點
def get_spiral(t, noise_amplitude=0.5):
    r = t
    x = r * np.cos(t)
    y = r * np.sin(t)
    return add_noise(x, y, noise_amplitude)

(6) 在上面的函式中,我們增加了一些噪聲,因為這樣做可以增加一些不確定性。下面定義
噪聲函式:

def add_noise(x, y, amplitude):
    X = np.concatenate((x, y))
    X += amplitude * np.random.randn(2, X.shape[1])
    return X.T

(7) 我們再定義一個函式來獲取位於玫瑰曲線上的資料點(rose curve,又稱為rhodonea curve,
極座標中的正弦曲線):

def get_rose(t, noise_amplitude=0.02):
    # 設定玫瑰曲線方程;如果變數k是奇數,那麼曲線有k朵花瓣;如果k是偶數,那麼有2k朵花瓣
    k = 5
    r = np.cos(k*t) + 0.25
    x = r * np.cos(t)
    y = r * np.sin(t)
    return add_noise(x, y, noise_amplitude)

(8) 為了增加多樣性,我們再定義一個hypotrochoid函式:

def get_hypotrochoid(t, noise_amplitude=0):
    a, b, h = 10.0, 2.0, 4.0
    x = (a - b) * np.cos(t) + h * np.cos((a - b) / b * t)
    y = (a - b) * np.sin(t) - h * np.sin((a - b) / b * t)
    return add_noise(x, y, 0)

(9) 現在可以定義主函式main了:

if __name__=='__main__':
    # 生成樣本資料
    n_samples = 500
    np.random.seed(2)
    t = 2.5 * np.pi * (1 + 2 * np.random.rand(1, n_samples))
    X = get_spiral(t)
    # 不考慮螺旋形的資料連線性
    connectivity = None
    perform_clustering(X, connectivity, 'No connectivity')
    # 根據資料連線線建立K個臨近點的圖形
    connectivity = kneighbors_graph(X, 10, include_self=False)
    perform_clustering(X, connectivity, 'K-Neighbors connectivity')
    plt.show()

注意:如果你看到 __name__=='__main__'不懂得話可以點開此處點選開啟連結

(10) 執行程式碼,可以看到如圖1所示的圖形(沒有用任何連線特徵)。

                                                                                 圖1


(11) 還可以看到如圖2所示的圖形(使用連線特徵)。
                                                                                圖2