1. 密度聚類概念
DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪聲的基於密度的聚類方法)是一種很典型的密度聚類算法,和K-Means,BIRCH這些一般只適用於凸樣本集的聚類相比,DBSCAN既可以適用於凸樣本集,也可以適用於非凸樣本集。
2. 密度聚類步驟

這個算法的關鍵是理解幾個概念:
- 直接密度可達
- 密度可達
- 核心點
- 邊界點
- 噪聲點

# coding:utf-8 """ @author = LPS """ import numpy as np import matplotlib.pyplot as plt data = np.loadtxt('moon.txt') n,m = data.shape all_index = np.arange(n) dis = np.zeros([n,n]) data = np.delete(data, m-1, axis=1) def dis_vec(a,b): # 計算兩個向量的距離 if len(a)!=len(b): return Exception else: return np.sqrt(np.sum(np.square(a-b))) for i in range(n): # 計算距離矩陣 for j in range(i): dis[i,j] = dis_vec(data[i],data[j]) dis[j,i] = dis[i,j] def dbscan(s, minpts): # 密度聚類 center_points = [] # 存放最終的聚類結果 k = 0 # 檢驗是否進行了合並過程 for i in range(n): if sum(dis[i] <= s) >= minpts: # 查看距離矩陣的第i行是否滿足條件 if len(center_points) == 0: # 如果列表長為0,則直接將生成的列表加入 center_points.append(list(all_index[dis[i] <= s])) else: for j in range(len(center_points)): # 查找是否有重復的元素 if set(all_index[dis[i] <= s]) & set(center_points[j]): center_points[j].extend(list(all_index[dis[i] <= s])) k=1 # 執行了合並操作 if k==0 : center_points.append(list(all_index[dis[i] <= s])) # 沒有執行合並說明這個類別單獨加入 k=0 lenc = len(center_points) # 以下這段代碼是進一步查重,center_points中所有的列表並非完全獨立,還有很多重復 # 那么為何上面代碼已經查重了,這里還需查重,其實可以將上面的步驟統一放到這里,但是時空復雜的太高 # 經過第一步查重后,center_points中的元素數目大大減少,此時進行查重更快! k = 0 for i in range(lenc-1): for j in range(i+1, lenc): if set(center_points[i]) & set(center_points[j]): center_points[j].extend(center_points[i]) center_points[j] = list(set(center_points[j])) k=1 if k == 1: center_points[i] = [] # 合並后的列表置空 k = 0 center_points = [s for s in center_points if s != []] # 刪掉空列表即為最終結果 return center_points if __name__ == '__main__': center_points = dbscan(0.2,10) # 半徑和元素數目 c_n = center_points.__len__() # 聚類完成后的類別數目 print (c_n) ct_point = [] color = ['g','r','b','m','k'] noise_point = np.arange(n) # 沒有參與聚類的點即為噪聲點 for i in range(c_n): ct_point = list(set(center_points[i])) noise_point = set(noise_point)- set(center_points[i]) print (ct_point.__len__()) # 輸出每一類的點個數 print (ct_point) # 輸出每一類的點 print ("**********") noise_point = list(noise_point) for i in range(c_n): ct_point = list(set(center_points[i])) plt.scatter(data[ct_point,0], data[ct_point,1], color=color[i]) # 畫出不同類別的點 plt.scatter(data[noise_point,0], data[noise_point,1], color=color[c_n], marker='h', linewidths=0.1) # 畫噪聲點 plt.show()
DBSCAN的主要優點有:
1) 可以對任意形狀的稠密數據集進行聚類,相對的,K-Means之類的聚類算法一般只適用於凸數據集。
2) 可以在聚類的同時發現異常點,對數據集中的異常點不敏感。
3) 聚類結果沒有偏倚,相對的,K-Means之類的聚類算法初始值對聚類結果有很大影響。
DBSCAN的主要缺點有:
1)如果樣本集的密度不均勻、聚類間距差相差很大時,聚類質量較差,這時用DBSCAN聚類一般不適合。
2) 如果樣本集較大時,聚類收斂時間較長,此時可以對搜索最近鄰時建立的KD樹或者球樹進行規模限制來改進。
3) 調參相對於傳統的K-Means之類的聚類算法稍復雜,不同的參數組合對最后的聚類效果有較大影響。
實驗:
原圖 square4 e=0.85 minpts = 13 square4-sklearn e=0.9 minpts=15
原圖 結果圖
原圖 square1 1.185,8 square1 0.85 15
原圖 結果圖
原圖 結果圖
實驗過程中:前幾幅圖由於分布比較密集,參數調整要很多次,后幾張圖因為分布比較分散,所以參數基本一次設置成功。
結果和資料已上傳,下載~~~