Apriori 關聯分析算法原理分析與代碼實現

前言算法

  想必你們都聽過數據挖掘領域那個經典的故事 - "啤酒與尿布" 的故事。網絡

  那麼,具體是怎麼從海量銷售信息中挖掘出啤酒和尿布之間的關係呢?app

  這就是關聯分析所要完成的任務了。框架

  本文將講解關聯分析領域中最爲經典的Apriori算法,並給出具體的代碼實現。函數

關聯分析領域的一些概念學習

  1. 頻繁項集: 數據集中常常出如今一塊兒的物品的集合。例如 "啤酒和尿布"測試

  2. 關聯規則: 指兩個物品集之間可能存在很強的關係。例如 "{啤酒} -> {尿布}" 就是一條關聯規則。網站

  3. 支持度: 數據集中,出現了某個物品集的數據項佔總數據項的比重。spa

  4. 可信度: 這個概念是針對某條關聯規則而定的。它是指兩個物品集的支持度和其中某個物品集的支持度之比,如 "支持度{啤酒,尿布} / 支持度{尿布}"。code

  所以,用這些屬於來解釋啤酒與尿布的故事,那就是:{啤酒,尿布}是一個頻繁項集;"{啤酒} -> {尿布}" 就是一條關聯規則;顧客買尿布的同時買啤酒的可能性爲 "支持度{啤酒,尿布} / 支持度{尿布}"。

  那麼對海量的數據,假如要獲得支持度大於0.8的全部頻繁項集,該怎麼作?

  若是用蠻力法一個個統計,是根本不現實的,那樣計算量實在太大。

  本文將要介紹的Apriori關聯分析算法意義就在於可以大幅度減小這種狀況的計算量,並從頻繁項集中高效檢索出關聯規則,從而大大減小關聯規則學習所須要消耗的計算量。

Apriori算法基本原理

  若是{0,1}是頻繁項集,那麼{0}和{1}也都是頻繁項集。

  這顯然是正確的命題。

  其逆否命題 - 」若是{0}和{1}不都是頻繁項集,那麼{0,1}不是頻繁項集" 天然也是正確的。-> 這就是 Apriori 算法的核心思想之一。

  這樣,一旦發現某個集合不是頻繁項集,那麼它的全部超集也都不是頻繁項集,就不用浪費功夫去對它們進行檢索了。

  檢索出頻繁項集以後,接下來檢索出全部合乎要求的關聯規則。

  若是某條規則不知足最小可信度要求,那麼該規則的全部子集也不會知足。 -> 這是 Apriori 算法的核心思想的另外一部分。

  PS:這裏務必思考清楚規則是怎麼劃分的,什麼叫某個規則的子集。

  這樣,和上一步同理,也能高效的從頻繁項集中檢索出關聯規則了。

  具體實現將分爲頻繁集檢索關聯規則學習兩個部分進行講解。

頻繁項集檢索實現思路與實現代碼

  一種經典的實現方法是 "分級法":

  算法框架是在兩個大的步驟 - 篩選/過濾之間不斷迭代,直到全部狀況分析完畢。

  每次篩選的結果都要指定元素個數的狀況,所以所謂分級,也就是依次討論指定元素個數狀況的項集。

  在篩選以後,就是過濾。

  過濾有兩層意義,一個是項集必須在數據集中存在。這是第一層過濾;還有一層過濾,是指支持度過濾。只有知足支持度要求的項集才能保存下來。

  過濾以後,基於過濾集再進行篩選,每次篩選的元素個數都比上一次篩選的元素個數多一個。

  而後繼續過濾。如此反覆,直到最後一次篩選過濾完成。

  僞代碼實現:

當集合中項的個數大於0時:
    構建一個 k 個項組成的候選項集的列表
    檢查數據以確認每一個項集都是頻繁的
    保留頻繁項集並構建 k+1 項組成的候選項集列表

  其中檢查每一個項集是否頻繁部分的僞代碼:

對數據集中的每條交易記錄:
    對每一個候選集元素:
        檢查是否爲數據集元素,是才保留。
對每一個數據集
    若是支持度達到要求才保留
返回過濾後的頻繁項集 - 也即過濾集

  Python實現及測試代碼:

  1 def loadDataSet():
  2     '返回測試數據'
  3     
  4     return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
  5 
  6 #===================================
  7 # 輸入:
  8 #        dataSet: 數據集
  9 # 輸出:
 10 #        map(frozenset, C1): 候選集
 11 #===================================
 12 def createC1(dataSet):
 13     '建立候選集'
 14     
 15     C1 = []
 16     for transaction in dataSet:
 17         for item in transaction:
 18             if not [item] in C1:
 19                 C1.append([item])
 20                 
 21     C1.sort()
 22     
 23     # 返回的集合元素都是frozenset類型 -> 由於之後要用來作鍵。
 24     return map(frozenset, C1)
 25 
 26 #=============================================
 27 # 輸入:
 28 #        D: 數據集 (set格式)
 29 #        Ck: 候選集
 30 #        minSupport: 最小支持度
 31 # 輸出:
 32 #        retList: 過濾集
 33 #        supportData: 支持集(挖掘關聯規則時使用)
 34 #=============================================
 35 def scanD(D, Ck, minSupport):
 36     '由候選集獲得過濾集'
 37     
 38     # 統計候選元素出現的次數
 39     ssCnt = {}
 40     for tid in D:
 41         for can in Ck:
 42             if can.issubset(tid):
 43                 if not ssCnt.has_key(can): ssCnt[can]=1
 44                 else: ssCnt[can] += 1
 45                 
 46     # 構建過濾集和支持集
 47     numItems = float(len(D))
 48     retList = []
 49     supportData = {}
 50     for key in ssCnt:
 51         support = ssCnt[key]/numItems
 52         if support >= minSupport:
 53             retList.insert(0,key)
 54         supportData[key] = support
 55         
 56     return retList, supportData
 57 
 58 #===================================
 59 # 輸入:
 60 #        Lk: 過濾集
 61 #        k: 當前項集元素個數
 62 # 輸出:
 63 #        retList: 候選集
 64 #===================================
 65 def aprioriGen(Lk, k):
 66     '由過濾集獲得候選集'
 67     
 68     # 重組過濾集,獲得新的候選集。
 69     retList = []
 70     lenLk = len(Lk)
 71     for i in range(lenLk):
 72         for j in range(i+1, lenLk): 
 73             # 留意下重組技巧
 74             L1 = list(Lk[i])[:k-2]; L2 = list(Lk[j])[:k-2]
 75             L1.sort(); 
 76             L2.sort()
 77             if L1==L2:
 78                 retList.append(Lk[i] | Lk[j])
 79                 
 80     return retList
 81 
 82 #=============================================
 83 # 輸入:
 84 #        dataSet: 數據集
 85 #        minSupport: 最小支持度
 86 # 輸出:
 87 #        L: 頻繁集
 88 #        supportData: 支持集(挖掘關聯規則時使用)
 89 #=============================================
 90 def apriori(dataSet, minSupport = 0.5):
 91     '求頻繁項集及其對應支持度'
 92     
 93     C1 = createC1(dataSet)
 94     D = map(set, dataSet)
 95     L1, supportData = scanD(D, C1, minSupport)
 96     L = [L1]
 97     k = 2
 98     while (len(L[k-2]) > 0):
 99         Ck = aprioriGen(L[k-2], k)
100         Lk, supK = scanD(D, Ck, minSupport)
101         supportData.update(supK)
102         L.append(Lk)
103         k += 1
104         
105     return L, supportData
106     
107 def main():
108     'Apriori頻繁集檢索'
109     
110     L, s = apriori (loadDataSet())
111     
112     print L
113     print s

  測試結果:

  

關聯規則學習實現思路與實現代碼

  上一部分的工做是從數據集中檢索出頻繁集;而這一部分是根據頻繁集學習關聯規則。

  上一部分的工做是經過篩選集中的元素個數進行分級;而這一部分是針對規則右部的元素個數進行分級。

  另外還要注意,只用檢索單個頻繁集以內的關聯規則就能夠了。

  實現代碼:

 1 #===================================
 2 # 輸入:
 3 #        L: 頻繁集
 4 #        supportData: 支持集
 5 #        minConf: 最小可信度
 6 # 輸出:
 7 #        bigRuleList: 規則集
 8 #===================================
 9 def generateRules(L, supportData, minConf=0.7):
10     '從某個頻繁集中學習關聯規則'
11     
12     bigRuleList = []
13     for i in range(1, len(L)):
14         for freqSet in L[i]:
15             H1 = [frozenset([item]) for item in freqSet]
16             if (i > 1):
17                 rulesFromConseq(freqSet, H1, supportData, bigRuleList, minConf)
18             else:
19                 calcConf(freqSet, H1, supportData, bigRuleList, minConf)
20     return bigRuleList         
21 
22 #===================================
23 # 輸入:
24 #        L: 頻繁集
25 #        supportData: 支持集
26 #        minConf: 最小可信度
27 # 輸出:
28 #        bigRuleList: 規則集
29 #===================================
30 def calcConf(freqSet, H, supportData, brl, minConf=0.7):
31     '可信度過濾'
32     
33     prunedH = []
34     for conseq in H:
35         conf = supportData[freqSet]/supportData[freqSet-conseq]
36         if conf >= minConf: 
37             brl.append((freqSet-conseq, conseq, conf))
38             prunedH.append(conseq)
39             
40     return prunedH
41 
42 def rulesFromConseq(freqSet, H, supportData, brl, minConf=0.7):
43     '從某個頻繁項集中學習關聯規則'
44     
45     # 本次學習的規則右部中的元素個數
46     m = len(H[0])
47     if (len(freqSet) > (m + 1)):
48         # 重組規則右部
49         Hmp1 = aprioriGen(H, m+1)
50         # 規則學習
51         Hmp1 = calcConf(freqSet, Hmp1, supportData, brl, minConf)
52         if (len(Hmp1) > 1):
53             # 遞歸學習函數
54             rulesFromConseq(freqSet, Hmp1, supportData, brl, minConf)
55               
56 def main():
57     '關聯規則學習'
58     
59     L, s = apriori (loadDataSet())
60     
61     rules = generateRules(L, s)
62     print rules

  測試結果:

  

  測試數據爲: [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]

  結果的意思也就是說:1->3,5->2,2->5 的機率爲 1。

  顯然這是和預計相吻合的。

小結

  1. Apriori關聯算法在網絡購物網站中用的很是多,能夠基於此算法搭建商品推薦系統。

  2. 但Apriori算法也有一個缺點,那就是頻繁集的檢索速度仍是不夠快,由於每級都要從新檢索一遍候選集(雖然候選集愈來愈小)。

  3. 針對 2 中的問題,下篇文章將介紹一個更爲強大的發現頻繁集的算法 - FP-growth。(但它不能用來發現關聯規則)

相關文章
相關標籤/搜索