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

原圖 結果圖

原圖 結果圖
實驗過程中:前幾幅圖由於分布比較密集,參數調整要很多次,后幾張圖因為分布比較分散,所以參數基本一次設置成功。
結果和資料已上傳,下載~~~
