1. 程式人生 > >推薦演算法-關聯分析(關聯規則)

推薦演算法-關聯分析(關聯規則)

關聯分析又稱關聯挖掘,就是在交易資料、關係資料或其他資訊載體中,查詢存在於專案集合或物件集合之間的頻繁模式、關聯、相關性或因果結構。

或者說,關聯分析是發現交易資料庫中不同商品(項)之間的聯絡。

關聯分析是一種簡單、實用的分析技術,就是發現存在於大量資料集中的關聯性或相關性,從而描述了一個事物中某些屬性同時出現的規律和模式。

關聯分析是從大量資料中發現項集之間有趣的關聯和相關聯絡。關聯分析的一個典型例子是購物籃分析。該過程通過發現顧客放人其購物籃中的不同商品之間的聯絡,分析顧客的購買習慣。通過了解哪些商品頻繁地被顧客同時購買,這種關聯的發現可以幫助零售商制定營銷策略。其他的應用還包括價目表設計、商品促銷、商品的排放和基於購買模式的顧客劃分。

可從資料庫中關聯分析出形如“由於某些事件的發生而引起另外一些事件的發生”之類的規則。如“67%的顧客在購買啤酒的同時也會購買尿布”,因此通過合理的啤酒和尿布的貨架擺放或捆綁銷售可提高超市的服務質量和效益。又如“C語言課程優秀的同學,在學習‘資料結構’時為優秀的可能性達88%”,那麼就可以通過強化“C語言”的學習來提高教學效果。

何為關聯分析

定義:
1、事務:每一條交易稱為一個事務,例如示例1中的資料集就包含四個事務。
2、項:交易的每一個物品稱為一個項,例如Cola、Egg等。 
3、項集:包含零個或多個項的集合叫做項集,例如{Cola, Egg, Ham}。
4、k−項集:包含k個項的項集叫做k-項集,例如{Cola}叫做1-項集,{Cola, Egg}叫做2-項集。
5、支援度計數:一個項集出現在幾個事務當中,它的支援度計數就是幾。例如{Diaper, Beer}出現在事務 002、003和004中,所以它的支援度計數是3。
6、支援度:支援度計數除於總的事務數。例如上例中總的事務數為4,{Diaper, Beer}的支援度計數為3,所以它的支援度是3÷4=75%,說明有75%的人同時買了Diaper和Beer。
關聯規則A->B的支援度support=P(AB),指的是事件A和事件B同時發生的概率。
7、頻繁項集:支援度大於或等於某個閾值的項集就叫做頻繁項集。例如閾值設為50%時,因為{Diaper, Beer}的支援度是75%,所以它是頻繁項集。
8、前件和後件:對於規則{Diaper}→{Beer},{Diaper}叫做前件,{Beer}叫做後件。
9、置信度:對於規則{Diaper}→{Beer},{Diaper, Beer}的支援度計數除於{Diaper}的支援度計數,為這個規則的置信度。例如規則{Diaper}→{Beer}的置信度為3÷3=100%。說明買了Diaper的人100%也買了Beer。
置信度confidence=P(B|A)=P(AB)/P(A),指的是發生事件A的基礎上發生事件B的概率。
10、強關聯規則:大於或等於最小支援度閾值和最小置信度閾值的規則叫做強關聯規則。

關聯分析的最終目標就是要找出強關聯規則。

1.Apriori演算法

電子商務中常用的一種資料探勘方法就是從使用者交易資料集中尋找商品之間的關聯規則。關聯規則中常用的一種演算法是Apriori演算法。該演算法主要包含兩個步驟:首先找出資料集中所有的頻繁項集,這些項集出現的頻繁性要大於或等於最小支援度;然後根據頻繁項集產生強關聯規則,這些規則必須滿足最小支援度和最小置信度。
上面提到了最小支援度和最小置信度,事實上,在關聯規則中用於度量規則質量的兩個主要指標即為支援度和置信度。那麼,什麼是支援度和置信度呢?接下來進行講解。
給定關聯規則X=>Y,即根據X推出Y。形式化定義為:

定義

演算法步驟:

1.找出出現頻率最大的一個項L1。
2.根據L1找頻繁“2項集”的集合C2.
3.並剪掉不滿足支援度閾值的項,得到L2。
4.根據L2找頻繁“3項集”的集合C3。
假設D表示交易資料集;K為項集,即包含k個項的集合;Lk表示滿足最小支援度的k項集;Ck表示候選k項集。Apriori演算法的參考文獻描述如下。在該演算法中,候選集的計算過程如下所示:

候選集的計算過程

例如: L2 = {{A,C},{B,C},{B,E}{C,E}}
那麼 C3= {{A,B,C},{A,C,E},{B,C,E}}
5.根據性質和支援度閾值進行剪枝,得到L3。
Apriori性質:一個頻繁項集的任一子集也應該是頻繁項集。也就是,生成一個k-itemset的候選項時,如果這個候選項有子集不在(k-1)-itemset(已經確定是frequent的)中時,那麼這個候選項就不用拿去和支援度判斷了,直接刪除。

Apriori性質

6.迴圈上述過程,直到得到空集C,即直到不能發現更大的頻集L。
7.計算最大頻集L的非空子集,兩兩計算置信度,得到大於置信度閾值的強關聯規則。

舉個栗子

假設給定如下電子商務網站的使用者交易資料集,其中,定義最小支援度為2/9,即支援度計數為2,最小置信度為70%,現在要計算該資料集的關聯規則,如圖所示。

使用者交易資料集

步驟1,根據Apriori演算法計算頻繁項集。
1)計算頻繁1項集。掃描交易資料集,統計每種商品出現的次數,選取大於或等於最小支援度的商品,得到了候選項集。

頻繁1項集

2)根據頻繁1項集,計算頻繁2項集。首先將頻繁1項集和頻繁1項集進行連線運算,得到2項集,如下所示:

2項集

掃描使用者交易資料集,計算包含每個候選2項集的記錄數。

候選2項集

根據最小支援度,得到頻繁2項集。

頻繁2項集

3)根據頻繁2項集,計算頻繁3項集。首先將頻繁2項集進行連線,得到{{I1,I2,I3},{I1,I2,I5},{I1,I3,I5},{I2,I3,I4},{I2,I3,I5},{I2,I4,I5}},然後根據頻繁項集性質進行剪枝(第一種剪枝),即頻繁項集的非空子集必須是頻繁的
{I1,I2,I3}的2項子集為{I1,I2},{I1,I3},{I2,I3},都在頻繁2項集中,則保留;
{I1,I2,I5}的2項子集為{I1,I2},{I1,I5},{I2,I5},都在頻繁2項集中,則保留;
{I1,I3,I5}的2項子集為{I1,I3},{I1,I5},{I3,I5},由於{I3,I5}不是頻繁2項集,移除該候選集;
{I2,I3,I4}的2項子集為{I2,I3},{I2,I4},{I3,I4},由於{I3,I4}不是頻繁2項集,移除該候選集;
{I2,I3,I5}的2項子集為{I2,I3},{I2,I5},{I3,I5},由於{I3,I5}不是頻繁2項集,移除該候選集;
{I2,I4,I5}的2項子集為{I2,I4},{I2,I5},{I4,I5},由於{I4,I5}不是頻繁2項集,移除該候選集。通過剪枝,得到候選集{{I1,I2,I3},{I1,I2,I5}},掃描交易資料庫,計算包含候選3項集的記錄數(第二種閾值剪枝)

頻繁3項集

4)根據頻繁3項集,計算頻繁4項集。重複上述的思路,得到{I1,I2,I3,I5},根據頻繁項集定理,它的子集{I2,I3,I5}為非頻繁項集,所以移除該候選集。從而,頻繁4項集為空,至此,計算頻繁項集的步驟結束。

步驟2,根據頻繁項集,計算關聯規則。
這裡以頻繁3項集{I1,I2,I5}為例,計算關聯規則。{I1,I2,I5}的非空子集為{I1,I2}、{I1,I5}、{I2,I5}、{I1}、{I2}和{I5}。

規則1,{I1,I2}=>{I5},置信度為{I1,I2,I5}的支援度除以{I1,I2}的支援度,即2/4=50%,因其小於最小置信度,所以刪除該規則。
同理,最後可以得到{I1,I5}=>{I2},{I2,I5}=>{I1}和{I5}=>{I1,I2}為3條強關聯規則。

缺點

(1)在每一步產生侯選專案集時迴圈產生的組合過多,沒有排除不應該參與組合的元素;

(2)每次計算項集的支援度時,都對資料庫D中的全部記錄進行了一遍掃描比較,如果是一個大型的資料庫的話,這種掃描比較會大大增加計算機系統的I/O開銷。而這種代價是隨著資料庫的記錄的增加呈現出幾何級數的增加。因此人們開始尋求更好效能的演算法。

改進

1)基於劃分的方法。該演算法先把資料庫從邏輯上分成幾個互不相交的塊,每次單獨考慮一個分塊並對它生成所有的頻繁項集,然後把產生的頻繁項集合並,用來生成所有可能的頻繁項集,最後計算這些項集的支援度。這裡分塊的大小選擇要使得每個分塊可以被放入主存,每個階段只需被掃描一次。而演算法的正確性是由每一個可能的頻繁項集至少在某一個分塊中是頻繁項集保證的。
上面所討論的演算法是可以高度並行的。可以把每一分塊分別分配給某一個處理器生成頻繁項集。產生頻繁項集的每一個迴圈結束後.處理器之間進行通訊來產生全域性的候選是一項集。通常這裡的通訊過程是演算法執行時間的主要瓶頸。而另一方面,每個獨立的處理器生成頻繁項集的時間也是一個瓶頸。其他的方法還有在多處理器之間共享一個雜湊樹來產生頻繁項集,更多關於生成頻繁項集的並行化方法可以在其中找到。
2)基於Hash的方法。Park等人提出了一個高效地產生頻繁項集的基於雜湊(Hash)的演算法。通過實驗可以發現,尋找頻繁項集的主要計算是在生成頻繁2—項集Lk
上,Park等就是利用這個性質引入雜湊技術來改進產生頻繁2—項集的方法。
3)基於取樣的方法。基於前一遍掃描得到的資訊,對它詳細地做組合分析,可以得到一個改進的演算法,其基本思想是:先使用從資料庫中抽取出來的取樣得到一些在整個資料庫中可能成立的規則,然後對資料庫的剩餘部分驗證這個結果。這個演算法相當簡單並顯著地減少了FO代價,但是一個很大的缺點就是產生的結果不精確,即存在所謂的資料扭曲(Dataskew)。分佈在同一頁面上的資料時常是高度相關的,不能表示整個資料庫中模式的分佈,由此而導致的是取樣5%的交易資料所花費的代價同掃描一遍資料庫相近。
4)減少交易個數。減少用於未來掃描事務集的大小,基本原理就是當一個事務不包含長度為志的大項集時,則必然不包含長度為走k+1的大項集。從而可以將這些事務刪除,在下一遍掃描中就可以減少要進行掃描的事務集的個數。這就是AprioriTid的基本思想。

2.FP-growth演算法

由於Apriori方法的固有缺陷.即使進行了優化,其效率也仍然不能令人滿意。2000年,Han Jiawei等人提出了基於頻繁模式樹(Frequent Pattern Tree,簡稱為FP-tree)的發現頻繁模式的演算法FP-growth。在FP-growth演算法中,通過兩次掃描事務資料庫,把每個事務所包含的頻繁專案按其支援度降序壓縮儲存到FP—tree中。在以後發現頻繁模式的過程中,不需要再掃描事務資料庫,而僅在FP-Tree中進行查詢即可,並通過遞迴呼叫FP-growth的方法來直接產生頻繁模式,因此在整個發現過程中也不需產生候選模式。該演算法克服了Apriori演算法中存在的問顥.在執行效率上也明顯好於Apriori演算法。

構造FP-Tree

挖掘頻繁模式前首先要構造FP-Tree,演算法偽碼如下:
輸入:一個交易資料庫DB和一個最小支援度threshold.
輸出:它的FP-tree.
步驟:
1.掃描資料庫DB一遍.得到頻繁項的集合F和每個頻繁項的支援度.把F按支援度遞降排序,結果記為L.
2.建立FP-tree的根節點,記為T,並且標記為’null’.然後對DB中的每個事務Trans做如下的步驟.
根據L中的順序,選出並排序Trans中的事務項.把Trans中排好序的事務項列表記為[p|P],其中p是第一個元素,P是列表的剩餘部分.呼叫insert_tree([p|P],T).
函式insert_tree([p|P],T)的執行如下.
如果T有一個子結點N,其中N.item-name=p.item-name,則將N的count域值增加1;否則,建立一個新節點N,使它的count為1,使它的父節點為T,並且使它的node_link和那些具有相同item_name域串起來.如果P非空,則遞迴呼叫insert_tree(P,N).

挖掘頻繁模式

FP-Tree進行挖掘,演算法如下:
輸入:一棵用演算法一建立的樹Tree
輸出:所有的頻繁集
步驟:
呼叫FP-growth(Tree,null).
procedure FP-Growth ( Tree, x)
{
(1)if (Tree只包含單路徑P) then
(2) 對路徑P中節點的每個組合(記為B)
(3) 生成模式B並x,支援數=B中所有節點的最小支援度
(4) else 對Tree頭上的每個ai,do
{
(5) 生成模式B= ai 並 x,支援度=ai.support;
(6) 構造B的條件模式庫和B的條件FP樹TreeB;
(7)if TreeB != 空集
(8)**then **call FP-Growth ( TreeB , B )
}
}

舉個栗子

構建FP-tree
  FP-growth演算法通過構建FP-tree來壓縮事務資料庫中的資訊,從而更加有效地產生頻繁項集。FP-tree其實是一棵字首樹,按支援度降序排列,支援度越高的頻繁項離根節點越近,從而使得更多的頻繁項可以共享字首。

根據上面的例子,構建FP-tree。

頻數

得到新的順序:

使用者交易排序資料集

FP-tree的根節點為null,不表示任何項。接下來,對事務型資料庫進行第二次掃描,從而開始構建FP-tree:
  第一條記錄<I2,I1,I5>對應於FP-tree中的第一條分支<(I2:1),(I1:1),(I5:1)>:

第一條記錄

由於第二條記錄<I2,I4>與第一條記錄有相同的字首<I2>,因此<I2>的支援度加一,同時在(I2:2)節點下新增節點(I4:1)。所以,FP-tree中的第二條分支是<(I2:2),(I4:1)>:

第二條記錄

第三條記錄<I2,I3>與前兩條記錄相比,只有一個共同字首<I2>,因此,只需要在(I2:3)下新增節點<I3:1>:

第三條記錄

第四條記錄<I2,I1,I4>與之前所有記錄共同字首<I2,I1>,因此在<I2,I1>節點下新增節點<I4>:

第四條記錄

類似地,將第五條記錄<I1,I3>作為FP-tree的一個分支,更新相關節點的支援度:

第五條記錄

以此類推的到最後的樹:

FP-tree

綜上,FP-tree的節點可以定義為:

class TreeNode { private: String name; // 節點名稱 int count; // 支援度計數 TreeNode *parent; // 父節點 Vector<TreeNode *> children; // 子節點 TreeNode *nextHomonym; // 指向同名節點 ... }

從FP-tree中挖掘頻繁模式(Frequent Patterns)
  我們從頭表的底部開始挖掘FP-tree中的頻繁模式。在FP-tree中以I5結尾的節點鏈共有兩條,分別是<(I2:7),(I1:4),(I3:2),(I5:1)>和<(I2:7),(I1:4),(I5:1)>。

其中,第一條節點連結串列表示客戶購買的物品清單<I2,I1,I3,I5>在資料庫中共出現了1次。需要注意到是,儘管<I2,I4>在第一條節點鏈中出現了4次,單個物品<I2>出現了7次,但是它們與I5一起出現只有1次,所以在條件FP-tree中將<(I2:7),(I1:4),(I3:2),(I5:1)>記為<(I2:1),(I1:1),(I3:1),(I5:1)>。

同理,第二條節點連結串列示客戶購買的物品清單<(I2:7),(I1:4),(I5:1)>在資料庫中只出現了一次。

我們將p的字首節點鏈<(I2:1),(I1:1),(I3:1),(I5:1)>和<(I2:1),(I1:1),(I5:1)>稱為I5的條件模式基(conditional pattern base)

我們將I5的條件模式基作為新的事務資料庫,每一行儲存p的一個字首節點鏈,根據第二節中構建FP-tree的過程,計算每一行記錄中各種物品的支援度,然後按照支援度降序排列,僅保留頻繁項集,剔除那些低於支援度閾值的項,建立一棵新的FP-tree,這棵樹被稱之為I5的條件FP-tree:

I5的條件FP-tree

從圖可以看到I5的條件FP-tree中滿足支援度閾值的剩下2個節點,所以以I5結尾的頻繁項集有(I5:2),(I1,I5 :2),(I2,I5 :2),(I1,I2,I5 :2)。

同理可得I3的條件FP-tree:

I3的條件FP-tree

得到以I3結尾的頻繁項集有(I3:4),(I1,I3 :4),(I2,I3 :4),(I1,I2,I3 :2)。

於是,以I4結尾的頻繁項集有(I4:2),(I2,I4 :2),以I2結尾的頻繁項集有(I2:7),以I1結尾的頻繁項集有(I1:6),(I2,I1 :4)。

最後計算關聯。