利用不相交集實現等價元素的聚類

2021-07-05 12:47:19 字數 3252 閱讀 4000

說到聚類,相信大家最先想到的應該是k-means,但是我們知道k-means必須指定聚類的個數,而且聚類初始點的選取也很大影響最後聚類的效果。雖然有一些方法(如k-means++)可以設定較為合理的初始聚類點,但仍然需要指定聚類的個數,但有時我們並不知道一堆資料中有多少個類,這樣就使得聚類變得沒法下手。這裡介紹一種利用一種樹型資料結構——不相交集,實現的資料聚類方法。

不相交集(disjoint-set),也叫並查集(union-find)是保持一組不相交的動態集合。給定一系列資料,我們首先假設每個元素是乙個集合,通過集合的查詢合併實現等價元素的合併,從而實現相同類別的元素的聚類。這裡兩個元素等價的標準是由自己設定,取決於具體應用。例如目標檢測中滑窗檢測目標時用於聚合方框,其等價標準就是方框的重疊率的大小;再比如影象處理中聯通區域標記的應用,其等價標準就是兩個點是否聯通。 ###opencv中並查演算法的實現

opencv中的partition函式實現了這一資料分類的功能,具體的函式宣告如下:

1

2

template

int partition (const

vector

< _tp > & vec, vector

< int > & labels, _eqpredicate predicate =_eqpredicate())

其中,

下面做個簡單的示例: 當使用bool函式的時候,呼叫如下,注意equivalence沒有括號

123

456

bool equivalence(const

int &a, const

int &b)

cv::partition(data,labels,equaliance);

當使用函式物件的時候,呼叫如下,這次equivalence有括號,如果需要傳入引數的話,可以在類裡面寫個私有變數,傳入即可。

123

4567

8910

class equivalence

};cv::partition(data,labels,equaliance());

在介紹partition源**之前,先大體講一下不相交集資料結構的一種較快的實現方式——不相交集森林。用有根樹來表示乙個集合,樹上的每個節點都是集合中的元素,每棵樹代表乙個集合。通過引入兩種啟發式策略,可以實現目前已知最快的並查演算法。具體的介紹可以參考thomas h. cormen等人的《演算法導論》第二十一章的內容。此外除了opencv中有這個演算法的實現外,boost中也有相關的實現,可以參考disjoint sets。

兩種啟發式策略:

按秩合併:是指兩棵樹在合併的時候秩小的樹的根指向值大的樹的根,當兩棵樹秩相同的時候,任選一棵樹指向另一棵樹,同時秩加一。這裡秩是指樹的高度。

壓縮路徑:是指使查詢路徑上的每個節點都直接指向根節點,但該操作不改變秩的大小,因為秩還要用到樹的合併中。

opencv中partition的實現在opencv_core工程下的operations.hpp檔案下。下面貼出核心**,並作了詳細注釋:

123

4567

891011

1213

1415

1617

1819

2021

2223

2425

2627

2829

3031

3233

3435

3637

3839

4041

4243

4445

4647

4849

5051

5253

5455

5657

5859

6061

6263

6465

6667

6869

7071

7273

7475

7677

7879

8081

8283

8485

8687

8889

9091

9293

9495

9697

9899

100101

102103

104105

106107

108

template

int partition( const

vector

<_tp>& _vec, vector

& labels,

_eqpredicate predicate=_eqpredicate())

// the main o(n^2) pass: merge connected components

for( i = 0; i < n; i++ )

//判定此時的root是樹的根節點

assert( nodes[root][parent] < 0 );

int k = j, parent;

// compress the path from node2 to root

// 壓縮j處節點的路徑,沿著j處的節點向上逐一指向根節點

while( (parent = nodes[k][parent]) >= 0 )

// compress the path from node to root

//壓縮i處節點的路徑,沿著i處節點向上逐一指向根節點

k = i;

while( (parent = nodes[k][parent]) >= 0 )

}} }

// final o(n) pass: enumerate classes

labels.resize(n);

int nclasses = 0;

//對每個元素找到它的根節點,然後重新利用rank,

//把rank賦值為集合的類別label

for( i = 0; i < n; i++ )

return nclasses;

}

相比傳統的k-means聚類方法,該方法具有不需要指定聚類個數的優勢。針對要分類的資料集,如果你事先知道元素間相似性的判斷準則,像重疊矩形框的聚合,那麼用並查演算法是比較方便的。我的理解是k-means的聚類方法不需要知道元素確切的屬於同一類元素的相似性準則,而是通過該元素與每個集合的中心點的距離遠近判定元素的集合歸屬。

利用不相交集畫迷宮

當我們畫乙個80 50的迷宮時相當於是畫了個80 50的方格仔,把格仔和格仔之間的某些牆拆掉,互相連通的格仔我們稱之為屬於同乙個集合,如果兩個集合不連通,那就稱之為不相交集.畫迷宮的過程就是不斷地拆除格仔與格仔之間的牆,直到第乙個格仔和最後乙個格仔屬於同乙個集合演算法終止.不相交集類.ifndef ...

不相交集python實現

1.不相交集是解決等價關係的一種資料結構,執行合併和查詢的速度都非常快,m次執行合併和查詢的執行時間為 m logn 在乙個集合中,對於每一對元素 a,b a,b s,對於關係r如果滿足下面三個條件,則成關係r為等價關係 1 自反性 對於所有a s,ara 2 對稱性 arb當且僅當bra 3 傳遞...

不相交集ADT

1.不相交集是解決等價關係的一種資料結構,執行合併和查詢的速度都非常快,m次執行合併和查詢的執行時間為 m logn 在乙個集合中,對於每一對元素 a,b a,b s,對於關係r如果滿足下面三個條件,則成關係r為等價關係 1 自反性 對於所有a s,ara 2 對稱性 arb當且僅當bra 3 傳遞...