關聯規則挖掘:Apriori算法(基於Groceries數據集)


在美國有這樣一家奇怪的超市,它將啤酒與尿布這樣兩個奇怪的東西放在一起進行銷售,並且最終讓啤酒與尿布這兩個看起來沒有關聯的東西的銷量雙雙增加。這家超市的名字叫做沃爾瑪。

你會不會覺得有些不可思議?雖然事后證明這個案例確實有根據,美國的太太們常叮囑她們的丈夫下班后為小孩買尿布,而丈夫們在買尿布后又隨手帶回了他們喜歡的啤酒。但這畢竟是事后分析,我們更應該關注的,是在這樣的場景下,如何找出物品之間的關聯規則。接下來就來介紹下如何使用Apriori算法,來找到物品之間的關聯規則吧。

一. 關聯分析概述

選擇物品間的關聯規則也就是要尋找物品之間的潛在關系。要尋找這種關系,有兩步,以超市為例

找出頻繁一起出現的物品集的集合,我們稱之為頻繁項集。比如一個超市的頻繁項集可能有{{啤酒,尿布},{雞蛋,牛奶},{香蕉,蘋果}}
在頻繁項集的基礎上,使用關聯規則算法找出其中物品的關聯結果。
簡單點說,就是先找頻繁項集,再根據關聯規則找關聯物品。

為什么要先找頻繁項集呢?還是以超市為例,你想想啊,我們找物品關聯規則的目的是什么,是為了提高物品的銷售額。如果一個物品本身購買的人就不多,那么你再怎么提升,它也不會高到哪去。所以從效率和價值的角度來說,肯定是優先找出那些人們頻繁購買的物品的關聯物品。

既然要找出物品的關聯規則有兩步,那我們也一步一步來。我們會先介紹如何用Apriori找出物品的頻繁項集,然后下一篇會在Apriori處理后的頻繁項集的基礎上,進行物品的關聯分析。

二. Apriori算法基礎概念

在介紹Apriori算法之前,我們需要先了解幾個概念,別擔心,我們會結合下面的例子來進行說明的。

這些是一個超市里面的一部分購買商品記錄:

交易編號 購買商品
0 牛奶,洋蔥,肉豆蔻,芸豆,雞蛋,酸奶
1 蒔蘿,洋蔥,肉豆蔻,芸豆,雞蛋,酸奶
2 牛奶,蘋果,芸豆,雞蛋
3 牛奶,獨角獸,玉米,芸豆,酸奶
4 玉米,洋蔥,洋蔥,芸豆,冰淇淋,雞蛋

2.1 關聯分析的幾個概念

支持度(Support):支持度可以理解為物品當前流行程度。計算方式是:

支持度 = (包含物品A的記錄數量) / (總的記錄數量)

用上面的超市記錄舉例,一共有五個交易,牛奶出現在三個交易中,故而{牛奶}的支持度為3/5。{雞蛋}的支持度是4/5。牛奶和雞蛋同時出現的次數是2,故而{牛奶,雞蛋}的支持度為2/5。

置信度(Confidence):置信度是指如果購買物品A,有較大可能購買物品B。計算方式是這樣:

置信度( A -> B) = (包含物品A和B的記錄數量) / (包含 A 的記錄數量)

舉例:我們已經知道,(牛奶,雞蛋)一起購買的次數是兩次,雞蛋的購買次數是4次。那么Confidence(牛奶->雞蛋)的計算方式是Confidence(牛奶->雞蛋)=2 / 4。

提升度(Lift):提升度指當銷售一個物品時,另一個物品銷售率會增加多少。計算方式是:

提升度( A -> B) = 置信度( A -> B) / (支持度 A)

舉例:上面我們計算了牛奶和雞蛋的置信度Confidence(牛奶->雞蛋)=2 / 4。牛奶的支持度Support(牛奶)=3 / 5,那么我們就能計算牛奶和雞蛋的支持度Lift(牛奶->雞蛋)=0.83
當提升度(A->B)的值大於1的時候,說明物品A賣得越多,B也會賣得越多。而提升度等於1則意味着產品A和B之間沒有關聯。最后,提升度小於1那么意味着購買A反而會減少B的銷量。

其中支持度和Apriori相關,而置信度和提升度是下一篇尋找物品關聯規則的時候會用到。

2.2 Apriori 算法介紹

Apriori的作用是根據物品間的支持度找出物品中的頻繁項集。通過上面我們知道,支持度越高,說明物品越受歡迎。那么支持度怎么決定呢?這個是我們主觀決定的,我們會給Apriori提供一個最小支持度參數,然后Apriori會返回比這個最小支持度高的那些頻繁項集。

說到這里,有人可能會發現,既然都知道了支持度的計算公式,那直接遍歷所有組合計算它們的支持度不就可以了嗎?

是的,沒錯。確實可以通過遍歷所有組合就能找出所有頻繁項集。但問題是遍歷所有組合花的時間太多,效率太低,假設有N個物品,那么一共需要計算2^N-1次。每增加一個物品,數量級是成指數增長。而Apriori就是一種找出頻繁項集的高效算法。它的核心就是下面這句話:

某個項集是頻繁的,那么它的所有子集也是頻繁的。

這句話看起來是沒什么用,但是反過來就很有用了。

如果一個項集是 非頻繁項集,那么它的所有超集也是非頻繁項集。

Apriori算法中的非頻繁項集:
請輸入圖片描述

如圖所示,我們發現{A,B}這個項集是非頻繁的,那么{A,B}這個項集的超集,{A,B,C},{A,B,D}等等也都是非頻繁的,這些就都可以忽略不去計算。

運用Apriori算法的思想,我們就能去掉很多非頻繁的項集,大大簡化計算量。

2.3 Apriori算法流程

要使用Apriori算法,我們需要提供兩個參數,數據集和最小支持度。我們從前面已經知道了Apriori會遍歷所有的物品組合,怎么遍歷呢?答案就是遞歸。先遍歷1個物品組合的情況,剔除掉支持度低於最小支持度的數據項,然后用剩下的物品進行組合。遍歷2個物品組合的情況,再剔除不滿足條件的組合。不斷遞歸下去,直到不再有物品可以組合。

2.4 Apriori算法實現

(1)數據集處理

請輸入圖片描述

采用Groceries數據集,我們需要的數據格式是:List of List,每一個購物清單是一個list,所有的購物清單也構成一個List。

    with open(filename)as f:
    f_csv = csv.reader(f)
    for index, val in enumerate(f_csv):
        if index != 0:
            goodsList = str(val[1]).replace('}','').replace('{','').split(',')
            # print(str(type(goodsList)))
            data_set.append(list(goodsList))

(2)項的排列組合
create_Ck

Ck = set()
len_Lksub1 = len(Lksub1)
list_Lksub1 = list(Lksub1)
for i in range(len_Lksub1):
    for j in range(1, len_Lksub1):
        l1 = list(list_Lksub1[i])
        l2 = list(list_Lksub1[j])
        l1.sort()
        l2.sort()
        if l1[0:k - 2] == l2[0:k - 2]:
            Ck_item = list_Lksub1[i] | list_Lksub1[j]
            # pruning
            if is_apriori(Ck_item, Lksub1):
                Ck.add(Ck_item)
return Ck

is_apriori

    for item in Ck_item:
    sub_Ck = Ck_item - frozenset([item])
    if sub_Ck not in Lksub1:
        return False
return True

(3)頻繁項集的計算
將獲得的所有排列組合,計算支持度。

generate_Lk_by_Ck

support_data = {}
C1 = create_C1(data_set)    # 獲得一層候選項集
L1 = generate_Lk_by_Ck(data_set, C1, min_support, support_data) # 獲得一層頻繁項集
print("len-lk:" + str(len(list(L1))) + "  L1:" + str(L1))
Lksub1 = L1.copy()
L = []
L.append(Lksub1) # List of List
for i in range(2, k + 1): # 多層頻繁項集的獲取
    Ci = create_Ck(Lksub1, i)
    Li = generate_Lk_by_Ck(data_set, Ci, min_support, support_data)
    Lksub1 = Li.copy()
    L.append(Lksub1)
return L, support_data # L是所有的頻繁項集,按照層數保存的List of List,support_data是頻繁項集和支持度的鍵值對

generate_Lk_by_Ck

Lk = []
item_count = {}
for t in data_set: # 遍歷所有條目
    for item in Ck: # 候選k階頻繁項集循環
        if item.issubset(t): # item是否是t的子集 ,並計數存到item_count
            if item not in item_count:
                item_count[item] = 1
            else:
                item_count[item] += 1
t_num = float(len(data_set))
for item in item_count:
    if (item_count[item] / t_num) >= min_support: # 支持度比較
        print('LK add : ' + str(item))
        Lk.append(item)
        support_data[item] = item_count[item] / t_num
print('LK:' + str(Lk))
return Lk # 返回頻繁項集

(4)置信度的計算
傳入最小置信度,然后將所有的置信度進行計算,大於最小置信度的條件概率,計入新的list。
generate_big_rules

big_rule_list = []
sub_set_list = []
for i in range(0, len(L)): # 遍歷頻繁項集
    for freq_set in L[i]: # 頻繁項集
        for sub_set in sub_set_list:
            if sub_set.issubset(freq_set):
                # print("sub_set:" + str(sub_set))
                # print("freq_set:" + str(freq_set))
                conf = support_data[freq_set] / support_data[freq_set - sub_set] # 支持度計算
                big_rule = (freq_set - sub_set, sub_set, conf)
                # print("freq_set - sub_set:" + str(freq_set - sub_set))
                if conf >= min_conf and big_rule not in big_rule_list:
                    # print freq_set-sub_set, " => ", sub_set, "conf: ", conf
                    big_rule_list.append(big_rule)
            # print("+++++++")
        sub_set_list.append(freq_set)
return big_rule_list

源碼

下面我們來用Apriori算法實戰一下吧。

三. Apriori算法實戰

我們用一個簡單的例子來用一下Apriori吧,這里用到的庫是mlxtend

在放代碼之前,先介紹下Apriori算法的參數吧。

def apriori(df, min_support=0.5, use_colnames=False, max_len=None)

參數如下: df:這個不用說,就是我們的數據集。 min_support:給定的最小支持度。
use_colnames:默認False,則返回的物品組合用編號顯示,為True的話直接顯示物品名稱。
max_len:最大物品組合數,默認是None,不做限制。如果只需要計算兩個物品組合的話,便將這個值設置為2。

OK,接下來就來用一個簡單的例子來看看怎么使用Apriori算法找到頻繁項集吧。

import pandas as pd 
from mlxtend.preprocessing import TransactionEncoder 
from mlxtend.frequent_patterns import apriori #設置數據集 

dataset = [
    ['牛奶','洋蔥','肉豆蔻','芸豆','雞蛋','酸奶'], 
    ['蒔蘿','洋蔥','肉豆蔻','芸豆','雞蛋','酸奶'], 
    ['牛奶','蘋果','芸豆','雞蛋'], 
    ['牛奶','獨角獸','玉米','芸豆','酸奶'], 
    ['玉米','洋蔥','洋蔥','芸豆','冰淇淋','雞蛋']
] 
te = TransactionEncoder() #進行 one-hot 編碼 
te_ary = te.fit(records).transform(records) 
df = pd.DataFrame(te_ary, columns=te.columns_) #利用 Apriori 找出頻繁項集 
freq = apriori(df, min_support=0.05, use_colnames=True)

首先,需要先將商品進行one-hot編碼,編碼后用boolean值表示。所謂ont-hot編碼呢,直觀來說就是有多少個狀態就有多少比特,而且只有一個比特為1,其他全為0的一種碼制。比如冰淇淋只存在最后一共交易單中,其他交易中都沒出現。那冰淇淋就可以用[0,0,0,0,1]來表示

這里編碼后的數據如下:

冰淇淋 洋蔥 牛奶 獨角獸 玉米 肉豆蔻 芸豆 蘋果 蒔蘿 酸奶 雞蛋
0 False True True False False True True False False True True
1 False True False False False True True False True True True
2 False False True False False False True True False False True
3 False False True True True False True False False True False
4 True True False False True False True False False False True
我們設定的最小支持度是0.6,那么只有支持度大於0.6的物品集合才是頻繁項集,最終結果如下:

support itemsets 0 0.6 (洋蔥) 1 0.6 (牛奶) 2 1.0 (芸豆) 3 0.6 (酸奶) 4 0.8 (雞蛋) 5 0.6 (芸豆, 洋蔥) 6 0.6 (洋蔥, 雞蛋) 7 0.6 (牛奶, 芸豆) 8 0.6 (酸奶, 芸豆) 9 0.8 (芸豆, 雞蛋) 10 0.6 (芸豆, 洋蔥, 雞蛋)
四. 小結
今天我們介紹了關聯分析中會用到的幾個概念,支持度,置信度,提升度。然后講述了Apriori算法的作用,以及Apriori算法如何高效得找出物品的頻繁項集。

最后使用Apriori算法找出例子中的頻繁項集。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM