Birch層次聚類算法
標簽(空格分隔): CF樹建立
主要借鑒的網文地址,并進行大量引用:【非常淺顯易懂】
http://www.cnblogs.com/pinard/p/6179132.html 【主要以此文為主】
http://www.cnblogs.com/tiaozistudy/p/6129425.html
根據上述第二個網址的步驟,進行代碼化的代碼地址:
https://github.com/AresAnt/ML-DL/tree/master/Clustering/Birch
BIRCH算法比較適合于數據量大,類別數K也比較多的情況。它運行速度很快,只需要單遍掃描數據集就能進行聚類,當然需要用到一些技巧,下面我們就對BIRCH算法做一個總結。
【個人建議,如想要自己寫CF樹生成代碼前,請先了解一下B+樹的構造與寫法對之后的代碼完成將會有幫助。】
1.聚類特征CF與聚類特征樹CF Tree
在聚類特征樹中,一個聚類特征CF是這樣定義的:每一個CF是一個三元組,可以用(N,LS,SS)表示。其中N代表了這個CF中擁有的樣本點的數量,這個好理解;LS代表了這個CF中擁有的樣本點各特征維度的和向量,SS代表了這個CF中擁有的樣本點各特征維度的平方和。舉個例子如下圖,在CF Tree中的某一個節點的某一個CF中,有下面5個樣本(3,4), (2,6), (4,5), (4,7), (3,8)。則它對應的N=5, LS= (3+2+4+4+3,4+6+5+7+8) =(16,30), SS = (32+22+42+42+32+42+62+52+72+82) = (54+190) = 244。具體內容可如下所示:

CF有一個很好的性質,就是滿足線性關系,也就是CF1+CF2=(N1+N2,LS1+LS2,SS1+SS2)。這個性質從定義也很好理解。如果把這個性質放在CF Tree上,也就是說,在CF Tree中,對于每個父節點中的CF節點,它的(N,LS,SS)三元組的值等于這個CF節點所指向的所有子節點的三元組之和。如下圖所示:

從上圖中可以看出,根節點的CF1的三元組的值,可以從它指向的6個子節點(CF7 - CF12)的值相加得到。這樣我們在更新CF Tree的時候,可以很高效。
對于CF Tree,我們一般有幾個重要參數,第一個參數是每個內部節點的最大CF數B,第二個參數是每個葉子節點的最大CF數L,第三個參數是針對葉子節點中某個CF中的樣本點來說的,它是葉節點每個CF的最大樣本半徑閾值T,也就是說,在這個CF中的所有樣本點一定要在半徑小于T的一個超球體內。對于上圖中的CF Tree,限定了B=7, L=5, 也就是說內部節點最多有7個CF,而葉子節點最多有5個CF。
2.聚類特征樹CF Tree的生成
下面我們看看怎么生成CF Tree。我們先定義好CF Tree的參數: 即內部節點的最大CF數B, 葉子節點的最大CF數L, 葉節點每個CF的最大樣本半徑閾值T
在最開始的時候,CF Tree是空的,沒有任何樣本,我們從訓練集讀入第一個樣本點,將它放入一個新的CF三元組A,這個三元組的N=1,將這個新的CF放入根節點,此時的CF Tree如下圖:

現在我們繼續讀入第二個樣本點,我們發現這個樣本點和第一個樣本點A,在半徑為T的超球體范圍內,也就是說,他們屬于一個CF,我們將第二個點也加入CF A,此時需要更新A的三元組的值。此時A的三元組中N=2。此時的CF Tree如下圖:

此時來了第三個節點,結果我們發現這個節點不能融入剛才前面的節點形成的超球體內,也就是說,我們需要一個新的CF三元組B,來容納這個新的值。此時根節點有兩個CF三元組A和B,此時的CF Tree如下圖:

當來到第四個樣本點的時候,我們發現和B在半徑小于T的超球體,這樣更新后的CF Tree如下圖:

那個什么時候CF Tree的節點需要分裂呢?假設我們現在的CF Tree 如下圖, 葉子節點LN1有三個CF, LN2和LN3各有兩個CF。我們的葉子節點的最大CF數L=3。此時一個新的樣本點來了,我們發現它離LN1節點最近,因此開始判斷它是否在sc1,sc2,sc3這3個CF對應的超球體之內,但是很不幸,它不在,因此它需要建立一個新的CF,即sc8來容納它。問題是我們的L=3,也就是說LN1的CF個數已經達到最大值了,不能再創建新的CF了,怎么辦?此時就要將LN1葉子節點一分為二了。

我們將LN1里所有CF元組中,找到兩個最遠的CF做這兩個新葉子節點的種子CF,然后將LN1節點里所有CF sc1, sc2, sc3,以及新樣本點的新元組sc8劃分到兩個新的葉子節點上。將LN1節點劃分后的CF Tree如下圖:

如果我們的內部節點的最大CF數B=3,則此時葉子節點一分為二會導致根節點的最大CF數超了,也就是說,我們的根節點現在也要分裂,分裂的方法和葉子節點分裂一樣,分裂后的CF Tree如下圖:

有了上面這一系列的圖,相信大家對于CF Tree的插入就沒有什么問題了,總結下CF Tree的插入:
- 從根節點向下尋找和新樣本距離最近的葉子節點和葉子節點里最近的CF節點
- 如果新樣本加入后,這個CF節點對應的超球體半徑仍然滿足小于閾值T,則更新路徑上所有的CF三元組,插入結束。否則轉入3.
- 如果當前葉子節點的CF節點個數小于閾值L,則創建一個新的CF節點,放入新樣本,將新的CF節點放入這個葉子節點,更新路徑上所有的CF三元組,插入結束。否則轉入4。
- 將當前葉子節點劃分為兩個新葉子節點,選擇舊葉子節點中所有CF元組里超球體距離最遠的兩個CF元組,分布作為兩個新葉子節點的第一個CF節點。將其他元組和新樣本元組按照距離遠近原則放入對應的葉子節點。依次向上檢查父節點是否也要分裂,如果需要按和葉子節點分裂方式相同
3.Birch算法流程
如不愿看下列粗糙流程,可以參考:http://www.cnblogs.com/tiaozistudy/p/twostep_cluster_algorithm.html【之前給出的第二個網站,根據其步驟進行操作】
# 獲取的初始化參數的值,枝平衡銀子β,葉平衡因子λ,空間閾值T,以及是否
class Birch_Class():
# 獲取的初始化參數的值,枝平衡因子β,葉平衡因子λ,空間閾值T,以及是否
def __init__(self,branch_balance=2,leaf_balance=3,threshold=3,compute_labels=True):
self.branch_balance = branch_balance
self.leaf_balance = leaf_balance
self.threshod = threshold
self.compute_labels=compute_labels
傳入參數:
- 分支平衡參數: branch_balance
- 葉子平衡參數: leaf_balance
- 空間閾值: threshold
---以上三者數據用來初始化類的基本屬性
1.初始化CF樹為空樹(建立一個TreeNode,每個TreeNode有N個CFNode)【N與分支平衡因子與葉平衡因子有關】
2.逐條導入數據(后面統一用簇來代替),進行CF樹的填充
3.判斷當前插入的簇與TreeNode中最近的的CFNode(CF簇),然后篩選出該簇,進行同樣的遞歸計算,直到葉子節點。
#偽代碼:
if TreeNode is Leaf:
find nearest CFNode
else:
TreeNode = min(Dist(TreeNode.CFnode,傳進來的簇))
4.到葉子節點后發現,不滿足葉平衡因子,或計算的閾值超出了范圍,則進行葉節點分裂。
5.葉節點分裂后,會增加分支節點上的CFNode增加,此時需要判斷增加CFNode后的TreeNode是否滿足分支平衡因子,如果不滿足則當前分支節點進行分裂,同時上一層的分支節點進行CFNode數量增加。
#偽代碼:
# 計算葉節點是否要分裂,len(TreeNode)就是指CFNode的數量
if len(TreeNode) < leaf_balance or Dist(CFNode,傳入的簇) < threshold:
TreeNode.add(CFNode)
else:
TreeNode.split()
# 分裂后,判斷上一層分支數量會不會超出
@遞歸的函數
if len(TreeNode.parent) < branch_balance:
TreeNode.parent.add(TreeNode)
else:
TreeNode = TreeNode.parent (開始上面的函數遞歸)
6.簇插入到葉子節點時候,需要更新當前插入路徑下的聚類特征值,即L,SS,LS等
7.輸出CF樹,然后可以進行優化
4.Birch算法小結
BIRCH算法可以不用輸入類別數K值,這點和K-Means,Mini Batch K-Means不同。如果不輸入K值,則最后的CF元組的組數即為最終的K,否則會按照輸入的K值對CF元組按距離大小進行合并。
一般來說,BIRCH算法適用于樣本量較大的情況,這點和Mini Batch K-Means類似,但是BIRCH適用于類別數比較大的情況,而Mini Batch K-Means一般用于類別數適中或者較少的時候。BIRCH除了聚類還可以額外做一些異常點檢測和數據初步按類別規約的預處理。但是如果數據特征的維度非常大,比如大于20,則BIRCH不太適合,此時Mini Batch K-Means的表現較好。
對于調參,BIRCH要比K-Means,Mini Batch K-Means復雜,因為它需要對CF Tree的幾個關鍵的參數進行調參,這幾個參數對CF Tree的最終形式影響很大。
最后總結下BIRCH算法的優缺點:
BIRCH算法的主要優點有:
1) 節約內存,所有的樣本都在磁盤上,CF Tree僅僅存了CF節點和對應的指針。
2) 聚類速度快,只需要一遍掃描訓練集就可以建立CF Tree,CF Tree的增刪改都很快。
3) 可以識別噪音點,還可以對數據集進行初步分類的預處理
BIRCH算法的主要缺點有:
1) 由于CF Tree對每個節點的CF個數有限制,導致聚類的結果可能和真實的類別分布不同.
2) 對高維特征的數據聚類效果不好。此時可以選擇Mini Batch K-Means
3) 如果數據集的分布簇不是類似于超球體,或者說不是凸的,則聚類效果不好。