密度聚類(Density-based Clustering)假設聚類結構可以經過樣本分佈的緊密程度來肯定。DBSCAN是經常使用的密度聚類算法,它經過一組鄰域參數(ϵϵ,MinPtsMinPts)來描述樣本分佈的緊密程度。給定數據集DD={x⃗ 1,x⃗ 2,x⃗ 3,...,x⃗ Nx→1,x→2,x→3,...,x→N},數據集屬性定義以下。python
-
ϵϵ-鄰域:Nϵ(x⃗ i)Nϵ(x→i)={x⃗ j∈D|distance(x⃗ i,x⃗ j)x→j∈D|distance(x→i,x→j)≤ϵ≤ϵ},Nϵ(x⃗ i)Nϵ(x→i)包含了樣本集DD中與x⃗ ix→i距離不大於ϵϵ的全部樣本。算法
-
核心對象core object:若|Nϵ(x⃗ i)Nϵ(x→i)|≥MinPts≥MinPts,則稱x⃗ ix→i是一個核心對象。即:若x⃗ ix→i的ϵϵ-鄰域中至少包含MinPtsMinPts個樣本,則稱x⃗ ix→i是一個核心對象。app
-
密度直達directly density-reachable:若x⃗ ix→i是一個核心對象,且x⃗ j∈x→j∈Nϵ(x⃗ i)Nϵ(x→i),則稱x⃗ jx→j由x⃗ ix→i密度直達,記做x⃗ ix→i–>x⃗ jx→j。dom
-
密度可達density-reachable:對於x⃗ ix→i和x⃗ jx→j,若存在樣本序列(p⃗ 0,p⃗ 1,p⃗ 2,...,p⃗ m,p⃗ m+1p→0,p→1,p→2,...,p→m,p→m+1),其中p⃗ 0p→0=x⃗ ix→i,p⃗ m+1p→m+1=x⃗ jx→j,p⃗ s∈D,s=1,2,...,mp→s∈D,s=1,2,...,m。若是p⃗ s+1p→s+1由p⃗ s,s=1,2,...,mp→s,s=1,2,...,m密度直達,則稱x⃗ jx→j由x⃗ ix→i密度可達,記做x⃗ ix→i~>x⃗ jx→j。ide
- 密度相連density-connected:對於x⃗ ix→i和x⃗ jx→j,若存在x⃗ kx→k,使得x⃗ ix→i和x⃗ jx→j均由x⃗ kx→k密度可達,則稱x⃗ jx→j由x⃗ ix→i密度相連,記做x⃗ ix→i~x⃗ jx→j。
DBSCAN算法的定義:給定鄰域參數(ϵϵ,MinPtsMinPts),一個簇C⊆DC⊆D是知足下列性質的非空樣本子集:函數
- 接性connectivity:若x⃗ i∈C,x⃗ j∈Cx→i∈C,x→j∈C,則x⃗ ix→i~x⃗ jx→j
- 大性maximality:若x⃗ i∈Cx→i∈C,且→xi→xi~>x⃗ jx→j,則x⃗ j∈Cx→j∈C
即一個簇是由密度可達關係導出的最大的密度相連樣本集合。
DBSCAN算法的思想:若x⃗ x→爲核心對象,則x⃗ x→密度可達的全部樣本組成的集合X={x⃗ ∗∈D|x⃗ x→∗∈D|x→~>x⃗ ∗x→∗},能夠證實XX就是知足鏈接性與最大性的簇。因而DBSCAN算法首選任選數據集中的一個核心對象做爲種子seedseed,再由此出發肯定相應的聚類簇。測試
下面給出DBSCAN算法:lua
-
輸入idea
- 數據集DD={x⃗ 1,x⃗ 2,x⃗ 3,...,x⃗ Nx→1,x→2,x→3,...,x→N}
- 鄰域參數(ϵϵ,MinPtsMinPts)
-
輸出:簇劃分CC={C1,C2,...,CkC1,C2,...,Ck}spa
- 算法步驟以下:
- 初始化核心對象集合爲空集:Ω=∅∅
- 尋找核心對象:遍歷全部的樣本點x⃗ i,i=1,2,...,Nx→i,i=1,2,...,N,計算Nϵ(x⃗ i)Nϵ(x→i),若是|Nϵ(x⃗ i)Nϵ(x→i)|≥MinPts≥MinPts,則Ω=Ω⋃⋃{x⃗ ix→i}
- 迭代:以任一未訪問過的核心對象爲出發點,找出有其密度可達的樣本生成的聚類簇,直到全部的核心對象都被訪問爲止
Python 實戰
DBSCANDBSCAN是sciki−kearnsciki−kearn提供的密度聚類算法模型,其原型爲:
class sklearn.cluster.DBSCAN(eps=0.5,min_samples=5,metric='euclidean',algorithm='auto',leaf_size=30,p=None,random_state=None)
- 1
參數
- epseps:ϵϵ參數,用於肯定鄰域大小。
- min_samplesmin_samples:MinPtsMinPts參數,用於判斷核心對象。
- metricmetric:一個字符串或可調用對象,用於計算距離。若是是字符串,則必須是在metrics.pairwise.calculate_distance中指定。
- algorithmalgorithm:一個字符串,用於計算兩點間距離並找出最近鄰的點,能夠爲以下:
- ‘autoauto’:由算法自動取捨合適的算法。
- ‘ball_treeball_tree’:用ball樹來搜索。
- ‘kd_treekd_tree’:用kd樹搜索。
- ‘brutebrute’:暴力搜索。
- leaf_sizeleaf_size:一個整數,用於指定當algorithm=ball_tree或kd_tree時,樹的葉節點大小。該參數會影響構建樹,搜索最近鄰的速度,同時影響樹的內存。
- random_staterandom_state:被廢棄的接口,將在scikit-learn v 0.18中移除。
屬性
- core_sample_indices_core_sample_indices_:核心樣本在原始訓練集中的位置。
- components_components_:核心樣本的一份副本。
- labels_labels_:每一個樣本所屬的簇標記。對於噪聲樣本,其簇標記爲-1副本。
方法
- fit(X[,y,sample_weight])fit(X[,y,sample_weight]):訓練模型。
- fit_predict(X[,y,sample_weight])fit_predict(X[,y,sample_weight]):訓練模型並預測每一個樣本所屬的簇標記。
#導包 from sklearn import cluster from sklearn.metrics import adjusted_rand_score import numpy as np import matplotlib.pyplot as plt from sklearn.datasets.samples_generator import make_blobs from sklearn import mixture from sklearn.svm.libsvm import predict
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
#產生數據 def create_data(centers,num=100,std=0.7): X,labels_true = make_blobs(n_samples=num,centers=centers, cluster_std=std) return X,labels_true
- 1
- 2
- 3
- 4
""" 數據做圖 """ def plot_data(*data): X,labels_true=data labels=np.unique(labels_true) fig=plt.figure() ax=fig.add_subplot(1,1,1) colors='rgbycm' for i,label in enumerate(labels): position=labels_true==label ax.scatter(X[position,0],X[position,1],label="cluster %d"%label), color=colors[i%len(colors)] ax.legend(loc="best",framealpha=0.5) ax.set_xlabel("X[0]") ax.set_ylabel("Y[1]") ax.set_title("data") plt.show()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
#測試函數 def test_DBSCAN(*data): X,labels_true = data clst = cluster.DBSCAN(); predict_labels = clst.fit_predict(X) print("ARI:%s"%adjusted_rand_score(labels_true,predict_labels)) print("Core sample num:%d"%len(clst.core_sample_indices_))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
#結果 ARI:0.330307120902 Core sample num:991
- 1
- 2
- 3
其中ARIARI指標爲0.330307120902,該值越大越好,DBSCAN根據密度,將原始數據集劃分爲991個簇。
下面考察ϵϵ參數的影響:
def test_DBSCAN_epsilon(*data): X,labels_true = data epsilons = np.logspace(-1,1.5) ARIs=[] Core_nums = [] for epsilon in epsilons: clst = cluster.DBSCAN(eps=epsilon) predicted_labels = clst.fit_predict(X) ARIs.append(adjusted_rand_score(labels_true,predicted_labels)) Core_nums.append(len(clst.core_sample_indices_)) fig = plt.figure(figsize=(10,5)) ax = fig.add_subplot(1,2,1) ax.plot(epsilons,ARIs,marker = '+') ax.set_xscale('log') ax.set_xlabel(r"$\epsilon$") ax.set_ylim(0,1) ax.set_ylabel('ARI') ax = fig.add_subplot(1,2,2) ax.plot(epsilons,Core_nums,marker='o') ax.set_xscale('log') ax.set_xlabel(r"$\epsilon$") ax.set_ylabel('Core_num') fig.suptitle("DBSCAN") plt.show()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
centers = [[1,1],[1,2],[2,2],[10,20]] X,labels_true = create_data(centers,1000,0.5) test_DBSCAN_epsilon(X,labels_true)
- 1
- 2
- 3
ϵϵ參數的影響結果如上圖所示:
能夠看到ARIARI指數隨着ϵϵ的增加,先上升後保持平穩,最後懸崖式降低。懸崖式降低是由於咱們產生的訓練樣本的間距比較小,最遠的兩個樣本之間的距離不超過30,當ϵϵ過大時,全部的點都在一個鄰域中。
樣本核心數量隨着ϵϵ的增加而上升,這是由於隨着ϵϵ的增加,樣本點的鄰域在擴展,則樣本點鄰域中的樣本會增多,這就產生了更多知足條件的核心樣本點。可是樣本集中的樣本數量有限,所以核心樣本點的數量增加到必定數目後會趨於穩定。
下面接着考察MinPtsMinPts參數的影響:
def test_DBSCAN_min_samples(*data): X,labels_true=data min_samples=range(1,100) ARIs=[] Core_nums=[] for num in min_samples: clst=cluster.DBSCAN(min_samples=num) predicted_labels=clst.fit_predict(X) ARIs.append(adjusted_rand_score(labels_true, predicted_labels)) Core_nums.append(len(clst.core_sample_indices_)) fig=plt.figure(figsize=(10,5)) ax=fig.add_subplot(1,2,1) ax.plot(min_samples,ARIs,marker='+') ax.set_xlabel("min_samples") ax.set_ylim(0,1) ax.set_ylabel('ARI') ax=fig.add_subplot(1,2,2) ax.plot(min_samples,Core_nums,marker='o') ax.set_xlabel("min_samples") ax.set_ylabel('Core_nums') fig.suptitle("DBSCAN") plt.show()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
centers = [[1,1],[1,2],[2,2],[10,20]] X,labels_true = create_data(centers,1000,0.5) test_DBSCAN_min_samples(X,labels_true)
- 1
- 2
- 3
MinPtsMinPts參數的影響結果以下:
能夠看出ARIARI指數隨着MinPtsMinPts的增加,平穩地降低。而核心樣本數量隨着MinPtsMinPts的增加基本呈線性降低,這是由於隨着MinPtsMinPts的增加,樣本點的鄰域中必須包含更多的樣本才能使它成爲一個核心點。所以產生的樣本點數量愈來愈少。
有關ARIARI,請參考: