1. 程式人生 > >機器學習-層次聚類(劃分聚類)

機器學習-層次聚類(劃分聚類)

層次聚類(劃分聚類)

聚類就是對大量未知標註的資料集,按照資料內部存在的資料特徵將資料集劃分為多個不同的類別,使類別內的資料比較相似,類別之間的資料相似度比較小;屬於無監督學習。

演算法步驟

1.初始化的k箇中心點

2.為每個樣本根據距離分配類別

3.更新每個類別的中心點(更新為該類別的所有樣本的均值)

4.重複上面兩步操作,直到達到某個中止條件

 

層次聚類方法對給定的資料集進行層次的分解,直到滿足某種條件為止,傳統的層次聚類演算法主要分為兩大類演算法:

凝聚的層次聚類

AGNES演算法==>採用自底向上的策略。

agglomerative(凝聚) nesting(巢狀)

最初將每個物件作為一個簇,然後這些簇根據某些準則(兩個簇之間的相似度度量方式)被一步一步合併,兩個簇間的距離可以由這兩個不同簇中距離最近的資料點的相似度來確定;聚類的合併過程反覆進行直到所有的物件滿足簇數目。


AGNES就是把每個水果當成一個類別,然後再進行聚類。

 

合併點的選擇:

  • 兩個簇間的最大距離(complete)

  • 兩個簇間的最小距離(word)

  • 兩個簇間的平均距離(average)

適合鏈式的聚類,條狀的就比較適合。

程式碼:

linkages :complete,word,average

import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
# 呼叫AGNES
from sklearn.cluster import AgglomerativeClustering
from sklearn.neighbors import kneighbors_graph  ## KNN的K近鄰計算
import sklearn.datasets as ds
# 攔截異常資訊
import warnings
​
warnings.filterwarnings('ignore')
# 設定屬性防止中文亂碼
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
# 模擬資料產生: 產生600條資料
np.random.seed(0)
n_clusters = 4
N = 1000
data1, y1 = ds.make_blobs(n_samples=N, n_features=2, centers=((-1, 1), (1, 1), (1, -1), (-1, -1)), random_state=0)
​
n_noise = int(0.1 * N)
r = np.random.rand(n_noise, 2)
min1, min2 = np.min(data1, axis=0)
max1, max2 = np.max(data1, axis=0)
r[:, 0] = r[:, 0] * (max1 - min1) + min1
r[:, 1] = r[:, 1] * (max2 - min2) + min2
​
data1_noise = np.concatenate((data1, r), axis=0)
y1_noise = np.concatenate((y1, [4] * n_noise))
# 擬合月牙形資料
data2, y2 = ds.make_moons(n_samples=N, noise=.05)
data2 = np.array(data2)
n_noise = int(0.1 * N)
r = np.random.rand(n_noise, 2)
min1, min2 = np.min(data2, axis=0)
max1, max2 = np.max(data2, axis=0)
r[:, 0] = r[:, 0] * (max1 - min1) + min1
r[:, 1] = r[:, 1] * (max2 - min2) + min2
data2_noise = np.concatenate((data2, r), axis=0)
y2_noise = np.concatenate((y2, [3] * n_noise))
​
​
def expandBorder(a, b):
    d = (b - a) * 0.1
    return a - d, b + d
​
​
## 畫圖
# 給定畫圖的顏色
cm = mpl.colors.ListedColormap(['#FF0000', '#00FF00', '#0000FF', '#d8e507', '#F0F0F0'])
plt.figure(figsize=(14, 12), facecolor='w')
linkages = ("ward", "complete", "average")  # 把幾種距離方法,放到list裡,後面直接迴圈取值
for index, (n_clusters, data, y) in enumerate(((4, data1, y1), (4, data1_noise, y1_noise),
                                               (2, data2, y2), (2, data2_noise, y2_noise))):
    # 前面的兩個4表示幾行幾列,第三個引數表示第幾個子圖(從1開始,從左往右數)
    plt.subplot(4, 4, 4 * index + 1)
    plt.scatter(data[:, 0], data[:, 1], c=y, cmap=cm)
    plt.title(u'原始資料', fontsize=17)
    plt.grid(b=True, ls=':')
    min1, min2 = np.min(data, axis=0)
    max1, max2 = np.max(data, axis=0)
    plt.xlim(expandBorder(min1, max1))
    plt.ylim(expandBorder(min2, max2))
​
    # 計算類別與類別的距離(只計算最接近的七個樣本的距離) -- 希望在agens演算法中,在計算過程中不需要重複性的計算點與點之間的距離
    connectivity = kneighbors_graph(data, n_neighbors=7, mode='distance', metric='minkowski', p=2, include_self=True)
    connectivity = (connectivity + connectivity.T)
    for i, linkage in enumerate(linkages):
        ##進行建模,並傳值
        ac = AgglomerativeClustering(n_clusters=n_clusters, affinity='euclidean',
                                     connectivity=connectivity, linkage=linkage)
        ac.fit(data)
        y = ac.labels_
​
        plt.subplot(4, 4, i + 2 + 4 * index)
        plt.scatter(data[:, 0], data[:, 1], c=y, cmap=cm)
        plt.title(linkage, fontsize=17)
        plt.grid(b=True, ls=':')
        plt.xlim(expandBorder(min1, max1))
        plt.ylim(expandBorder(min2, max2))
​
plt.tight_layout(0.5, rect=(0, 0, 1, 0.95))
plt.show()

AGNES使用不同合併方式的結果:

 

 

分裂的層次聚類(類似於決策樹)

DIANA演算法==>採用自頂向下的策略。

divisive(分裂) analysis(分析)

首先將所有物件置於一個簇中,然後按照某種既定的規則逐漸細分為越來越小的簇(比如利用kmeans),直到達到某個終結條件(簇數目或者簇距離達到閾值)。

1,將所有樣本資料作為一個簇放到一個佇列中2,劃分為兩個子簇(初始化兩個中心點進行聚類),並將子簇新增到佇列中3,迴圈迭代第二步操作,直到中止條件達到(聚簇數量、最小平方誤差、迭代次數)

分割點的選擇:

  • 各自簇的誤差

  • 各自簇的SSE(優選這種策略)

  • 選擇樣本資料量最多的簇

DIANA類似於分麵包

 

AGNES和DIANA

  • 簡單,理解容易

  • 合併點/分裂點選擇不太容易

  • 合併/分類的操作不能進行撤銷(麵包切開就合不上了)

  • 大資料集不太適合

  • 執行效率較低O(t*n2),t為迭代次數,n為樣本點數

AGNES的優化

BIRCH(掌握)

BIRCH演算法(平衡迭代削減聚類法):

聚類特徵使用3元組進行一個簇的相關資訊,通過構建滿足分枝因子和簇直徑限制的聚類特徵樹來求聚類,聚類特徵樹其實是一個具有兩個引數分枝因子和類直徑的高度平衡樹;分枝因子規定了樹的每個節點的子女的最多個數,而類直徑體現了對這一類點的距離範圍;非葉子節點為它子女的最大特徵值;

聚類特徵樹的構建可以是動態過程的,可以隨時根據資料對模型進行更新操作。

 三元組

 

BIRCH的構造

 

 

從根節點到葉子節點一層一層的取判斷,

優缺點:

  • 適合大規模資料集,線性效率;

  • 只適合分佈呈凸形或者球形的資料集、需要給定聚類個數和簇之間的相關引數

程式碼實現:

庫引數:

  1. threshold 類直徑

  2. branshing_factor 分支因子

  3. n_clusters 簇個數



from itertools import cycle
from time import time
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.colors as colors
​
from sklearn.cluster import Birch
from sklearn.datasets.samples_generator import make_blobs
​
## 設定屬性防止中文亂碼
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
## 產生模擬資料
xx = np.linspace(-22, 22, 10)
yy = np.linspace(-22, 22, 10)
xx, yy = np.meshgrid(xx, yy)
n_centres = np.hstack((np.ravel(xx)[:, np.newaxis],
                       np.ravel(yy)[:, np.newaxis]))
# 產生10萬條特徵屬性是2,類別是100,符合高斯分佈的資料集
X, y = make_blobs(n_samples=100000, n_features=2, centers=n_centres, random_state=28)
# 建立不同的引數(簇直徑)Birch層次聚類
birch_models = [
    Birch(threshold=1.7, n_clusters=None),
    Birch(threshold=0.5, n_clusters=None),
    Birch(threshold=1.7, n_clusters=100)
]
# threshold:簇直徑的閾值,    branching_factor:大葉子個數
​
# 我們也可以加引數來試一下效果,比如加入分支因子branching_factor,給定不同的引數值,看聚類的結果
## 畫圖
final_step = [u'直徑=1.7;n_lusters=None', u'直徑=0.5;n_clusters=None', u'直徑=1.7;n_lusters=100']
​
plt.figure(figsize=(12, 8), facecolor='w')
plt.subplots_adjust(left=0.02, right=0.98, bottom=0.1, top=0.9)
colors_ = cycle(colors.cnames.keys())
cm = mpl.colors.ListedColormap(colors.cnames.keys())
​
for ind, (birch_model, info) in enumerate(zip(birch_models, final_step)):
    t = time()
    birch_model.fit(X)
    time_ = time() - t
    # 獲取模型結果(label和中心點)
    labels = birch_model.labels_
    centroids = birch_model.subcluster_centers_
    n_clusters = len(np.unique(centroids))
    print("Birch演算法,引數資訊為:%s;模型構建消耗時間為:%.3f秒;聚類中心數目:%d" % (info, time_, len(np.unique(labels))))
​
    # 畫圖
    subinx = 221 + ind
    plt.subplot(subinx)
    for this_centroid, k, col in zip(centroids, range(n_clusters), colors_):
        mask = labels == k
        plt.plot(X[mask, 0], X[mask, 1], 'w', markerfacecolor=col, marker='.')
        if birch_model.n_clusters is None:
            plt.plot(this_centroid[0], this_centroid[1], '*', markerfacecolor=col, markeredgecolor='k', markersize=2)
    plt.ylim([-25, 25])
    plt.xlim([-25, 25])
    plt.title(u'Birch演算法%s,耗時%.3fs' % (info, time_))
    plt.grid(False)
​
# 原始資料集顯示
plt.subplot(224)
plt.scatter(X[:, 0], X[:, 1], c=y, s=1, cmap=cm, edgecolors='none')
plt.ylim([-25, 25])
plt.xlim([-25, 25])
plt.title(u'原始資料')
plt.grid(False)
​
plt.show()

執行結果:

Birch演算法,引數資訊為:直徑=1.7;n_lusters=None;模型構建消耗時間為:2.510秒;聚類中心數目:171Birch演算法,引數資訊為:直徑=0.5;n_clusters=None;模型構建消耗時間為:6.689秒;聚類中心數目:3205Birch演算法,引數資訊為:直徑=1.7;n_lusters=100;模型構建消耗時間為:3.013秒;聚類中心數目:100

Process finished with exit code 0

 

CURE(沒人用)

CURE演算法(使用代表點的聚類法):

該演算法先把每個資料點看成一類,然後合併距離最近的類直至類個數為所要求的個數為止。但是和AGNES演算法的區別是:取消了使用所有點或用中心點+距離來表示一個類

而是從每個類中抽取固定數量、分佈較好的點作為此類的代表點,並將這些代表點乘以一個適當的收縮因子,使它們更加靠近類中心點。

代表點的收縮特性可以調整模型可以匹配那些非球形的場景,而且收縮因子的使用可以減少噪音對聚類的影響。

 

找幾個特殊的點來代替整個類別中的樣本

優缺點:能夠處理非球形分佈的應用場景採用隨機抽樣和分割槽的方式可以提高演算法的執行