說到聚類,相信大家最先想到的應該是k-means,但是我們知道k-means必須指定聚類的個數,而且聚類初始點的選取也很大影響最後聚類的效果。雖然有一些方法(如k-means++)可以設定較為合理的初始聚類點,但仍然需要指定聚類的個數,但有時我們並不知道一堆資料中有多少個類,這樣就使得聚類變得沒法下手。這裡介紹一種利用一種樹型資料結構——不相交集,實現的資料聚類方法。
不相交集(disjoint-set),也叫並查集(union-find)是保持一組不相交的動態集合。給定一系列資料,我們首先假設每個元素是乙個集合,通過集合的查詢合併實現等價元素的合併,從而實現相同類別的元素的聚類。這裡兩個元素等價的標準是由自己設定,取決於具體應用。例如目標檢測中滑窗檢測目標時用於聚合方框,其等價標準就是方框的重疊率的大小;再比如影象處理中聯通區域標記的應用,其等價標準就是兩個點是否聯通。 ###opencv中並查演算法的實現
opencv中的partition函式實現了這一資料分類的功能,具體的函式宣告如下:
12
templateint partition (const
vector
< _tp > & vec, vector
< int > & labels, _eqpredicate predicate =_eqpredicate())
其中,
下面做個簡單的示例: 當使用bool函式的時候,呼叫如下,注意equivalence沒有括號
123456
bool equivalence(constint &a, const
int &b)
cv::partition(data,labels,equaliance);
當使用函式物件的時候,呼叫如下,這次equivalence有括號,如果需要傳入引數的話,可以在類裡面寫個私有變數,傳入即可。
1234567
8910
class equivalence};cv::partition(data,labels,equaliance());
在介紹partition源**之前,先大體講一下不相交集資料結構的一種較快的實現方式——不相交集森林。用有根樹來表示乙個集合,樹上的每個節點都是集合中的元素,每棵樹代表乙個集合。通過引入兩種啟發式策略,可以實現目前已知最快的並查演算法。具體的介紹可以參考thomas h. cormen等人的《演算法導論》第二十一章的內容。此外除了opencv中有這個演算法的實現外,boost中也有相關的實現,可以參考disjoint sets。
兩種啟發式策略:
按秩合併:是指兩棵樹在合併的時候秩小的樹的根指向值大的樹的根,當兩棵樹秩相同的時候,任選一棵樹指向另一棵樹,同時秩加一。這裡秩是指樹的高度。
壓縮路徑:是指使查詢路徑上的每個節點都直接指向根節點,但該操作不改變秩的大小,因為秩還要用到樹的合併中。
opencv中partition的實現在opencv_core工程下的operations.hpp檔案下。下面貼出核心**,並作了詳細注釋:
1234567
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
templateint 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 傳遞...