機器學習 - 算法模型 - 聚類

聚類

分類(class)與聚類(cluster)不同,分類是有監督學習模型,聚類屬於無監督學習模型。聚類講究使用一些算法把樣本劃分爲n個羣落。一般情況下,這種算法都需要計算歐氏距離。

歐氏距離即歐幾里得距離。
P(x1)Q(x2):x1x2=(x1x2)2P(x1,y1)Q(x2,y2):x1x2)2+(y1y2)2P(x1,y1,z1)Q(x2,y2,z2):(x1x2)2+(y1y2)2+(z1z2)2 P(x_1) - Q(x_2): |x_1-x_2| = \sqrt{(x_1-x_2)^2} \\ P(x_1,y_1) - Q(x_2,y_2): \sqrt{x_1-x_2)^2+(y_1-y_2)^2} \\ P(x_1,y_1,z_1) - Q(x_2,y_2,z_2): \sqrt{(x_1-x_2)^2+(y_1-y_2)^2+(z_1-z_2)^2} \\
用兩個樣本對應特徵值之差的平方和之平方根,即歐氏距離,來表示這兩個樣本的相似性。

K均值算法

第一步:隨機選擇k個樣本作爲k個聚類的中心,計算每個樣本到各個聚類中心的歐氏距離,將該樣本分配到與之距離最近的聚類中心所在的類別中。

第二步:根據第一步所得到的聚類劃分,分別計算每個聚類的幾何中心,將幾何中心作爲新的聚類中心,重複第一步,直到計算所得幾何中心與聚類中心重合或接近重合爲止。

注意:

  1. 聚類數k必須事先已知。藉助某些評估指標,優選最好的聚類數。
  2. 聚類中心的初始選擇會影響到最終聚類劃分的結果。初始中心儘量選擇距離較遠的樣本。

K均值算法相關API:

import sklearn.cluster as sc
# n_clusters: 聚類數
model = sc.KMeans(n_clusters=4)
# 不斷調整聚類中心,知道最終聚類中心穩定則聚類完成
model.fit(x)
# 獲取訓練結果的聚類中心
centers = model.cluster_centers_

案例:加載multiple3.txt,基於K均值算法完成樣本的聚類。

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = np.loadtxt('../data/multiple3.txt', delimiter=',')
# K均值聚類器
model = sc.KMeans(n_clusters=4)
model.fit(x)
centers = model.cluster_centers_
n = 500
l, r = x[:, 0].min() - 1, x[:, 0].max() + 1
b, t = x[:, 1].min() - 1, x[:, 1].max() + 1
grid_x = np.meshgrid(np.linspace(l, r, n),
                     np.linspace(b, t, n))
flat_x = np.column_stack((grid_x[0].ravel(), grid_x[1].ravel()))    
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)
# pred_y = model.predict(x)
pred_y = model.labels_	# 每個預測樣本的類別標籤(副產品)
mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80)
mp.scatter(centers[:, 0], centers[:, 1], marker='+', c='gold', s=1000, linewidth=1)
mp.show()

圖像量化

KMeans聚類算法可以應用於圖像量化領域。通過KMeans算法可以把一張圖像所包含的顏色值進行聚類劃分,求每一類別的平均值後再重新生成新的圖像。可以達到圖像降維的目的。這個過程稱爲圖像量化。圖像量化可以更好的保留圖像的輪廓,降低機器識別圖像輪廓的難度。

案例:

import numpy as np
import scipy.misc as sm
import scipy.ndimage as sn
import sklearn.cluster as sc
import matplotlib.pyplot as mp


# 通過K均值聚類量化圖像中的顏色
def quant(image, n_clusters):
    x = image.reshape(-1, 1)
    model = sc.KMeans(n_clusters=n_clusters)
    model.fit(x)
    y = model.labels_
    centers = model.cluster_centers_.ravel()
    return centers[y].reshape(image.shape)


original = sm.imread('../data/lily.jpg', True)
quant4 = quant(original, 4)
quant3 = quant(original, 3)
quant2 = quant(original, 2)
mp.figure('Image Quant', facecolor='lightgray')
mp.subplot(221)
mp.title('Original', fontsize=16)
mp.axis('off')
mp.imshow(original, cmap='gray')
mp.subplot(222)
mp.title('Quant-4', fontsize=16)
mp.axis('off')
mp.imshow(quant4, cmap='gray')
mp.subplot(223)
mp.title('Quant-3', fontsize=16)
mp.axis('off')
mp.imshow(quant3, cmap='gray')
mp.subplot(224)
mp.title('Quant-2', fontsize=16)
mp.axis('off')
mp.imshow(quant2, cmap='gray')
mp.tight_layout()
mp.show()

均值漂移算法

首先假定樣本空間中的每個聚類均服從某種已知的概率分佈規則,然後用不同的概率密度函數擬合樣本中的統計直方圖,不斷移動密度函數的中心(均值)的位置,直到獲得最佳擬合效果爲止。這些概率密度函數的峯值點就是聚類的中心,再根據每個樣本距離各個中心的距離,選擇最近聚類中心所屬的類別作爲該樣本的類別。

均值漂移算法的特點:

  1. 聚類數不必事先已知,算法會自動識別出統計直方圖的中心數量。
  2. 聚類中心不依據於最初假定,聚類劃分的結果相對穩定。
  3. 樣本空間應該服從某種概率分佈規則,否則算法的準確性會大打折扣。

均值漂移算法相關API:

# 量化帶寬,決定每次調整概率密度函數的步進量
# n_samples:樣本數量
# quantile:量化寬度(直方圖一條的寬度)
bw = sc.estimate_bandwidth(x, n_samples=len(x), quantile=0.1)
# 均值漂移聚類器
model = sc.MeanShift(bandwidth=bw, bin_seeding=True)
model.fit(x)

案例:加載multiple3.txt,使用均值漂移算法對樣本完成聚類劃分。

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp

x = np.loadtxt('../data/multiple3.txt', delimiter=',')
# 量化帶寬,決定每次調整概率密度函數的步進量
bw = sc.estimate_bandwidth(x, n_samples=len(x), quantile=0.2)
# 均值漂移聚類器
model = sc.MeanShift(bandwidth=bw, bin_seeding=True)
model.fit(x)
centers = model.cluster_centers_
n = 500
l,  r = x[:, 0].min() - 1, x[:, 0].max() + 1
b,  t = x[:, 1].min() - 1, x[:, 1].max() + 1
grid_x = np.meshgrid(np.linspace(l, r, n),
                     np.linspace(b, t, n))
flat_x = np.column_stack((grid_x[0].ravel(), grid_x[1].ravel()))
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)
pred_y = model.predict(x)
mp.figure('Mean Shift Cluster', facecolor='lightgray')
mp.title('Mean Shift Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80)
mp.scatter(centers[:, 0], centers[:, 1], marker='+', c='gold', s=1000, linewidth=1)
mp.show()

凝聚層次算法

首先假定每個樣本都是一個獨立的聚類,如果統計出來的聚類數大於期望的聚類數,則從每個樣本出發尋找離自己最近的另一個樣本,與之聚集,形成更大的聚類,同時令總聚類數減少,不斷重複以上過程,直到統計出來的聚類數達到期望值爲止。

凝聚層次算法的特點:

  1. 聚類數k必須事先已知。藉助某些評估指標,優選最好的聚類數。
  2. 沒有聚類中心的概念,因此只能在訓練集中劃分聚類,但不能對訓練集以外的未知樣本確定其聚類歸屬。
  3. 在確定被凝聚的樣本時,除了以距離作爲條件以外,還可以根據連續性來確定被聚集的樣本。

凝聚層次算法相關API:

# 凝聚層次聚類器
model = sc.AgglomerativeClustering(n_clusters=4)
pred_y = model.fit_predict(x)

案例:重新加載multiple3.txt,使用凝聚層次算法進行聚類劃分。

import numpy as np
import sklearn.cluster as sc
import matplotlib.pyplot as mp
x = np.loadtxt('../data/multiple3.txt', delimiter=',')
# 凝聚層次聚類器
model = sc.AgglomerativeClustering(n_clusters=4)
pred_y = model.fit_predict(x)
mp.figure('Agglomerative Cluster', facecolor='lightgray')
mp.title('Agglomerative Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=80)
mp.show()

在確定被凝聚的樣本時,除了以距離作爲條件以外,還可以根據連續性來確定被聚集的樣本。

import numpy as np
import sklearn.cluster as sc
import sklearn.neighbors as nb
import matplotlib.pyplot as mp
n_samples = 500
x = np.linspace(-1, 1, n_samples)
y = np.sin(x * 2 * np.pi)
n = 0.3 * np.random.rand(n_samples, 2)
x = np.column_stack((x, y)) + n
# 無連續性的凝聚層次聚類器
model_nonc = sc.AgglomerativeClustering( linkage='average', n_clusters=3)
pred_y_nonc = model_nonc.fit_predict(x)
# 近鄰篩選器
conn = nb.kneighbors_graph( x, 10, include_self=False)
# 有連續性的凝聚層次聚類器
model_conn = sc.AgglomerativeClustering(
    linkage='average', n_clusters=3, connectivity=conn)
pred_y_conn = model_conn.fit_predict(x)
mp.figure('Nonconnectivity', facecolor='lightgray')
mp.title('Nonconnectivity', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], c=pred_y_nonc, cmap='brg', alpha=0.5, s=30)
mp.figure('Connectivity', facecolor='lightgray')
mp.title('Connectivity', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.scatter(x[:, 0], x[:, 1], c=pred_y_conn, cmap='brg', alpha=0.5, s=30)
mp.show()

輪廓係數

好的聚類:內密外疏,同一個聚類內部的樣本要足夠密集,不同聚類之間樣本要足夠疏遠。

輪廓係數計算規則:針對樣本空間中的一個特定樣本,計算它與所在聚類其它樣本的平均距離a,以及該樣本與距離最近的另一個聚類中所有樣本的平均距離b,該樣本的輪廓係數爲(b-a)/max(a, b),將整個樣本空間中所有樣本的輪廓係數取算數平均值,作爲聚類劃分的性能指標s。

輪廓係數的區間爲:[-1, 1]。 -1代表分類效果差,1代表分類效果好。0代表聚類重疊,沒有很好的劃分聚類。

輪廓係數相關API:

import sklearn.metrics as sm
# v:平均輪廓係數
# metric:距離算法:使用歐幾里得距離(euclidean)
v = sm.silhouette_score(輸入集, 輸出集, sample_size=樣本數, metric=距離算法)

案例:輸出KMeans算法聚類劃分後的輪廓係數。

# 打印平均輪廓係數
print(sm.silhouette_score( x, pred_y, sample_size=len(x), metric='euclidean'))

DBSCAN算法

從樣本空間中任意選擇一個樣本,以事先給定的半徑做圓,凡被該圓圈中的樣本都視爲與該樣本處於相同的聚類,以這些被圈中的樣本爲圓心繼續做圓,重複以上過程,不斷擴大被圈中樣本的規模,直到再也沒有新的樣本加入爲止,至此即得到一個聚類。於剩餘樣本中,重複以上過程,直到耗盡樣本空間中的所有樣本爲止。

DBSCAN算法的特點:

  1. 事先給定的半徑會影響最後的聚類效果,可以藉助輪廓係數選擇較優的方案。

  2. 根據聚類的形成過程,把樣本細分爲以下三類:

    外周樣本:被其它樣本聚集到某個聚類中,但無法再引入新樣本的樣本。

    孤立樣本:聚類中的樣本數低於所設定的下限,則不稱其爲聚類,反之稱其爲孤立樣本。

    核心樣本:除了外周樣本和孤立樣本以外的樣本。

DBSCAN聚類算法相關API:

# DBSCAN聚類器
# eps:半徑
# min_samples:聚類樣本數的下限,若低於該數值,則稱爲孤立樣本
model = sc.DBSCAN(eps=epsilon, min_samples=5)
model.fit(x)

案例:修改凝聚層次聚類案例,基於DBSCAN聚類算法進行聚類劃分,選擇最優半徑。

import numpy as np
import sklearn.cluster as sc
import sklearn.metrics as sm
import matplotlib.pyplot as mp

x = np.loadtxt('../data/perf.txt', delimiter=',')
epsilons, scores, models = np.linspace(0.3, 1.2, 10), [], []
for epsilon in epsilons:
    # DBSCAN聚類器
    model = sc.DBSCAN(eps=epsilon, min_samples=5)
    model.fit(x)
    score = sm.silhouette_score(
        x, model.labels_, sample_size=len(x), metric='euclidean')
    scores.append(score)
    models.append(model)
scores = np.array(scores)
best_index = scores.argmax()
best_epsilon = epsilons[best_index]
print(best_epsilon)
best_score = scores[best_index]
print(best_score)
best_model = models[best_index]

案例:獲取核心樣本、外周樣本、孤立樣本。並且使用不同的點型繪圖。

best_model = models[best_index]
pred_y = best_model.fit_predict(x)
core_mask = np.zeros(len(x), dtype=bool)
core_mask[best_model.core_sample_indices_] = True
offset_mask = best_model.labels_ == -1
periphery_mask = ~(core_mask | offset_mask)
mp.figure('DBSCAN Cluster', facecolor='lightgray')
mp.title('DBSCAN Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
labels = best_model.labels_
mp.scatter(x[core_mask][:, 0], x[core_mask][:, 1], c=labels[core_mask], 
           cmap='brg', s=80, label='Core')
mp.scatter(x[periphery_mask][:, 0], x[periphery_mask][:, 1], alpha=0.5,
           c=labels[periphery_mask], cmap='brg', marker='s', s=80, label='Periphery')
mp.scatter(x[offset_mask][:, 0], x[offset_mask][:, 1],
           c=labels[offset_mask], cmap='brg', marker='x', s=80, label='Offset')
mp.legend()
mp.show()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章