dbscan算法以及其基於grid建立索引的改進方法


1. 什麼是DBSCAN?

DBSCAN全稱Density-based spatial clustering of applications with noise,即帶噪聲的基於密度的空間聚類。主要思想就是把空間中密度較大,每個點之間有多個鄰近點的部分聚爲一類,而把密度較低的部分作爲離羣值(outlier)對待。

1.1 幾個概念

DBSCAN需要設置兩個參數,minPts和ϵ,這兩個參數主要用於定義以下概念。

核心點(Core Point)、密度可達(Reachablility)、離羣點(Outlier)

  1. 核心點:如果一個點p,在以它爲球心,以ϵ爲半徑的球內,至少有minPts個點(包括p點自己),則這個點被稱爲核心點(Core Point)。且這些在球內的點被稱爲直接可達p點。
  2. 密度可達:設有點p1,p2,p3pn,且這些點均爲核心點,另有一點q,如果pi直接可達pi+1i=1,2,...,n1,且pn直接可達q,那麼我們說p1密度可達qq is Density Reachable from p1)。
  3. 離羣點:如果一個點除了自己以外沒有其他點密度可達它,那麼這個點被定義爲離羣點(Outlier)。

密度相連(Connectedness)

根據密度可達(reachable)的定義,我們可以發現,reachable並不是對稱的,p密度可達q,但如果q不是核心點,那麼q並不密度可達p。因此,引入密度相連的概念。定義如下:
已知有點pq,如果另存在點oo既密度可達p也密度可達q,則陳pq密度相連(Density-Connected)。

簇(Cluster)

有了密度相連的定義,簇的定義隨即產生。在dbscan中,所有密度相連的點構成的集合爲一個(cluster)。具體請見下例(來自wikipedia)。

上圖爲2中各點,設minPts = 4,各圓的半徑爲ϵ。則各紅點爲核心點,因爲空間中距離它們ϵ的點至少有4個(包括自己)。另外,紅點和黃點密度相連,它們共同形成了一個簇。最後,藍色點N是離羣點,因爲沒有任何點可達它。

我們可以觀察到上圖中的B點和C點雖然不是核心點,但是它們與紅色點密度相連,因此也被歸到和紅色點一起的簇中。只不過作爲非核心點,它們沒法再向外拓展其他它們直接可達的點。因而可以把這些點理解爲這個簇的邊界點。

僞代碼

D: total points set
eps: ϵ,用於定義核心點的半徑
MinPts: 用於定義核心點的鄰近點數量

DBSCAN(D, eps, MinPts) {
   C = 0
   for each point P in dataset D {
      if P is visited
         continue next point
      mark P as visited
      NeighborPts = regionQuery(P, eps)
      if sizeof(NeighborPts) < MinPts
         mark P as NOISE
      else {
         C = next cluster
         expandCluster(P, NeighborPts, C, eps, MinPts)
      }
   }
}

expandCluster(P, NeighborPts, C, eps, MinPts) {
   add P to cluster C
   for each point P' in NeighborPts { 
      if P' is not visited {
         mark P' as visited
         NeighborPts' = regionQuery(P', eps)
         if sizeof(NeighborPts') >= MinPts
            NeighborPts = NeighborPts joined with NeighborPts'
      }
      if P' is not yet member of any cluster
         add P' to cluster C
   }
}

regionQuery(P, eps)
   return all points within P's eps-neighborhood (including P)
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32

通過上式可以看到,一個cluster的擴張,全是通過核心點來做的。

複雜度

由於要比較每個點之間的距離來判斷點與點之間是否“直接密度可達”,因此在這裏算法複雜度爲O(n2)

優點和缺點

優點:DBSCAN算法最大的優點是它不需要像kmeans一樣事先明確具體的簇的數量;且DBSCAN面向的的數據集簇的形狀可以是非凸的,這是因爲某點是否屬於一個簇是由這個簇中做靠近它的核心點決定的,也就是說這個簇的局部來決定,而不是像kmeans一樣一個點代表了整個簇;另外,由於DBSCAN有離羣點的概念,模型健壯性更強;最後,在具體領域中,如果模型使用者對數據認識非常到位,可以把minPts和ϵ兩個參數定的比較合適,有時候這兩個參數或許是可以由對應實際學科中的某概念來解釋。
缺點: DBSCAN中,部分在簇邊界上的點可能可以被分到多個簇中,具體被分到哪個取決於遍歷時的順序,不過這個並不會影響到核心點和離羣點的定義,以及核心點之間的聚類;由於需要計算距離(通常用歐氏距離),一旦數據的維數較高,計算量會很大,而且此時定義一個合適的ϵ難度也會比較大;另外,數據集中每個簇自己的密度可能會有點不同,此時唯一的minPts-ϵ組合並不能很好的描述這個場景。

什麼是Gridded DBSCAN?

通過上文,其實可以發現DBSCAN中很關鍵的一個部分是決定數據集中每個點是否是核心點。傳統DBSCAN做法是計算每個點之間的距離,並以此判斷各點的鄰近點數量,算法複雜度是O(n2)。事實上,決定一個點是否爲核心點,只需要參考這個點與“周圍”的點的距離即可,並不需要計算這個點和其餘所有點之間的距離。也就是說,如果我們能保證在這個“周圍”之外的點的距離一定大於ϵ,且讓這個“周圍”儘可能的大或者可以提供其他一些方面計算的便利,我們就可以省去很多計算。那麼,到底如何合理地定義這個”周圍“呢?
有一個思路是將數據集劃成一個個的小格,每個小格就是一個“周圍”,在這個小格中的各點之間可以由一定的關係,且各小格之間也有一些關係來簡化一些計算。詳細思路請見下文。

爲便於說明和理解,下文中的說明都將以2中數據集爲例。

怎麼劃grid?

2劃分成各個以ϵ/2爲邊長的正方形小格(下文有時稱grid),則每個點唯一對應的grid也可以確定下來,具體爲各點座標除以grid的邊長,取下界整數。此處算法複雜度爲O(n)

爲什麼這麼劃好?

這麼定義grid有如下好處:
1. 首先,每個小格的對角線長度爲ϵ,是每個小格內的最長距離。換句話說,每個小格內的各點之間的距離不會超過ϵ,因此,如果在同一個小格中的點數量超過了參數minPts,那麼不需要計算這些點的鄰近點數量,就可以直接判斷這些點爲核心點;
2. 對那些包含點數量沒超過minPts的小格,也不需要講其中的點和數據集中其他所有點計算距離。一來對於小格中的點,小格中已包含了一部分它的鄰近點,其次,我們只需要去鄰近的小格中找點即可,如下圖中,對最中心的grid,只需要找其周圍的21個grid(包括自己)中的點幾個。


本圖來自參考文獻
本圖來自參考文獻

3. 因爲每個grid內點與點之間的距離不大於ϵ ,因此同一個grid的點互相密度相連。所以,如果兩個來自不同grid的核心點之間可以確定密度相連,那麼,這兩個grid中所有點都密度相連。換句話說,我們就不需要再確定每個點之間是否相連,而只需要確定grid與grid之間是否相連即可,這裏“grid密度相連”的定義爲:如果p1是來自grid1的核心點,p2是來自grid2的核心點,且p1,p2密度相連,則grid1,grid2密度相連。

僞代碼

D: total points set
eps: ϵ,用於定義核心點的半徑
MinPts: 用於定義核心點的鄰近點數量

G = set_grid(); // 分配所有點到對應的grid,得到grid的全集G
find_core_point();
merged_G = merge_grid(); // 將grid合併,merged_G可以看成一個二維數組,所有互相連接的grid存在同一個數組中
class_point();

find_core_point() {
    for grid in G
        size = grid.pt_set.size();
        if (size > minPts)
            每個grid.pt_set中的點均爲核心點;
        else 
            for pt in grid.pt_set
                if (pt與grid.neigh_grid_set中超過(minPts - size)個點距離小於eps)
                    pt是核心點;
}

merge_grid() {
    for grid in G
        for neigh_grid in grid.neigh_grid_set
            check grid與neigh_grid是否相連
    merge_connected_grid();
}    

class_point() {
    for cluster in merged_G
        所有clster.grid.pt記爲一個簇
    for grid in G
        if grid not in merged_G // 這些grid中沒有core_point
            for neigh_grid in grid.neigh_grid.set
                if neigh_grid中有core_point與grid中點相連
                    neigh_grid中各點分到core_point的簇中
                    breakgrid中所有點爲NOISE;
}
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 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
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

優點和缺點

根據參考文獻中描述,加入grid索引之後,算法複雜度可以降到O(nlog(n)) ,且在計算中略去了不少不必要的點與點之間的計算。但是這個方法仍不能解決在數據特徵維數變高後帶來的計算問題,而且,當數據特徵維數變多之後,尋找grid的neighbour grid的難度也會變大。

留存問題

當特徵維數變多之後,尋找grid的鄰近grid難度較大。Brute force的方法是直接找包含從grid各邊向外延伸一個ϵ的最小正方體,但一旦維數變多,這個超正方體會包含很多非鄰近grid的grid。

參考文獻

  1. Ade Gunawan, A Faster Algorithm for DBSCAN, Technische Universiteit Eindhoven
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章