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

【資料探勘】Apriori演算法

關聯分析:在大資料中尋找有趣的關係,包括頻繁項集或者關聯規則頻繁項集是指經常一起出現的物品的集合,關聯關係暗示兩種物品之間可能存在很強的關係。這種關聯分析有什麼用呢?根據常識,經常一起出現的可能有某種關係,比如商品A和商品B在同一個頻繁項集裡,那麼可能說明購買商品A的人會選擇購買商品B,或者反過來。那麼商家就可以利用這個資訊,將頻繁項集的物品擺放在一起,以希望提高營業額。又或者網上購物時,可以根據頻繁項集來給使用者進行推薦,往往能收到很好的效果。

那麼怎麼確定頻繁項集呢?我們需要依靠支援度置信度

支援度的定義是:資料集中包含該項集所佔的比例。假如有[1,3,5],[1,2,3],[1,3,4],[2,3,4]這四個原始資料,可以看到4個數據中[1]出現了3次,那麼[1]的支援度就是3/4。我們可以通過定義一個最小支援度

,只保留滿足最小支援度的項集。

置信度的定義是:在A出現的情況下,B出現在同一個項集的概率。即P(B|A)=P(AB)/P(A)。比如[1,3,5],[1,2,3],[1,3,4],[2,3,4]這四個資料,[2]的支援度為0.5,[2,4]的支援度為0.25,那麼關聯規則[2]→[4]的置信度為0.25/0.5=0.5。與最小支援度相對,也有最小置信度。如果一個關聯規則大於最小置信度,則稱為強關聯規則。否則稱為弱關聯規則

 

Apriori規則頻繁項集的所有非空子集也必須是頻繁的。換句話說,如果一個項集的子集中包含非頻繁項集,那這個項集我們就不用考慮了,因為他一定不是頻繁項集。有n個元素的集合,如果窮舉他的集合的話,時間複雜度將達到指數級。利用Apriori規則,我們可以將時間複雜度降低到可以接受的程度。

 

Apriori舉例:

原始項集:[1,3,4],[2,3,5],[1,2,3,5],[2,5],最小支援度為0.5

第一次掃描:[1][2][3][5] ([4]因為支援度為0.25小於0.5被排除,根據Apriori規則,包含[4]的集合都不可能是頻繁項集,因此之後的演算法不用考慮[4])

候選集合:[1,2],[1,3],[1,5],[2,3],[2,5],[3,5]

第二次掃描:[2,3],[2,5],[1,3],[3,5](其餘不符合最支援度)

候選集合:[2,3,5](為什麼[1,3,5]不見了?因為[1,2],[1,5]都不是頻繁項集,根據Apriori規則,他也不可能是頻繁項集)

第三次掃描[2,3,5].

最終產生的頻繁項集:[1],[2],[3],[5],[2,3],[2,5],[1,3],[3,5],[2,3,5]


python程式碼:

# -*- coding: utf-8 -*-
from numpy import *
import itertools
support_dic = {}
# 生成原始資料,用於測試
def loadDataSet():
    return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
# 獲取整個資料庫中的一階元素
# C1 = {1, 2, 3, 4, 5}
def createC1(dataSet):
    C1 = set([])
    for item in dataSet:
        C1 = C1.union(set(item))
    return [frozenset([i]) for i in C1]
# 輸入資料庫(dataset) 和 由第K-1層資料融合後得到的第K層資料集(Ck),
# 用最小支援度(minSupport)對 Ck 過濾,得到第k層剩下的資料集合(Lk)
def getLk(dataset, Ck, minSupport):
    global support_dic
    Lk = {}
    # 計算Ck中每個元素在資料庫中出現次數
    for item in dataset:
        for Ci in Ck:
            if Ci.issubset(item):
                if not Ci in Lk:
                    Lk[Ci] = 1
                else:
                    Lk[Ci] += 1
    # 用最小支援度過濾
    Lk_return = []
    for Li in Lk:
        support_Li = Lk[Li] / float(len(dataSet))
        if support_Li >= minSupport:
            Lk_return.append(Li)
            support_dic[Li] = support_Li
    return Lk_return
# 將經過支援度過濾後的第K層資料集合(Lk)融合
# 得到第k+1層原始資料Ck1
'''連線步'''
def genLk1(Lk):
    Ck1 = []
    for i in range(len(Lk) - 1):
        for j in range(i + 1, len(Lk)):
            if sorted(list(Lk[i]))[0:-1] == sorted(list(Lk[j]))[0:-1]:
                Ck1.append(Lk[i] | Lk[j])
    return Ck1
# 遍歷所有二階及以上的頻繁項集合
def genItem(freqSet):
    for i in range(1, len(freqSet)):
        for freItem in freqSet[i]:
            genRule(freItem)
# 輸入一個頻繁項,根據“置信度”生成規則
# 採用了遞迴,對規則樹進行剪枝
def genRule(Item, minConf=0.5):
    if len(Item) >= 2:
        for element in itertools.combinations(list(Item), 1):
            if support_dic[Item] / float(support_dic[Item - frozenset(element)]) >= minConf:
                print(str([Item - frozenset(element)]) + "----->" + str(element))
                print(support_dic[Item] / float(support_dic[Item - frozenset(element)]))
                genRule(Item - frozenset(element))
# 輸出結果
if __name__ == '__main__':
    dataSet = loadDataSet()
    result_list = []
    print(dataSet)
    Ck = createC1(dataSet)
    print(Ck)
    # 迴圈生成頻繁項集合,直至產生空集
    while True:
        Lk = getLk(dataSet, Ck, 0.5)
        if not Lk:
            break
        result_list.append(Lk)
        Ck = genLk1(Lk)
        if not Ck:
            break
    # 輸出頻繁項及其“支援度”
    print(support_dic)
    # 輸出規則
    genItem(result_list)