1 概述
本專題重點在於使用sklearn進行聚類分析,不涉及聚類算法的原理介紹。
1.1 無監督學習與聚類算法
在機器學習當中,有相當一部分算法屬於“無監督學習”,無監督算法在訓練的時候只需要特徵矩陣X,不需要標籤。聚類算法就是無監督學習的代表算法。
聚類算法又叫“無監督分類”,其目的是將數據劃分爲有意義或者有用的組(簇)。這種劃分可以基於業務的需求或者建模的需求來完成,也可以單純的幫助我們探索數據的自然結構和分佈。比如在商業中,如果我們的手頭有大量的客戶信息,我們可以使用聚類將客戶劃分爲若干組,以便進一步分析和開展營銷活動,最有名的客戶價值判斷模型RFM就常和聚類分析共同使用。再比如,聚類可以用於降維和矢量量化(vector quantization),可以將高位特徵壓縮到一列當中,常常用於圖像,聲音,視頻等非結構化數據,可以大幅壓縮數據量。
聚類 | 分類 | |
---|---|---|
核心 | 將數據分成多組 探索每個組的數據是否有聯繫 |
從已經分組的數據中去學習 把新數據放到已經分好的組中去 |
學習類型 | 無監督,不需要標籤進行訓練 | 有監督,需要標籤 |
典型算法 | K-Means, DBSCAN, 層次聚類, 譜聚類 | 決策樹, 貝葉斯, 邏輯迴歸, SVM |
算法輸出 | 聚類的結果是不確定的 不一定總是能夠反映數據的真實分類 |
分類結果是確定的 分類的優劣是客觀的 |
1.2 sklearn中常用的聚類算法
sklearn中的聚類算法有兩種表現形式,一種是類,需要實例化,訓練並使用接口和屬性來調用。另一種是函數,只需要輸入特徵矩陣和超參數即可返回聚類的結果和各種指標。
類 | 含義 | 輸入 |
---|---|---|
cluster.AffinityPropagation | 執行親和傳播數據聚類 | [damping, …] |
cluster.AgglomerativeClustering | 凝聚聚類 | […] |
cluster.Birch | Birch聚類算法 | [threshold, branching_factor, …] |
cluster.DBSCAN | DBSCAN聚類算法 | [eps, min_samples, metrix, …] |
cluster.FeatureAgglomeration | 凝聚特徵 | [n_clusters, …] |
cluster.KMeans | K均值聚類 | [n_clusters, init, n_init, …] |
cluster.MiniBatchKMeans | 小批量K均值聚類 | [n_clusters, init, …] |
cluster.MeanShift | 使用平坦核函數的平均移位聚類 | [bandwidth, seeds, …] |
cluster.SpectralClustering | 譜聚類 | [n_clusters, …] |
1.3 sklearn中聚類使用示例
1.3.1 聚類示例
以KMeans爲例,在sklearn中進行聚類步驟如下:
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
x = make_blobs(n_samples=1000, n_features=2, centers = 4, cluster_std=2.0)[0]
## 方式1:使用fit函數訓練,然後調用cluster1.labels_得到每個數據對應的簇編號(0,1,2,...)
cluster1 = KMeans(n_clusters = 4, random_state=10).fit(x)
y_pred = cluster1.labels_
## 方式2:使用fit_predict直接獲得每個數據對應簇編號
y_pred = KMeans(n_clusters = 4, random_state=10).fit_predit(x)
## 以上兩個方法得到的結果完全一致。
1.3.2 重要屬性
- culster_centers_ - 簇心:返回每個簇心的座標
- inertia - 總距離平方和:越小越好
2 sklearn中生成測試數據函數介紹
生成數據的函數主要有:sklearn.datasets.make_classification
, sklearn.datasets.make_circles
, sklearn.datasets.make_moons
以及sklearn.datasets.make_blobs
。這裏簡單介紹每一個函數,具體參數見官方文檔。
2.1 make_classification
主要用來生成分類數據,用法示例:
x = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, n_repeated=0, n_clusters_per_class=1)
示例:
from sklearn.datasets import make_classification, make_circles, make_moons
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(15,5))
fig.add_subplot(1,3,1)
x = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, n_repeated=0, n_clusters_per_class=1)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_classification')
fig.add_subplot(1,3,2)
x = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, n_repeated=0, n_clusters_per_class=2)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_classification')
fig.add_subplot(1,3,3)
x = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, n_repeated=0, n_clusters_per_class=2)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_classification')
2.2 make_moons
用來生成月牙形數據,用法示例:
x = make_moons(n_samples=1000, noise=0.1)
示例:
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(15,5))
fig.add_subplot(1,3,1)
x = make_moons(n_samples=1000, noise=0)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('Make_moons(noise=0)')
fig.add_subplot(1,3,2)
x = make_moons(n_samples=1000, noise=0.1)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('Make_moons(noise=0.1)')
fig.add_subplot(1,3,3)
x = make_moons(n_samples=1000, noise=0.5)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('Make_moons(noise=0.5)')
2.3 make_moons
用來生成環形數據,用法示例:
x = make_circles(n_samples=1000, noise=0.05, factor=0.6)
示例:
from sklearn.datasets import make_circles
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(15,5))
fig.add_subplot(1,3,1)
x = make_circles(n_samples=1000, noise=0)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_circles(noise=0)')
fig.add_subplot(1,3,2)
x = make_circles(n_samples=1000, noise=0.05, factor=0.6)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_circles(noise=0.1)')
fig.add_subplot(1,3,3)
x = make_circles(n_samples=1000, noise=0.5)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_circles(noise=0.5)')
2.4 make_blobs
用來生成簇數據,用法示例:
x = make_blobs(n_samples=1000, n_features=2, centers = 3)
示例:
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize=(15,5))
fig.add_subplot(1,3,1)
x = make_blobs(n_samples=1000, n_features=2, centers = 2)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_blobs')
fig.add_subplot(1,3,2)
x = make_blobs(n_samples=1000, n_features=2, centers = 3)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_blobs')
fig.add_subplot(1,3,3)
x = make_blobs(n_samples=1000, n_features=2, centers = 4)
plt.plot(x[0][:,0], x[0][:,1], 'b.')
plt.title('make_blobs')
3 使用sklearn聚類示例
使用常用的六個聚類算法,並將聚類結果使用PCA降維後可視化。
3.1 簇數據聚類
from sklearn.datasets import make_circles
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans, DBSCAN, SpectralClustering, Birch, MeanShift, AgglomerativeClustering
from sklearn.decomposition import PCA
import pandas as pd
x = make_blobs(n_samples=1000, n_features=2, centers = 4, cluster_std=2.0)[0]
pca = PCA(n_components=2)
pca_result = pca.fit_transform(x)
fig = plt.figure(figsize=(15,10))
model = AgglomerativeClustering(n_clusters = 4)
y_pred = model.fit_predict(x)
fig.add_subplot(2,3,1)
plt.scatter(pca_result[:,0], pca_result[:,1], marker='.', c=y_pred)
plt.title('AgglomerativeClustering')
model = KMeans(n_clusters = 4, random_state=10)
y_pred = model.fit_predict(x)
fig.add_subplot(2,3,2)
plt.scatter(pca_result[:,0], pca_result[:,1], marker='.', c=y_pred)
plt.title('KMeans')
model = DBSCAN(eps=0.1)
model.fit(x)
y_pred = model.labels_
fig.add_subplot(2,3,3)
plt.scatter(pca_result[:,0], pca_result[:,1], marker='.', c=y_pred)
plt.title('DBSCAN')
model = SpectralClustering(n_clusters = 4, random_state=10)
y_pred = model.fit_predict(x)
fig.add_subplot(2,3,4)
plt.scatter(pca_result[:,0], pca_result[:,1], marker='.', c=y_pred)
plt.title('SpectralClustering')
model = Birch(n_clusters=4)
model.fit(x)
y_pred = model.labels_
fig.add_subplot(2,3,5)
plt.scatter(pca_result[:,0], pca_result[:,1], marker='.', c=y_pred)
plt.title('Birch')
model = MeanShift()
model.fit(x)
y_pred = model.labels_
fig.add_subplot(2,3,6)
plt.scatter(pca_result[:,0], pca_result[:,1], marker='.', c=y_pred)
plt.title('MeanShift')
3.2 月牙形數據聚類
代碼基本類似,直接放結果了
3.3 環形數據聚類
4 各聚類算法在各種簇分佈下的聚類效果對比
這裏使用sklearn官方的示例代碼演示一下效果。
print(__doc__)
import time
import numpy as np
import matplotlib.pyplot as plt
from sklearn import cluster, datasets
from sklearn.neighbors import kneighbors_graph
from sklearn.preprocessing import StandardScaler
np.random.seed(0)
# Generate datasets. We choose the size big enough to see the scalability
# of the algorithms, but not too big to avoid too long running times
n_samples = 1500
noisy_circles = datasets.make_circles(n_samples=n_samples, factor=.5,
noise=.05)
noisy_moons = datasets.make_moons(n_samples=n_samples, noise=.05)
blobs = datasets.make_blobs(n_samples=n_samples, random_state=8)
no_structure = np.random.rand(n_samples, 2), None
colors = np.array([x for x in 'bgrcmykbgrcmykbgrcmykbgrcmyk'])
colors = np.hstack([colors] * 20)
clustering_names = [
'MiniBatchKMeans', 'AffinityPropagation', 'MeanShift',
'SpectralClustering', 'Ward', 'AgglomerativeClustering',
'DBSCAN', 'Birch']
plt.figure(figsize=(len(clustering_names) * 2 + 3, 9.5))
plt.subplots_adjust(left=.02, right=.98, bottom=.001, top=.96, wspace=.05,
hspace=.01)
plot_num = 1
datasets = [noisy_circles, noisy_moons, blobs, no_structure]
for i_dataset, dataset in enumerate(datasets):
X, y = dataset
# normalize dataset for easier parameter selection
X = StandardScaler().fit_transform(X)
# estimate bandwidth for mean shift
bandwidth = cluster.estimate_bandwidth(X, quantile=0.3)
# connectivity matrix for structured Ward
connectivity = kneighbors_graph(X, n_neighbors=10, include_self=False)
# make connectivity symmetric
connectivity = 0.5 * (connectivity + connectivity.T)
# create clustering estimators
ms = cluster.MeanShift(bandwidth=bandwidth, bin_seeding=True)
two_means = cluster.MiniBatchKMeans(n_clusters=2)
ward = cluster.AgglomerativeClustering(n_clusters=2, linkage='ward',
connectivity=connectivity)
spectral = cluster.SpectralClustering(n_clusters=2,
eigen_solver='arpack',
affinity="nearest_neighbors")
dbscan = cluster.DBSCAN(eps=.2)
affinity_propagation = cluster.AffinityPropagation(damping=.9,
preference=-200)
average_linkage = cluster.AgglomerativeClustering(
linkage="average", affinity="cityblock", n_clusters=2,
connectivity=connectivity)
birch = cluster.Birch(n_clusters=2)
clustering_algorithms = [
two_means, affinity_propagation, ms, spectral, ward, average_linkage,
dbscan, birch]
for name, algorithm in zip(clustering_names, clustering_algorithms):
# predict cluster memberships
t0 = time.time()
algorithm.fit(X)
t1 = time.time()
if hasattr(algorithm, 'labels_'):
y_pred = algorithm.labels_.astype(np.int)
else:
y_pred = algorithm.predict(X)
# plot
plt.subplot(4, len(clustering_algorithms), plot_num)
if i_dataset == 0:
plt.title(name, size=18)
plt.scatter(X[:, 0], X[:, 1], color=colors[y_pred].tolist(), s=10)
if hasattr(algorithm, 'cluster_centers_'):
centers = algorithm.cluster_centers_
center_colors = colors[:len(centers)]
plt.scatter(centers[:, 0], centers[:, 1], s=100, c=center_colors)
plt.xlim(-2, 2)
plt.ylim(-2, 2)
plt.xticks(())
plt.yticks(())
plt.text(.99, .01, ('%.2fs' % (t1 - t0)).lstrip('0'),
transform=plt.gca().transAxes, size=15,
horizontalalignment='right')
plot_num += 1
plt.show()
5 聚類算法的模型評估指標
本節參考自:【機器學習】菜菜的sklearn課堂06 - 聚類算法與KMeans
不同於分類模型和迴歸,聚類算法的模型評估不是一件簡單的事情。在分類問題中,有直接結果作爲輸出,而且分類問題的結果有正誤之分,所以可以使用預測準確度,混淆矩陣,ROC曲線等指標來進行評估。在迴歸問題中有均方誤差,RSE,MSE等損失函數衡量模型的擬合程度。那麼如何衡量聚類算法的效果呢?
面試高危問題:如何衡量聚類算法的效果? |
---|
像KMeans這種聚類算法,其目標是確保“簇內差異小,簇間差異大“,因此可以通過衡量簇內差異來衡量聚類的效果,sklearn自帶的inertia就是用距離來衡量簇內差異的指標,因此能否使用inertia來作爲聚類的衡量指標呢?inertia越小模型就越好嗎? |
inertia可以作爲指標,但是這個指標的缺點和極限太大。
- 它不是有界的,我們只知道inertia越小越好,但是我們並不知道一個較小的inertia是否已經達到了模型的極限
- 它的計算太容易收到特徵數目的影響,數據維度很大的時候,inertia的計算量會爆炸,不適合評估模型
- inertia對數據的分佈有假設,假設數據滿足凸分佈,並且假設數據是各向同性的(isotropic),即數據的屬性在不同方向上代表着相同的含義。但是現實中的數據往往不是這樣的。所以使用inertia作爲評估指標,會讓聚類算法在一些細長簇,環形簇或者不規則性狀的流行時表現不佳。
那麼可以使用什麼指標呢?
5.1 當真實標籤已知的時候
雖然聚類的過程中不輸入真實標籤,但這不代表數據集中沒有真實標籤。如果擁有真實的標籤,我們更傾向於使用分類算法,但仍然可以使用聚類算法對其進行分類。常用的衡量帶標籤數據聚類效果的方法有以下三種:
模型評估指標 | 說明 |
---|---|
互信息分 普通互信息分 metrics.adjusted_mutual_info_score(y_pred, y_true) 調整的互信息分 metrics.mutual_info_score(y_pred, y_true) 標準化互信息分 metrics.normalized_mutual_info_score(y_pred, y_true) |
取值範圍在(0,1),越接近1聚類效果越好 |
V-measure:基於條件上分析的一系列直觀度量 同質性、完整性、同質性和完整性的調和平均(V-measure) metrics.homogeneity_score(y_true, y_pred) metrics.completeness_score(y_true, y_pred) metrics.v_measure(y_true, y_pred) |
取值範圍在(0,1),越接近1聚類效果越好 |
調整蘭德係數 metrics.adjusted_rand_score(y_true, y_pred) |
取值在(-1,1)之間,負值象徵着簇內的點差異巨大,越接近1表示聚類效果越好。 |
5.2 當真實標籤未知的時候:輪廓係數
5.2.1 輪廓係數介紹
在99%的情況下,我們是對沒有真實標籤的數據進行探索,並不知道數據的真實類別。這樣的聚類,是完全依賴於評價簇內的稠密程度(簇內差異小)和簇間的離散程度(簇間差異大)來評估聚類的效果,其中輪廓係數是最常用的聚類算法的評價指標。它是對每個樣本來定義的,能夠同時衡量:
- 樣本與其自身所在的簇中的其他樣本的相似度a,等於樣本與統一簇中所有其他點之間的平均距離
- 樣本與其他簇中樣本的相似度b,等於樣本與下一個最近的簇中的所有點之間的平均距離
我們希望b永遠大於a,並且越大越好,因此單個樣本的輪廓係數計算爲:
這個公式可以被解析爲:如果,如果,如果。因此輪廓係數的範圍是(-1,1),其值越接近1表示樣本與自己所在的簇中的樣本很相似,並且與其他簇中的樣本不相似,當樣本點與簇外的樣本更相似的時候,輪廓係數爲負數。當輪廓係數爲0的時候,表示兩個簇中的樣本相似度一致,兩個簇本應該是一個簇。因此輪廓係數越接近1越好,越大越好。
在sklearn中可以使用metrics中的silhouette_score來計算輪廓係數,它返回的是一個數據集中所有樣本的輪廓係數的均值。在metrics中的sihouette_samples的參數餘輪廓係數一致,能夠返回數據集中每個樣本自己的輪廓係數。用法如下:
from sklearn.metrics import silhouette_score
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
x = make_blobs(n_samples=1000, n_features=2, centers = 4, cluster_std=2.0)[0]
y_pred = KMeans(n_clusters = 4, random_state=10).fit_predict(x)
silhouette_score(x, y_pred)
# >>> 0.4359497951008228
輪廓係數有很多優點,它在有限空間中取值,是的我們對模型的聚類效果有一個參考。並且輪廓係數對數據的分佈沒有假設,因此在很多的數據集上都表現良好,它在每一個簇的分割比較清晰時表現最好。
但是輪廓係數也有缺陷,它在凸型的數據上表面會虛高,比如基於密度進行聚類,或通過DBSCAN獲得的聚類結果,如果使用輪廓係數來衡量,會表現出比真是聚類效果更高的分數。
5.2.2 使用輪廓係數可視化圖像輔助選擇簇的個數
這裏參考【機器學習】菜菜的sklearn課堂06 - 聚類算法與KMeans提供的可視化代碼,能夠生成很完整且漂亮的可視化圖片,如下圖所示。關於生該圖的完整代碼見我的下一篇博客:
5.3 當真實標籤未知時的其他評價指標
除了輪廓係數是最常用的,還有卡林斯基-哈拉巴斯指數(Calinski-Harabaz index,簡稱CHI,也被稱爲方差比標準),戴維斯-布爾丁指數(Davies-Bouldin)以及權變矩陣(Contingency Matrix)可以使用。
標籤未知時的評估指標 |
---|
卡林斯基-哈拉巴斯指數:sklearn.metrics.calinski_harabaz_score(x, y_pred) |
戴維斯-布爾丁指數:sklearn.metrics.davies_bouldin_score(x, y_pred) |
權變矩陣:sklearn.metrics.cluster.contingency_matrix(x, y_pred) |
(完)