1. 程式人生 > >頻繁項集挖掘之apriori和fp-growth

頻繁項集挖掘之apriori和fp-growth

Apriori和fp-growth是頻繁項集(frequent itemset mining)挖掘中的兩個經典演算法,主要的區別在於一個是廣度優先的方式,另一個是深度優先的方式,後一種是基於前一種效率較低的背景下提出來的,雖然都是十幾年前的,但是理解這兩個演算法對資料探勘和學習演算法都有很大好處。在理解這兩個演算法之前,應該先了解頻繁項集挖掘是做什麼用的。

頻繁項集挖掘是關聯規則挖掘中的首要的子任務。關聯規則挖掘是要找出一個數據集上,滿足一定條件的項集。這些項的集合能構成 形如蘊含式"A=>B"這樣的“規則”。這個"=>"符號是通過一些條件來定義的,如果沒有條件那當然所有的項組合都能形成這樣的關係。頻繁程度就是一種要求,也就是AB共同次數出現了超過閾值。 A和B能否形成"=>"規則, 就要根據定義來算,那首先就得把A、B需要的條件挖出來,也就是頻繁項集挖掘要做的。

關聯規則定義比較容易能搜到,頻繁項集挖掘簡單的說就是:給定一個項列表list = {A,B,C,...},一個數據集D的每條記錄都是list 的子集,要找出資料集中頻繁共同出現次數超過閾值t,也就是支援度,的所有組合。

這個挖掘其實不好做,因為結果可能是list 中所有項的組合,有2^|list|個可能,搜尋空間是個組合爆炸的空間。看下圖,先別看紅字紅線:

                  

要弄好這件事不僅需要有效減小搜尋空間,而且對每個可能的搜尋都必須快速完成。所以頻繁項集挖掘在演算法實踐和編碼實現上就要有非常強的技巧。我們就來深入學習apriori和fp-growth中的搜尋方式和技巧。這兩個演算法很容易找到完整的步驟,這裡會更注重裡面一些精彩之處,但是可能書寫不會那麼規範,建議和完整演算法對照來讀。

先來看看apriori。Apriori採用廣度優先的搜尋方式,縮小搜尋空間用到了一個稱為apriori的性質。Apriori性質是這麼說的:頻繁項集的所有非空子集必然也是頻繁的。這是很顯然的,比如 同時包含項AB的記錄條數肯定比只包含A的記錄少。這條性質反過來也可以這麼說:如果一個項集是非頻繁的,那麼它的超集必然也是非頻繁的。

演算法過程如下:

 輸入:資料集D,支援度minsup

 輸出:滿足支援度的所有項集的集合L

L1 = 發現1-項集(D); 

 for (k=2;Lk-1 ≠Φ ;k++) {

 Ck = 連線剪枝生成(Lk-1, minsup)

      掃描D,為Ck中每個項集c

 統計 c.count

      保留Lk ={c ∈ Ck|c.count≥min_sup}

      L = L ∪ Lk  

 }

 Return L

其中演算法精華在於 連線剪枝生成(Lk-1, minsup) 這一步, 包含連線步和剪枝步兩個動作:

1. 連線步:長度k-1的項連線成長度k的項;具體就是對兩個k-1長的項L1和L2,必須滿足前k-2個項都相同才能連線,最後把L1和L2剩下的最後一項加起來,形成k的長度的項。

2. 剪枝步:k項連線完成後,檢查其所有k-1子集是否是頻繁的,如果是,才保留作為候選項。

可以通過一張截圖來演示一下apriori的過程:



對應第一張圖,連線步是從第k層的項集,向下擴充套件一層的候選項集,剪枝步能夠通過apriori性質過濾掉那些肯定非頻繁的項集。

Apriori的框架其實很小,但是可以想象得到主要的兩個步驟: 連線+剪枝(也就是候選集生成),以及,候選集統計是很耗費時間的。

剪枝步也需要對每個k-候選項集的k-1子集都進行一次檢測,也很耗費時間;統計頻繁次數是必須的,因此需要掃描資料庫,經歷I/O。那麼有必要剪枝,直接統計會不會更好呢,雖然沒有試驗過,但我估計還是剪枝以後減少候選集的統計更划算。而這兩個耗時的步驟在實現上如果能使用到技巧,對演算法時間影響最直接。比如剪枝步中k-1候選項集需要逐一向已有的k-1頻繁項集查詢,這用什麼資料結構最好?又如掃描資料庫的時候是否能過進行一些壓縮,相同的記錄進行合併減少遍歷次數,以及過濾掉對統計沒用的記錄?

面對apriori的問題,感覺Fp-growth突然間就冒出來了,它是一個挖掘方式和apriori完全不一樣的演算法,直接看可能不那麼像apriori直觀,因為演算法一開始就介紹了它採用的資料結構和挖掘方式。所以我們先對比下apriori和fp-growth的差異在哪,再介紹它的演算法。

簡單的說apriori是先產生一批候選項集,再通過原資料集去過濾非頻繁項集:先找A、B、C,檢查一下通過了,再找AB、AC、AB,檢查又通過了,再到ABC... 這樣的廣度優先的方式。而fp-growth是先從資料集中找頻繁的項,再從包含這個頻繁項的子資料集中找其他的頻繁項,把它們倆連起來也肯定是頻繁的:先找A,再在找包含A的子資料庫裡,找到B,就得到AB是頻繁,再再包含AB的子資料庫裡,找到C,ABC就是頻繁了。

在瞭解了fp-growth的大致思路以後,我們就能介紹它採用的資料結構和演算法了。

首先fp-growth採用了一個叫fp-tree 的資料結構去壓縮儲存資料集,放到記憶體裡,這樣以後過問原資料集的事就不必經過IO了。

Fp-tree主要是一種字首樹,和字典樹(trie)接近,並且節點把項的次數也記錄下了。字元的順序有所不同,字典樹用的是字母表順序,fp-tree (frequent pattern tree)用的是字母表的頻率降序,這樣的好處是出現次數多的項作為共享字首的概率也大,fp-tree的壓縮率就高(後面還會提到),根據apriori性質,非頻繁的項沒用,因此fp-tree上可以沒有它們。

根據前面提到fp-growth步驟,需要找資料庫上包含某個項的子資料庫,不能從樹根開始搜尋,因此為了方便,需要把fp-tree中所有枝幹、葉子上相同的項全串一起,這樣項從一個起點開始,向樹根遍歷,就能得到包含這個項的子資料庫了。這些起點和串起相同節點的鏈就是fp-tree的另一個部分:頭表和兄弟鏈。頭表包含樹上所有的單項,並是兄弟鏈的起點,那麼fp-tree不僅完整記錄了資料庫裡所需的資訊,還能找到對任一項找到包含了它的子資料庫。


有了fp-tree,挖掘頻繁項集就變得直觀了。首先是壓縮資料庫,過濾非頻繁項,得到一棵fp-tree 1號,對於一個項,比如A,通過兄弟鏈,遍歷樹找出 包含A的子樹(庫),又稱A的條件模式樹(庫),英文原文叫condition pattern tree(base)。然後把這個子庫當做一個新的資料庫2號,過濾2號庫非頻繁項,建立一個小點的fp-tree 2號,那麼那個A與這個2號樹裡的所有項,連起來肯定也是頻繁的;比如有B,同理把B的條件樹找出,也建立個fp-tree 3號,就能得到AB和3號樹上的項連起來也肯定是頻繁的。這個過程遞迴完成,建立不出條件子樹遞迴就跳出去。


演算法包含兩個部分:

1. 是建立fp-tree:掃描一遍資料庫,得到每個項的支援度,排序並過濾非頻繁項;再掃描一次資料庫,每條記錄按順序排序,新增到fp-tree上。

2. 呼叫演算法FP_growth(FP-tree, null)。

   Function Fp_growth(FP-tree, a){

 if(fp-tree 是單條路徑){

   對路徑上的組合b, 都連線a,輸出b∪ 

 }else{

   For each 項ai in 頭表{

     輸出一個模式b= ai∪ a,其支援度 support =ai.support 

     構造b的條件模式庫,然後構造b的條件模式樹 Treeb; 

     If (Treeb 不為空){

        呼叫演算法FP_growth(Treeb,b )

  }

 }

 }

FP_growth是個遞迴演算法,期間需要反覆遍歷樹和構建fp-tree。fp-growth中判斷單路徑部分可以不要,最後實際結果其實是和下面部分是一樣的,但是直接計算單路徑產生所有組合會便捷很多。另外一點,fp-tree要按支援度降序的順序的好處有幾點?前面說了可以提高共享字首的可能,提高壓縮率,樹小了,遍歷的步數還能減小,尋找最優壓縮的順序是個NP難問題,因此選這個辦法能有個比較好的壓縮率足夠了。

fp-growth雖然號稱不產生候選集,但是實際上候選集產生已經在尋找條件子庫的時候隱隱產生了,剪掉非頻繁候選項的時候是通過建樹步驟中的第一小步完成的。

fp-growth在實現上也可以有很多技巧,比如尋找條件子樹的時候,同一條路徑會被遍歷很多次,如何有效避免(後來han自己提出,遇到掃把型的fp-tree,即上面是單路徑、下面分叉的,可以把單路徑所有的組合分別連線到下面的部分挖掘結果上輸出,那就不用遍歷上面的單路徑了) 另外樹上節點用什麼資料結構儲存指向子孫節點的指標,能同時兼顧查詢時間和空間?


最後我們總結一下apriori和fp-growth之間的聯絡和差異。

初讀fp-growth演算法,估計都感覺不到它和apriori有什麼關係,但我個人猜測fp-growth是從apriori的統計候選集太耗時的那裡 改良開始的,希望實現候選項集的更快速的計算支援度,最後就徹底的改變的搜尋頻繁項集的方式。我覺得兩個演算法的最根本的差異在於apriori是以搜尋項集組合的空間作為基礎,通過資料庫來對照。而fp-growth是以資料庫為基礎,在裡面尋找項集是否頻繁,表現為搜尋方式一個是廣度優先一個是深度優先。

apriori的那剪枝步和統計支援度在fp-growth上就是不斷的建fp-tree和遍歷。而前者的統計需要經過的IO,後者已經壓縮到記憶體了;但fp-growth不是在所有資料集上都比apriori強,比如在稀疏的資料集上,fp-tree每個節點可能包含非常多子孫,因此儲存子孫節點的指標也是很大開銷,fp-tree本來就是通過壓縮使得資料集能被記憶體容納,結果導致最後fp-tree起不到壓縮效果適得其反。優化實現的apriori在稀疏資料集上也往往比fp-growth要快。


這裡fp-growth在大部分地方是完勝了apriori,後面很多改進都是基於深度優先的思想,並且更注重實現上的技巧。現在我們也沒必要去費太多精力去改進這兩個演算法了,因為頻繁項集挖掘是個組合爆炸的時間複雜度。在2003 2004年ICDM舉辦過兩個workshop就是專門比誰實現的頻繁項集挖掘最好(搜"FIMI 03",網站裡有很多的原始碼)。在這裡想多提一點,資料探勘中,沒有演算法能在所有資料集上PK掉其他演算法。因此我們應該瞭解一種任務的多種演算法,看看它們為什麼和如何在不同的資料集上體現出自己的優勢,這樣,通過比較我們不僅能更好的理解和掌握它們的精華,更能在當我們遇到新的資料集的時候,選取合適演算法甚至做出針對性的優化措施。

相關推薦

頻繁挖掘apriorifp-growth

Apriori和fp-growth是頻繁項集(frequent itemset mining)挖掘中的兩個經典演算法,主要的區別在於一個是廣度優先的方式,另一個是深度優先的方式,後一種是基於前一種效率較低的背景下提出來的,雖然都是十幾年前的,但是理解這兩個演算法對資料探勘

頻繁挖掘演算法——Apriori演算法

前言        關聯規則就是在給定訓練項集上頻繁出現的項集與項集之間的一種緊密的聯絡。其中“頻繁”是由人為設定的一個閾值即支援度 (support)來衡量,“緊密”也是由人為設定的一個關聯閾值即置信度(confidence)來衡量的。這兩種度量標準是頻繁項集挖掘中兩個至關

資料探勘演算法AprioriFP-growth

1、基本概念       支援度(support):資料集中包含該項集的記錄所佔比例   置信度或可信度(confidence):主要是針對莫以具體的關聯規則進行定義的,如:{尿布}->{啤酒}的可信度可以被定義為:支援度{尿布、葡萄酒}/支援度{尿布} 2、Apr

海量資料探勘MMDS week2: 頻繁挖掘 Apriori演算法的改進:基於hash的方法

海量資料探勘Mining Massive Datasets(MMDs) -Jure Leskovec courses學習筆記之關聯規則Apriori演算法的改進:基於hash的方法:PCY演算法, Multistage演算法, Multihash演算法 Apriori演

海量資料探勘MMDS week2: 頻繁挖掘 Apriori演算法的改進:非hash方法

海量資料探勘Mining Massive Datasets(MMDs) -Jure Leskovec courses學習筆記之關聯規則Apriori演算法的改進:非hash方法 - 大資料集下的頻繁項集:挖掘隨機取樣演算法、SON演算法、Toivonen演算法 Apri

頻繁挖掘Apriori演算法及其Python實現

Apriori演算法是通過限制候選產生髮現頻繁項集。 Apriori演算法使用一種稱為逐層搜尋的迭代方法,其中k項集用於探索(k+1)項集。首先,通過掃描資料庫,累計每個項的計數,並收集滿足最小支援度的項,找出頻繁1項集的集合,記為L1。然後,使用L1找出頻繁

資料探勘---頻繁挖掘Apriori演算法的C++實現

1 準備 2 作業粗糙翻譯內容 2.1 前言 程式設計作業可能比書面作業花費更多的時間,而這也算是你最後成績的10%,所以請提前開始; 這是個人作業,你可以與你的同學或者老師交流,但是不能夠共享程式碼和抄襲; 類似的庫或頻繁模式挖掘演算

R語言包arules進行頻繁挖掘的最簡單例子

arules是進行頻繁項集挖掘(frequent itemset mining)的有效工具,不過我在使用的時候發現網上很多例子都比較繁瑣,這裡總結一下其中apriori方法的最簡單使用方法,這裡首先給出程式碼:files_change<-read.transaction

海量資料探勘MMDS week2: Association Rules關聯規則與頻繁挖掘

海量資料探勘Mining Massive Datasets(MMDs) -Jure Leskovec courses學習筆記之association rules關聯規則與頻繁項集挖掘 {Frequent Itemsets: Often called "associatio

頻繁挖掘演算法——Eclat演算法

        前面介紹過的Apriori演算法和FP-growth演算法都是從TID項集格式(即{TID:itemset})的事務集中挖掘頻繁模式,其中TID是事務識別符號,而itemset是事務TID中購買的商品。這種資料格式稱為水平資料格式。或者,資料也可以用項-TID

Apriori關聯分析與FP-growth挖掘頻繁

1 問題引入 在去雜貨店買東西的過程,實際上包含了機器學習的應用,這包括物品的展示方式、優惠券等。通過檢視哪些商品經常被一起購買,商店可以瞭解使用者的購買習慣,然後將經常被一起購買的物品擺放在一起,有

手推FP-growth (頻繁模式增長)算法------挖掘頻繁

att 相同 事務 支持 apr 一次 多個 什麽 統計 一.頻繁項集挖掘為什麽會出現FP-growth呢? 原因:這得從Apriori算法的原理說起,Apriori會產生大量候選項集(就是連接後產生的),在剪枝時,需要掃描整個數據庫(就是給出的數據),通過模式匹配檢查候

python關聯分析 __機器學習FP-growth頻繁演算法

FP-growth演算法 專案背景/目的 對於廣告投放而言,好的關聯會一定程度上提高使用者的點選以及後續的諮詢成單 對於產品而言,關聯分析也是提高產品轉化的重要手段,也是大多商家都在做的事情,尤其是電商平臺 曾經我用SPSS Modeler做過Apriori關聯分析模型,也能

機器學習FP-growth頻繁演算法

FP-growth演算法專案背景/目的對於廣告投放而言,好的關聯會一定程度上提高使用者的點選以及後續的諮詢成單 對於產品而言,關聯分析也是提高產品轉化的重要手段,也是大多商家都在做的事情,尤其是電商平臺 曾經我用SPSS Modeler做過Apriori關聯分析模型,也能滿足需求,但是效果自然是不及pyt

機器學習FP-growth頻繁算法

算法 image -o 做的 mine 關聯 RoCE 節點 reat FP-growth算法項目背景/目的對於廣告投放而言,好的關聯會一定程度上提高用戶的點擊以及後續的咨詢成單 對於產品而言,關聯分析也是提高產品轉化的重要手段,也是大多商家都在做的事情,尤其是電商平臺 曾

python關聯分析__機器學習FP-growth頻繁演算法

FP-growth演算法 專案背景/目的 對於廣告投放而言,好的關聯會一定程度上提高使用者的點選以及後續的諮詢成單 對於產品而言,關聯分析也是提高產品轉化的重要手段,也是大多商家都在做的事情,尤其是電商平臺 曾經我用SPSS Modeler做過Apriori關聯

R_Studio(關聯)Apriori演算法尋找頻繁的方法

      使用Apriori演算法尋找頻繁項集        #匯入arules包 install.packages("arules") library ( arules ) setwd('D:\\data') Gary<-

機器學習Apriori演算法FP-growth演算法

1 關聯分析 無監督機器學習方法中的關聯分析問題。關聯分析可以用於回答"哪些商品經常被同時購買?"之類的問題。 2 Apriori演算法   頻繁項集即出現次數多的資料集   支援度就是幾個關聯的資料在資料集中出現的次數佔總資料集的比重。或者說幾個資料關聯出現的概率。   置信度體現了一個數據出現後,另

第12章:使用FP-growth演算法高效發現頻繁

原理:通過構建FP樹,在FP樹中發現頻繁項集。如下圖所示。        由圖可知FP樹包含頭指標,父節點,節點的名字,節點的值,節點連結值(虛線),節點的孩子節點,因此構建類定義樹結構,如下所示: class treeNode: d

第11章:使用Apriori演算法進行關聯分析(從頻繁集中挖掘關聯規則)

原理: 根據頻繁項集找關聯規則,如有一個頻繁項集{豆奶,萵苣},那麼可能有一條關聯規則是豆奶->萵苣,即一個人購買了豆奶,則大可能他會購買萵苣,但反過來一個人購買了萵苣,不一定他會購買豆奶,頻繁項集使用支援度量化,關聯規則使用可信度或置信度量化。一條規則P->H的可信度定義為支援