關聯規則演算法(Apriori)在Python上的實現
定義
關聯分析又稱關聯挖掘,就是在交易資料、關係資料或其他資訊載體中,查詢存在於專案集合或物件集合之間的頻繁模式、關聯、相關性或因果結構。可從資料庫中關聯分析出形如“由於某些事件的發生而引起另外一些事件的發生”之類的規則。如“67%的顧客在購買啤酒的同時也會購買尿布”,因此通過合理的啤酒和尿布的貨架擺放或捆綁銷售可提高超市的服務質量和效益。又如“‘C語言’課程優秀的同學,在學習‘資料結構’時為優秀的可能性達88%”,那麼就可以通過強化“C語言”的學習來提高教學效果。
相關名詞
示例1:如下是一個超市幾名顧客的交易資訊。
TID | Items |
---|---|
001 | Cola, Egg, Ham |
002 | Cola, Diaper, Beer |
003 | Cola, Diaper, Beer, Ham |
004 | Diaper, Beer |
TID代表交易流水號,Items代表一次交易的商品。
我們對這個資料集進行關聯分析,可以找出關聯規則{Diaper}→{Beer}。
它代表的意義是:購買了Diaper的顧客會購買Beer。這個關係不是必然的,但是可能性很大,這就已經足夠用來輔助商家調整Diaper和Beer的擺放位置了,例如擺放在相近的位置,進行捆綁促銷來提高銷售量。
1、事務:每一條交易稱為一個事務,例如示例1中的資料集就包含四個事務。
2、項:交易的每一個物品稱為一個項,例如Cola、Egg等。
3、項集:包含零個或多個項的集合叫做項集,例如{Cola, Egg, Ham}。
4、k−項集:包含k個項的項集叫做k-項集,例如{Cola}叫做1-項集,{Cola, Egg}叫做2-項集。
5、支援度計數:一個項集出現在幾個事務當中,它的支援度計數就是幾。例如{Diaper, Beer}出現在事務 002、003和004中,所以它的支援度計數是3。
6、支援度:支援度計數除於總的事務數。例如上例中總的事務數為4,{Diaper, Beer}的支援度計數為3,所以它的支援度是3÷4=75%,說明有75%的人同時買了Diaper和Beer。
7、頻繁項集:支援度大於或等於某個閾值的項集就叫做頻繁項集。例如閾值設為50%時,因為{Diaper, Beer}的支援度是75%,所以它是頻繁項集。
8、前件和後件:對於規則{Diaper}→{Beer},{Diaper}叫做前件,{Beer}叫做後件。
9、置信度:對於規則{Diaper}→{Beer},{Diaper, Beer}的支援度計數除於{Diaper}的支援度計數,為這個規則的置信度。例如規則{Diaper}→{Beer}的置信度為3÷3=100%。說明買了Diaper的人100%也買了Beer。
10、強關聯規則:大於或等於最小支援度閾值和最小置信度閾值的規則叫做強關聯規則。關聯分析的最終目標就是要找出強關聯規則。
案例
以下是某餐廳菜品訂單事務集,每一行代表一條事務,挖掘其中菜品之間的聯絡
python程式碼
Apriori演算法指令碼,命名為apriori.py
#-*- coding: utf-8 -*- from __future__ import print_function import pandas as pd #自定義連線函式,用於實現L_{k-1}到C_k的連線 def connect_string(x, ms): x = list(map(lambda i:sorted(i.split(ms)), x)) l = len(x[0]) r = [] for i in range(len(x)): for j in range(i,len(x)): if x[i][:l-1] == x[j][:l-1] and x[i][l-1] != x[j][l-1]: r.append(x[i][:l-1]+sorted([x[j][l-1],x[i][l-1]])) return r #尋找關聯規則的函式 def find_rule(d, support, confidence, ms = u'--'): result = pd.DataFrame(index=['support', 'confidence']) #定義輸出結果 support_series = 1.0*d.sum()/len(d) #支援度序列 column = list(support_series[support_series > support].index) #初步根據支援度篩選 k = 0 while len(column) > 1: k = k+1 print(u'\n正在進行第%s次搜尋...' %k) column = connect_string(column, ms) print(u'數目:%s...' %len(column)) sf = lambda i: d[i].prod(axis=1, numeric_only = True) #新一批支援度的計算函式 #建立連線資料,這一步耗時、耗記憶體最嚴重。當資料集較大時,可以考慮並行運算優化。 d_2 = pd.DataFrame(list(map(sf,column)), index = [ms.join(i) for i in column]).T support_series_2 = 1.0*d_2[[ms.join(i) for i in column]].sum()/len(d) #計算連線後的支援度 column = list(support_series_2[support_series_2 > support].index) #新一輪支援度篩選 support_series = support_series.append(support_series_2) column2 = [] for i in column: #遍歷可能的推理,如{A,B,C}究竟是A+B-->C還是B+C-->A還是C+A-->B? i = i.split(ms) for j in range(len(i)): column2.append(i[:j]+i[j+1:]+i[j:j+1]) cofidence_series = pd.Series(index=[ms.join(i) for i in column2]) #定義置信度序列 for i in column2: #計算置信度序列 cofidence_series[ms.join(i)] = support_series[ms.join(sorted(i))]/support_series[ms.join(i[:len(i)-1])] for i in cofidence_series[cofidence_series > confidence].index: #置信度篩選 result[i] = 0.0 result[i]['confidence'] = cofidence_series[i] result[i]['support'] = support_series[ms.join(sorted(i.split(ms)))] result = result.T.sort_values(['confidence','support'], ascending = False) #結果整理,輸出 return result
主指令碼
#-*- coding: utf-8 -*-
#使用Apriori演算法挖掘菜品訂單關聯規則
from __future__ import print_function
import pandas as pd
from apriori import * #匯入自行編寫的apriori函式
inputfile = 'G:/chapter5/demo/data/menu_orders.xls' #輸入檔案路徑
outputfile = 'C:/Users/yangge/Desktop/result.xlsx' #結果檔案路徑
data = pd.read_excel(inputfile, header = None)
print(u'\n轉換原始資料至0-1矩陣...')
ct = lambda x : pd.Series(1, index = x[pd.notnull(x)]) #轉換0-1矩陣的過渡函式
b = map(ct, data.as_matrix()) #用map方式執行
data = pd.DataFrame(list(b)).fillna(0) #實現矩陣轉換,空值用0填充
print(u'\n轉換完畢。')
del b #刪除中間變數b,節省記憶體
support = 0.2 #最小支援度
confidence = 0.5 #最小置信度
ms = '-' #連線符,預設'--',用來區分不同元素,如A--B。需要保證原始表格中不含有該字元
find_rule(data, support, confidence, ms).to_excel(outputfile) #儲存結果
print("計算結束!")
執行結果
第一條輸出結果解釋:客戶同時點菜品3和菜品2的概率是30%,點了菜品3再點菜品2的概率是100%。
最後一條輸出結果解釋:客戶同時點菜品1、菜品2和菜品4的概率是30%,點了菜品1和菜品2再點菜品4的概率是60%。
知道了這些可以對客戶進行智慧推薦,既能增加銷量又能滿足客戶需求。
備註:承接模型程式碼實現(支援python、matlab),有意請聯絡QQ947943645 ,非誠勿擾!