DBSCAN密度聚類


1. 密度聚類概念

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

 

2. 密度聚類步驟

DBSCAN算法描述:
輸入: 包含n個對象的數據庫,半徑e,最少數目MinPts;
輸出:所有生成的簇,達到密度要求。
(1)Repeat
(2)從數據庫中抽出一個未處理的點;
(3)IF抽出的點是核心點 THEN 找出所有從該點密度可達的對象,形成一個簇;
(4)ELSE 抽出的點是邊緣點(非核心對象),跳出本次循環,尋找下一個點;
(5)UNTIL 所有的點都被處理。
DBSCAN對用戶定義的參數很敏感,細微的不同都可能導致差別很大的結果,而參數的選擇無規律可循,只能靠經驗確定。
              

這個算法的關鍵是理解幾個概念:

  • 直接密度可達
  • 密度可達
  • 核心點
  • 邊界點
  • 噪聲點
理解這些概念的一個資料: ppt
 
3. python實現
思路:首先找出所有核心點,核心點就是那些在半徑e以內的鄰域中有>=MinPts個點的點。注意:核心點以內的所有點都與核心點為同一類!  所以如果某兩類點集中有一個點為重復,那他們應該合並為一類!舉例:類別1:[1,2,4,6,8],類別2:[3,6,7,9,10,99]。這兩個集合最初是兩個類別,但是因為有共同點6,那么他倆應當合並為1類。所以這個算法就很簡單了,代碼步驟如下:
1)求出所有點的距離矩陣dis=[n,n], n為數據的個數。
2)如果e取值為3,那么dis的每一行中>3的所有點個數的和只要>MinPts,則為1個類別。 
3)所有這些類別進行重復檢查,只要有重復值則合並,直到沒有重復。
4)這些沒有重復的類別就是最終形成的類別。
簡單說明:
 
 
  
代碼:
 
# 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

 

         

                                     原圖                                                                                            結果圖

       

                                           原圖                                                                                                                   結果圖

 實驗過程中:前幾幅圖由於分布比較密集,參數調整要很多次,后幾張圖因為分布比較分散,所以參數基本一次設置成功。

結果和資料已上傳,下載~~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM