1. 程式人生 > >資料探勘之Apriori演算法

資料探勘之Apriori演算法

python3程式碼如下:

#coding = utf-8
import numpy
#from python_util import fileread

"""
    程式所需部分:
        建立初始的候選集
        根據Lk產生Lk+1
        計算每個候選集的支援度
        計算置信度
        generateCandidate(Lk):篩選掉不合適的
        資料讀取
"""


"""
    建立初始的候選集
    INPUT:
        data_set:a list of list 儲存交易的資料
    OUTPUT:
        C1:列表,每個元素為一個集合
"""


def createInitCandidates(data_set):
    C1 = []
    for data in data_set:
        for item in data:
            if [item] not in C1:
                C1.append([item])
    C1.sort()
    return [frozenset(c) for c in C1]


"""
    計算支援度
    INPUT:
        data_set:交易資料
        candidate:候選項集合
    OUTPUT:
        
"""


def calSupport(data_set, candidates):
    # 首先將data_set轉化為集合
    support = {}

    datas = [frozenset(data) for data in data_set]
    for candidate in candidates:
        tmp = 0
        for data in datas:
            if candidate.issubset(data):
                tmp += 1
        support[candidate] = tmp/len(data_set)
    return support


"""
    根據支援度來進行篩選掉小於最小支援度的
    INPUT:
        candidates:候選項集合
        min_support:最小支援度
        support:candidates對應的支援度
    OUTPUT:
        new_candidates:即為Lk
"""


def filterCandidates(candidates, min_support, support):
    new_candidates = []
    for candidate in candidates:
        if support[candidate] >= min_support:
            new_candidates.append(candidate)
    new_candidates.sort()
    return new_candidates


"""
    GnenerateCandidates
    INPUT:
        Lk:a list consists of set
    OUTPUT:
        candidates:Ck+1
"""


def generateCandidates(Lk):
    candidates = []
    #找出當前候選項集的長度
    k = len(Lk[0])
    len_Lk = len(Lk)
    #self_joining
    for len_kl1 in range(len_Lk):
        tmp1 = list(Lk[len_kl1])[: k - 1]
        for len_kl2 in range(len_kl1+1, len_Lk):
            tmp2 = list(Lk[len_kl2])[: k - 1]
            if tmp1 == tmp2:
                candidate = Lk[len_kl1].union(Lk[len_kl2])
                candidates.append(candidate)
    candidates.sort()
    return candidates


"""
    Apriori演算法實現
    INPUT:
        data_set:資料集,a list consists of list
        min_support:最小支援度
"""


def Apriori(data_set, min_support):
    # 產生初始項集合
    C1 = createInitCandidates(data_set)
    support = calSupport(data_set, C1)
    # 篩選掉小於最小支援度的
    L1 = filterCandidates(C1, min_support, support)
    L = [L1]
    k = 2
    while len(L[k-2]) > 0:
        candidates = generateCandidates(L[k-2])
        tmp_support = calSupport(data_set, candidates)
        Lk = filterCandidates(candidates, min_support, tmp_support)
        #support.append(tmp_support)
        support.update(tmp_support)
        L.append(Lk)
        k += 1
    return support, L




"""
    還需要做的工作:
    輸出頻繁項集中高於最低值的置信度 兩個支援度相除
"""

def calConfidence(supportdata,set1,set2):
    tmp1=[]
    tmp2=[]
    set2.update(set1)
    for key in supportdata:
        if (set1 == key):
            tmp1 = supportdata[key]
        if (set2 == key):
            tmp2 = supportdata[key]
    if tmp1 == [] or tmp2 == []:
        print("小於最小支援度或不存在")
        return 0
    else:
        confidence = tmp2/tmp1
        return confidence



if __name__ == "__main__":
    #pathname = input("請輸入檔案地址")
    data_set = fileread("testInput.txt")
    support, L = Apriori(data_set, 0.2)
    print("所有項集的支援度為", support)
    print("頻繁項集為", L)
    #print(len(support))
    confidence = calConfidence(support, {1}, {2})
    print(confidence)

其中testInput.txt的格式如下:

1 2 5
2 4
2 3
1 2 4
1 3
2 3
1 3
1 2 3 5
1 2 3
2 4 5

在2006年12月召開的 IEEE 資料探勘國際會議上(ICDM, International Conference on Data Mining),與會的各位專家選出了當時的十大資料探勘演算法( top 10 data mining algorithms ),可以參見文獻【1】。本部落格已經介紹過的位列十大演算法之中的演算法包括:

Apriori演算法是一種用於關聯規則挖掘(Association rule mining)的代表性演算法,它同樣位居十大資料探勘演算法之列。關聯規則挖掘是資料探勘中的一個非常重要的研究方向,也是一個由來已久的話題,它的主要任務就是設法發現事物之間的內在聯絡。

歡迎關注白馬負金羈的部落格 http://blog.csdn.net/baimafujinji,為保證公式、圖表得以正確顯示,強烈建議你從該地址上檢視原版博文。本部落格主要關注方向包括:數字影象處理、演算法設計與分析、資料結構、機器學習、資料探勘、統計分析方法、自然語言處理。

引言:資料探勘與機器學習

有時候,人們會對機器學習與資料探勘這兩個名詞感到困惑。如果你翻開一本冠以機器學習之名的教科書,再同時翻開一本名叫資料探勘的教材,你會發現二者之間有相當多重合的內容。比如機器學習中也會講到決策樹和支援向量機,而資料探勘的書裡也必然要在決策樹和支援向量機上花費相當的篇幅。可見二者確有相當大的重合面,但如果細研究起來,二者也的確是各自不同的領域。

大體上看,資料探勘可以視為資料庫、機器學習和統計學三者的交叉。簡單來說,對資料探勘而言,資料庫提供了資料管理技術,而機器學習和統計學則提供了資料分析技術。所以你可以認為資料探勘包含了機器學習,或者說機器學習是資料探勘的彈藥庫中一類相當龐大的彈藥集。既然是一類彈藥,其實也就是在說資料探勘中肯定還有其他非機器學習範疇的技術存在。Apriori演算法就屬於一種非機器學習的資料探勘技術。

我們都知道資料探勘是從大量的、不完全的、有噪聲的、模糊的、隨機的資料中,提取隱含在其中的、人們事先不知道的、但又是潛在有用的資訊和知識的過程。 而機器學習是以資料為基礎,設法構建或訓練出一個模型,進而利用這個模型來實現資料分析的一類技術。這個被訓練出來的機器學習模型當然也可以認為是我們從資料中挖掘出來的那些潛在的、有意義的資訊和知識。在非機器學習的資料探勘技術中,我們並不會去建立這樣一個模型,而是直接從原資料集入手,設法分析出隱匿在資料背後的某些資訊或知識。在後續介紹Apriori演算法時,你會相當明顯地感受到這一特點。

基本概念

許多商業企業在日復一日的運營中積聚了大量的交易資料。例如,超市的收銀臺每天都收集大量的顧客購物資料。例如,下表給出了一個這種資料集的例子,我們通常稱其為購物籃交易(market basket transaction)。表中每一行對應一個交易,包含一個唯一標識TID和特定顧客購買的商品集合。零售商對分析這些資料很感興趣,以便了解其顧客的購買行為。可以使用這種有價值的資訊來支援各種商業中的實際應用,如市場促銷,庫存管理和顧客關係管理等等。

令I={i1,i2,⋯,id}I={i1,i2,⋯,id}是購物籃資料中所有項的集合,而T={t1,t2,⋯,tN}T={t1,t2,⋯,tN}是所有交易的集合。包含0個或多個項的集合被稱為項集(itemset)。如果一個項集包含kk個項,則稱它為 kk-項集。顯然,每個交易titi包含的項集都是II的子集。

關聯規則是形如 X→YX→Y 的蘊涵表示式,其中XX和YY是不相交的項集,即 X∩Y=∅X∩Y=∅。關聯規則的強度可以用它的支援度(support)和置信度(confidence)來度量。支援度確定規則可以用於給定資料集的頻繁程度,而置信度確定YY在包含XX的交易中出現的頻繁程度。支援度(ss:Fraction of transactions that contain both XX and YY)和置信度(cc:How often items in YY appear in transactions that contain XX)這兩種度量的形式定義如下: 

s(X→Y)=σ(X∪Y)Nc(X→Y)=σ(X∪Y)σ(X)s(X→Y)=σ(X∪Y)Nc(X→Y)=σ(X∪Y)σ(X)

例如考慮規則{Milk, Diaper}→→{Beer},則易得: 

s=σ(Milk,Diaper,Beer)|T|=25=0.4c=σ(Milk,Diaper,Beer)σ(Milk,Diaper)=23=0.67s=σ(Milk,Diaper,Beer)|T|=25=0.4c=σ(Milk,Diaper,Beer)σ(Milk,Diaper)=23=0.67

Association Rule Mining Task:Given a set of transactions T, the goal of association rule mining is to find all rules having

  • support ≥ minsup threshold
  • confidence ≥ minconf threshold

因此,大多數關聯規則挖掘演算法通常採用的一種策略是,將關聯規則挖掘任務分解為如下兩個主要的子任務。

  1. 頻繁項集產生:其目標是發現滿足最小支援度閾值的所有項集,這些項集稱作頻繁項集(frequent itemset)。
  2. 規則的產生:其目標是從上一步發現的頻繁項集中提取所有高置信度的規則,這些規則稱作強規則(strong rule)。

通常,頻繁項集產生所需的計算開銷遠大於產生規則所需的計算開銷。

最容易想到、也最直接的進行關聯關係挖掘的方法或許就是暴力搜尋(Brute-force)的方法:

  • List all possible association rules
  • Compute the support and confidence for each rule
  • Prune rules that fail the minsup and minconf thresholds

然而,由於Brute-force的計算量過大,所以取樣這種方法並不現實!格結構(Lattice structure)常被用來列舉所有可能的項集。如下圖所示為I={a,b,c,d,e}I={a,b,c,d,e}的項集格。一般來說,排除空集後,一個包含kk個項的資料集可能產生2k−12k−1個頻繁項集。由於在實際應用中kk的值可能非常大,需要探查的項集搜尋空集可能是指數規模的。 

發現頻繁項集的一種原始方法是確定格結構中每個候選項集(candidate itemset)的支援度計 數。為了完成這一任務,必須將每個候選項集與每個交易進行比較,如下圖所示。如果候選項集包含在交易中,則候選項集的支援度計數增加。例如,由於項集{Bread, Milk}出現在事務1、4 和5中,其支援度計數將增加3次。這種方法的開銷可能非常大,因為它需要進行O(NMw)O(NMw)次比 較,其中NN是交易數,M=2k−1M=2k−1是候選項集數,而ww是交易的最大寬度(也就是交易中最大的項數)。

先驗原理

在上一小節的末尾,我們已經看到Brute-force在實際中並不可取。我們必須設法降低產生頻繁項集的計算複雜度。此時我們可以利用支援度對候選項集進行剪枝,這也是Apriori所利用的第一條先驗原理:

Apriori定律1:如果一個集合是頻繁項集,則它的所有子集都是頻繁項集。

例如:假設一個集合{A,B}是頻繁項集,即A、B同時出現在一條記錄的次數大於等於最小支援度min_support,則它的子集{A},{B}出現次數必定大於等於min_support,即它的子集都是頻繁項集。

Apriori定律2:如果一個集合不是頻繁項集,則它的所有超集都不是頻繁項集。

舉例:假設集合{A}不是頻繁項集,即A出現的次數小於 min_support,則它的任何超集如{A,B}出現的次數必定小於min_support,因此其超集必定也不是頻繁項集。

下圖表示當我們發現{A,B}是非頻繁集時,就代表所有包含它的超級也是非頻繁的,即可以將它們都剪除。 

Apriori演算法與例項

R. Agrawal 和 R. Srikant於1994年在文獻【2】中提出了Apriori演算法,該演算法的描述如下:

  • Let kk=1
  • Generate frequent itemsets of length kk
  • Repeat until no new frequent itemsets are identified 
    • Generate length (kk+1) candidate itemsets from length kk frequent itemsets
    • Prune candidate itemsets containing subsets of length kk+1 that are infrequent
    • Count the support of each candidate by scanning the DB
    • Eliminate candidates that are infrequent, leaving only those that are frequent

或者在其他資料上更為常見的是下面這種形式化的描述(注意這跟前面的文字描述是一致的): 

下面是一個具體的例子,最開始資料庫裡有4條交易,{A、C、D},{B、C、E},{A、B、C、E},{B、E},使用min_support=2作為支援度閾值,最後我們篩選出來的頻繁集為{B、C、E}。 

上述例子中,最值得我們從L2L2到C3C3的這一步。這其實就是在執行虛擬碼中第一個藍色框條所標註的地方:Ck+1=GenerateCandidates(Lk)Ck+1=GenerateCandidates(Lk),具體來說在Apriori演算法中,它所使用的策略如下: 

可見生成策略由兩部分組成,首先是self-joining部分。例如,假設我們有一個L3L3={abc, abd, acd, ace, bcd}(注意這已經是排好序的}。選擇兩個itemsets,它們滿足條件:前kk-1個item都相同,但最後一個item不同,把它們組成一個新的Ck+1Ck+1的項集cc。如下圖所示,{abc}和{abd}組成{abcd},{acd}和{ace}組成{acde}。生成策略的第二部分是pruning。對於一個位於Ck+1Ck+1中的項集cc,ss是cc的大小為kk的子集,如果ss不存在於LkLk中,則將cc從Ck+1Ck+1中刪除。如下圖所示,因為{acde}的子集{cde}並不存在於L3L3中,所以我們將{acde}從C4C4中刪除。最後得到的C4C4,僅包含一個項集{abcd}。 

回到之前的例子,從L2L2到C3C3的這一步,我們就只能獲得{B、C、E}。以上便是Apriori演算法的最核心思想。當然在具體實現的時候,如何Count Supports of Candidates也是需要考慮的問題,我們這裡略去這部分內容的討論,有興趣讀者可以參閱文獻【3】以瞭解更多。

參考文獻

【1】Wu, X., Kumar, V., Quinlan, J.R., Ghosh, J., Yang, Q., Motoda, H., McLachlan, G.J., Ng, A., Liu, B., Philip, S.Y. and Zhou, Z.H., 2008. Top 10 algorithms in data mining. Knowledge and information systems, 14(1), pp.1-37. (http://www.cs.uvm.edu/~icdm/algorithms/10Algorithms-08.pdf

【2】Rakesh Agrawal and Ramakrishnan Srikant Fast algorithms for mining association rules in large databases. Proceedings of the 20th International Conference on Very Large Data Bases, VLDB, pages 487-499, Santiago, Chile, September 1994. (http://rakesh.agrawal-family.com/papers/vldb94apriori.pdf)

【3】Pang-Ning Tan, Micheale Steinbach, Vipin Kumar. 資料探勘導論,範明,等譯. 人民郵電出版社,2011