密度聚類之DBSCAN

      聚類算法K-means能夠處理一些聚類問題,但是其本身存在缺點:1.對噪聲(奇異點)很敏感;2.易收斂於局部最優解;3.不能發現非球狀簇。

       具體應用時,需要提前設置K值,且K值對運算過程和結果的影響很大;對於不規則聚類的處理效果很差,如下圖所示:


      本文將提出另一種聚類算法,基於密度的聚類算法——DBSAN,它能夠很好地解決上面實際應用中存在的問題。

一、  密度聚類、DBSCAN

1、密度聚類的核心思想:

    1)   簇羣是數據空間中的密集區域,在低密度區域處隔開;

    2)  一個簇被定義爲最大的密度連接點集;

    3)  能夠找到任意形狀的簇集。

2、基本概念

    1)  DBSCAN算法中有兩個重要參數 :ε和MinPts,前者爲密度定義時的鄰域半徑,後者是定義核心點時的閾值(也就是可以構成一個cluster的所需之最小的點數);

    2)  ε鄰域:以p對象爲中心,半徑爲ε的圓形或球形空間內所有對象的集合;p的ε鄰域:


    3)  高密度:ε鄰域內至少包括MinPts個對象;低密度:ε鄰域內對象少於MinPts個。因此上圖中,p的密度爲高密度,q的爲低密度。

    4)  三種類型的點:

       ①  核心點:高密度點,它是位於cluster內部的點,屬於某特定簇的點;

       ②  邊界點:低密度點,但其與核心點相鄰,它位於一個或多個簇的邊緣地帶,其屬於一個簇或另外一個簇,歸屬不明確;

       ③  噪聲點:既非核心點又非邊界點,數據集中的干擾數據,不屬於任何一個簇。


    5)  (直接)密度可達:如果p是核心點,q在其ε鄰域內,則稱q爲從p直接密度可達。下圖中,q從p直接密度可達,但p非從q密度可達,即:密度可達是非對稱的。


    6)  間接密度可達。上面講的是直接密度可達,如果p從p2直接密度可達,p2從p1直接密度可達,p1從q直接密度可達,q→p1→p2→p形成一個鏈,那麼成p爲從q間接密度可達,且q不能從p(間接)密度可達。綜上:密度可達具有傳遞性但不具有對稱性。


二、  DBSCAN的算法實現

      下面我們將對DBSCAN算法進行具體的實現和應用,具體將從三面入手:

1、算法僞代碼以及實現

      從上面的原理和概念可知,DBSCAN算法工作過程大體如下:

      1)根據ε和MinPts的值,先從樣本集D中找到一個核心點p(高密度點),並建立新簇C(p點放入此簇C中)。

      2)然後以此核心點p爲基礎,查找出其直接密度可達的點,並將這些點放入點集N(包括其自身)。

      3)對點集N中的所有點進行遍歷:將這些點放入簇C中,對每個點進行鄰域分析——對於核心點q(高密度點),將其直接鄰域可達(p點間接鄰域可達)的點,納入到點集N中;對於非核心點邊界點或噪聲q,此時因爲它是p點可達的(直接或間接),因此它將變成C的邊界點,非噪聲。

      4)重複上述過程3直到完成簇C的構建。注意:上述歸入到簇C的點均將設置爲已被訪問,因爲這些點均是核心點或邊界點,類型明確!

      5)對於樣本集中未訪問到的點(對於簇C而言是噪聲點),重複上述1—4過程,直到所有點均被遍歷/訪問到。

     綜上所述,DBSCAN算法的僞代碼如下:

(1) 首先將樣本集D中的所有對象標記爲未訪問狀態
(2) for(樣本集D中每個對象p) do
(3)     if (p已經歸入某個簇或標記爲已訪問) then
(4)         continue
(5)     else
(6)         檢查對象p的eps鄰域eps(p)
(7)         if (eps(p)包含的對象數不小於MinPts) then
(8)             標記對象p爲核心點,並標記其已被訪問
(9)             建立新簇C,p點放入簇C中
(10)            將p的eps(p)內的點放入點集N中
(11)            for (點集N中未處理的點q)  do
(12)                將q點放入簇C中,標記q點爲已處理(已歸入某簇或已訪問)
(13)                if (eps(q)包含的對象數不小於MinPts) then
(14)                    將q點標記爲核心點
(15)                    將其鄰域內的點加入點集N中
(16)                else
(17)                    將q點標記爲邊界點
(18)        else
(19)            將p點標記爲邊界點或噪聲點

      我們仍以iris數據集爲樣本進行相關的應用,具體python代碼如下:

def dist_calc(a,b): #計算ab兩點的距離,ab必須爲np.array 
    import math
    return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)

def region_search(p,eps,X): #鄰域搜索,返鄰域內滿足eps區域條件的點的個數
    num = 0 #記錄鄰域內點的個數,包括p自身
    ind = [] #記錄鄰域內點的索引
    for i,x in enumerate(X):
        if(dist_calc(p,x) <= eps): #鄰域搜索
            num += 1 
            ind.append(i)
    return num,ind #返回鄰域內點個數以及其索引值

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import DBSCAN

%matplotlib inline

iris = datasets.load_iris()
X = iris.data[:,2:4]    #樣本集
flag = [0 for x in X]  #訪問標誌,0未訪問,1已訪問
C_tp = [-1 for x in X] #類型標誌,-1未分類,012345分別代表類型索引
eps = 1 #定義鄰域半徑
pts = 6   #定義最少點數
C = -1    #定義簇個數,-1代表未分類

for i,x in enumerate(X):
    N = [] #對簇中對象的索引進行記錄
    if flag[i] == 1: #已訪問,
        continue
    else: #i點未被訪問時
        n_i,index_i = region_search(x,eps,X) #查找i點鄰域
        if( n_i >= pts): #高密度,從i點直接密度可達
            flag[i] = 1 #i點爲核心點,標記其已被訪問
            C += 1 #定義簇
            C_tp[i] = C #將i點放到簇C中,此時i點爲核心點
            N.extend(index_i) #將核心點鄰域內點的索引值進行記錄,歸屬於簇C
            
            for j in N: #對鄰域內的點進行遍歷查找
                if flag[j] == 1: #已訪問,防止重複遍歷
                    continue
                else:
                    flag[j] = 1 #標記已訪問
                C_tp[j] = C #將核心點鄰域內的點放到簇C中,密度可達的點

                n_j,index_j = region_search(X[j],eps,X) #查找j點的鄰域
                if( n_j >= pts): #高密度,j點爲核心點,鄰域內爲從i點間接密度可達
                    N.extend(index_j) #將核心點鄰域內點索引進行記錄,以便後續將其歸入C簇中
                else: #低密度,j點爲邊界點或噪聲
                    continue
        else: #低密度,直接密度不可達,噪聲或邊界點,此時不做相關操作
            continue
# print(C)
color = ('red','blue','yellow','black')
colors = np.array(color)[C_tp]
plt.scatter(X[:,0],X[:,1],c=colors,marker='+',s=20)
plt.show()

2、Scikit-learn函數調用

      此處仍以iris數據集爲樣本進行相關的應用,具體代碼如下:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.cluster import DBSCAN
%matplotlib inline
iris = datasets.load_iris()
X = iris.data[:,2:4]
# print(X)
plt.scatter(X[:,0],X[:,1],c='green')
plt.show()

db_pred = DBSCAN(eps=1,min_samples=6).fit_predict(X)
color = ('red','blue','yellow','black')
colors = np.array(color)[db_pred]
plt.scatter(X[:,0],X[:,1],c=colors,marker='+',s=20)
plt.show()

3、官方例程參考

      官方例程參考如下網址:

http://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html#examples-using-sklearn-cluster-dbscan

三、  關於ε和MinPts的選取



       


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章