機器學習系列文章:Apriori關聯規則分析演算法原理分析與程式碼實現

經年不往發表於2018-09-22

1.關聯規則淺談

    關聯規則(Association Rules)是反映一個事物與其他事物之間的相互依存性和關聯性,如果兩個或多個事物之間存在一定的關聯關係,那麼,其中一個事物就能通過其他事物預測到。關聯規則是資料探勘的一個重要技術,用於從大量資料中挖掘出有價值的資料項之間的相關關係。
        關聯規則首先被Agrawal, lmielinski and Swami在1993年的SIGMOD會議上提出。
        關聯規則挖掘的最經典的例子就是沃爾瑪的啤酒與尿布的故事,通過對超市購物籃資料進行分析,即顧客放入購物籃中不同商品之間的關係來分析顧客的購物習慣,發現美國婦女們經常會叮囑丈夫下班後為孩子買尿布,30%-40%的丈夫同時會順便購買喜愛的啤酒,超市就把尿布和啤酒放在一起銷售增加銷售額。有了這個發現後,超市調整了貨架的設定,把尿布和啤酒擺放在一起銷售,從而大大增加了銷售額。

2.常見案例

 
        前面講述了關聯規則挖掘對超市購物籃的例子,使用Apriori對資料進行頻繁項集挖掘與關聯規則的產生是一個非常有用的技術,其中我們眾所周知的例子如:
        (1) 沃爾瑪超市的尿布與啤酒
        (2) 超市的牛奶與麵包
        (3) 百度文庫推薦相關文件
        (4) 淘寶推薦相關書籍
        (5) 醫療推薦可能的治療組合
        (6) 銀行推薦相關聯業務
        這些都是商務智慧和關聯規則在實際生活中的運用

3.關聯規則的3個度量

    支援度(support):說明規則的統計顯著性

                    

    置信度(confidence):說明規則的強度(最小和最大置信度有公司設定)

                

    還有其他的度量標準,比如:提升度/興趣度(interest),但是前面提出的這兩個較為常用!

 

4. Apriori演算法簡介

    我們的目標是找出具有足夠高的支援度和置信度的所有規則,並且由於銷售資料庫一般非常大,所有我們希望通過少數幾遍資料庫掃描就找出它們。所以這裡就提出了一個有效演算法,稱為Apriori演算法(Agrawal等1996)來做這項工作。Apriori演算法是一種對有影響的挖掘布林關聯規則頻繁項集的演算法,通過演算法的連線和剪枝即可挖掘頻繁項集。

該演算法分為兩步:

            (1)找出頻繁項集,即找出具有足夠支援度的項集;

    這裡補充 頻繁項集的概念:

        頻繁項集:如果項集的出現頻率大於或等於最小支援度計數閾值,則稱它為頻繁項集,其中頻繁K-項集的集合通常記作Lk

下圖詳細描述了找出頻繁項集的過程:
 

            

具體分析結果:
        第一次掃描:對每個候選商品計數得C1,由於候選{D}支援度計數為1<最小支援度計數2,故刪除{D}得頻繁1-項集合L1;
        第二次掃描:由L1產生候選C2並對候選計數得C2,比較候選支援度計數與最小支援度計數2得頻繁2-項集合L2;
        第三次掃描:用Apriori演算法對L2進行連線和剪枝產生候選3項集合C3的過程如下:
        1.連線:
        C3=L2(連線)L2={{A,C},{B,C},{B,E},{C,E}}{{A,C},{B,C},{B,E},{C,E}}={{A,B,C},{A,C,E},{B,C,E}}
        2.剪枝:
        {A,B,C}的2項子集{A,B},{A,C}和{B,C},其中{A,B}不是2項子集L2,因此不是頻繁的,從C3中刪除;
        {A,C,E}的2項子集{A,C},{A,E}和{C,E},其中{A,E}不是2項子集L2,因此不是頻繁的,從C3中刪除;
        {B,C,E}的2項子集{B,C},{B,E}和{C,E},它的所有2項子集都是L2的元素,保留C3中。
        經過Apriori演算法對L2連線和剪枝後產生候選3項集的集合為C3={B,C,E}. 在對該候選商品計數,由於等於最小支援度計數2,故得頻繁3-項集合L3,同時由於4-項集中僅1個,故C4為空集,演算法終止。   
      

 

      (2)通過把頻繁項集劃分成兩個子集,分別作為前件和後件,把頻繁項集轉換成具有足夠置信度的規則;

        強關聯規:如果規則R:X=>Y滿足support(X=>Y)>=supmin(最小支援度,它用於衡量規則需要滿足的最低重要性)且confidence(X=>Y)>=confmin(最小置信度,它表示關聯規則需要滿足的最低可靠性)稱關聯規則X=>Y為強關聯規則,否則稱關聯規則X=>Y為弱關聯規則。
        例子:現有A、B、C、D、E五種商品的交易記錄表,找出所有頻繁項集,假設最小支援度>=50%,最小置信度>=50%。
        對於關聯規則R:A=>B,則:
        支援度(suppport):是交易集中同時包含A和B的交易數與所有交易數之比。
                            Support(A=>B)=P(A∪B)=count(A∪B)/|D|
        置信度(confidence):是包含A和B交易數與包含A的交易數之比。
                            Confidence(A=>B)=P(B|A)=support(A∪B)/support(A)

                        


        計算過程如下,K=1的時候項集{A}在T1、T3中出現2次,共4條交易,故支援度為2/4=50%,依次計算。其中項集{D}在T1出現,其支援度為1/4=25%,小於最小支援度50%,故去除,得到L1。
        然後對L1中項集兩兩組合,再分別計算其支援度,其中項集{A, B}在T3中出現1次,其支援度=1/4=25%,小於最小支援度50%,故去除,同理得到L2項集。
 

                    



        然後如下圖所示,對L2中的項集進行組合,其中超過三項的進行過濾,最後計算得到L3項集{B,C,E}。
 

                    


        最後對計算置信度,如下圖所示。
 

                       

 

         Apriori演算法弊端:需要多次掃描資料表。如果頻繁集最多包含10個項,那麼就需要掃描交易資料表10遍,這需要很大的I/O負載。同時,產生大量頻繁集,若有100個專案,可能產生候選項數目。

                            

        故:Jiawei Han等人在2000年提出了一種基於FP-樹的關聯規則挖掘演算法FP_growth,它採取“分而治之”的策略,將提供頻繁專案集的資料庫壓縮成一棵頻繁模式樹(FP-樹)。
        推薦一張圖,詳細分析關聯規則的過程:
 

                



        原文作者參考文獻:
        [1]高明 . 關聯規則挖掘演算法的研究及其應用[D].山東師範大學. 2006
        [2]李彥偉 . 基於關聯規則的資料探勘方法研究[D].江南大學. 2011
        [3]肖勁橙,林子禹,毛超.關聯規則在零售商業的應用[J].計算機工程.2004,30(3):189-190.
        [4]秦亮曦,史忠植.關聯規則研究綜述[J].廣西大學學報.2005,30(4):310-317.
        [5]陳志泊,韓慧,王建新,孫俏,聶耿青.資料倉儲與資料探勘[M].北京:清華大學出版社.2009.
        [6]沈良忠.關聯規則中Apriori 演算法的C#實現研究[J].電腦知識與技術.2009,5(13):3501-3504.
        [7]趙衛東.商務智慧(第二版)[M].北京:清華大學出版社.2011.

 

5. Apriori演算法程式碼實現(暫時使用引用地址處的程式碼,後期會更新個人書寫程式碼)

# -*- coding: utf-8 -*-  
""" 
Created on Mon Nov 28 03:29:51 2016 
 
地址:http://blog.csdn.net/u010454729/article/details/49078505 
 
@author: 參考CSDN u010454729  
"""  
  
# coding=utf-8    
def  loadDataSet():    
    return [[1,3,4],[2,3,5],[1,2,3,5],[2,5]]    
    
def createC1(dataSet):                  #構建所有候選項集的集合    
    C1 = []    
    for transaction in dataSet:    
        for item in transaction:    
            if not [item] in C1:    
                C1.append([item])       #C1新增的是列表,對於每一項進行新增,{1},{3},{4},{2},{5}    
    C1.sort()    
    return map(frozenset, C1)           #使用frozenset,被“冰凍”的集合,為後續建立字典key-value使用。    
    
def scanD(D,Ck,minSupport):             #由候選項集生成符合最小支援度的項集L。引數分別為資料集、候選項集列表,最小支援度    
    ssCnt = {}    
    for tid in D:                       #對於資料集裡的每一條記錄    
        for can in Ck:                  #每個候選項集can    
            if can.issubset(tid):       #若是候選集can是作為記錄的子集,那麼其值+1,對其計數    
                if not ssCnt.has_key(can):#ssCnt[can] = ssCnt.get(can,0)+1一句可破,沒有的時候為0,加上1,有的時候用get取出,加1    
                    ssCnt[can] = 1    
                else:    
                    ssCnt[can] +=1    
    numItems = float(len(D))      
    retList  = []    
    supportData = {}    
    for key in ssCnt:    
        support = ssCnt[key]/numItems   #除以總的記錄條數,即為其支援度    
        if support >= minSupport:    
            retList.insert(0,key)       #超過最小支援度的項集,將其記錄下來。    
        supportData[key] = support    
    return retList, supportData    
    
def aprioriGen(Lk, k):                  #建立符合置信度的項集Ck,    
    retList = []    
    lenLk   = len(Lk)    
    for i in range(lenLk):    
        for j in range(i+1, lenLk):     #k=3時,[:k-2]即取[0],對{0,1},{0,2},{1,2}這三個項集來說,L1=0,L2=0,將其合併得{0,1,2},當L1=0,L2=1不新增,    
            L1 = list(Lk[i])[:k-2]    
            L2 = list(Lk[j])[:k-2]    
            L1.sort()    
            L2.sort()    
            if L1==L2:    
                retList.append(Lk[i]|Lk[j])    
    return retList    
    
def apriori(dataSet, minSupport = 0.5):    
    C1 = createC1(dataSet)    
    D  = map(set,dataSet)    
    L1, supportData = scanD(D,C1,minSupport)    
    L  = [L1]                           #L將包含滿足最小支援度,即經過篩選的所有頻繁n項集,這裡新增頻繁1項集    
    k  = 2    
    while (len(L[k-2])>0):              #k=2開始,由頻繁1項集生成頻繁2項集,直到下一個打的項集為空    
        Ck = aprioriGen(L[k-2], k)    
        Lk, supK = scanD(D, Ck, minSupport)    
        supportData.update(supK)        #supportData為字典,存放每個項集的支援度,並以更新的方式加入新的supK    
        L.append(Lk)    
        k +=1    
    return L,supportData    
    
dataSet = loadDataSet()    
C1 = createC1(dataSet)    
print "所有候選1項集C1:\n",C1    
    
D = map(set, dataSet)    
print "資料集D:\n",D    
    
L1, supportData0 = scanD(D,C1, 0.5)    
print "符合最小支援度的頻繁1項集L1:\n",L1    
    
L, suppData = apriori(dataSet)    
print "所有符合最小支援度的項集L:\n",L    
print "頻繁2項集:\n",aprioriGen(L[0],2)    
L, suppData = apriori(dataSet, minSupport=0.7)    
print "所有符合最小支援度為0.7的項集L:\n",L    

 

執行結果:

所有候選1項集C1:  
[frozenset([1]), frozenset([2]), frozenset([3]), frozenset([4]), frozenset([5])]  
資料集D:  
[set([1, 3, 4]), set([2, 3, 5]), set([1, 2, 3, 5]), set([2, 5])]  
符合最小支援度的頻繁1項集L1:  
[frozenset([1]), frozenset([3]), frozenset([2]), frozenset([5])]  
所有符合最小支援度的項集L:  
[[frozenset([1]), frozenset([3]), frozenset([2]), frozenset([5])], [frozenset([1, 3]), frozenset([2, 5]),   
frozenset([2, 3]), frozenset([3, 5])], [frozenset([2, 3, 5])], []]  
頻繁2項集:  
[frozenset([1, 3]), frozenset([1, 2]), frozenset([1, 5]), frozenset([2, 3]), frozenset([3, 5]), frozenset([2, 5])]  
所有符合最小支援度為0.7的項集L:  
[[frozenset([3]), frozenset([2]), frozenset([5])], [frozenset([2, 5])], []]  

 

引文及參考:

    1.本文主要參考地址:https://blog.csdn.net/Eastmount/article/details/53368440

    2.本文參考圖書《機器學習導論》

程式碼後續會及時補充完善,如需轉載,請尊重作者的辛勤付出,註明文章來源!

記錄生活,分享技術!

 

相關文章