背景
關聯規則應用,一般是爲了尋求:已知某些項在一定概率下推導出另一項,這樣的組合。
當然在數據量比較小的時候,這樣的問題可以窮盡的,但是在數據量比較大時,搜索將成爲瓶頸。
Aprior算法提出頻繁項的子集必須都是頻繁,據此設計程序將減少搜索次數。
在看《Python數據分析與挖掘實戰大數據技術叢書.pdf》,裏面實現的Aprior算法有點煩瑣,而且未實現剪切步,有提升空間。
按自己的思路重寫了一遍,耗時90ms——>70ms,效率提高22%。
代碼
import pandas as pd
import itertools
def find_rule2(d, support, confidence):
"""
關聯規則:Aprior算法
輸入:
d: 數據樣本,pd.DataFrame
示例:(3條數據)
a b c d e
0 1 0 1 0 1
1 0 1 0 1 0
2 0 1 1 0 0
support:支持度閾值,0.2 表示 20%
confidence:置信度閾值,0.3 表示 30%
含 連接步、剪切步
"""
result = dict() #定義輸出結果
# 最小支持度個數
lend = len(d)
support_num = support*lend
support_series = d.sum() #支持度序列
L1 = {(k,):v for k,v in support_series[support_series>=support_num].items()} #L1頻繁項集
# 計算支持度數目
def getsupport(v):
return np.sum(d.loc[:,v].sum(axis=1)==len(v))
LL_all = []
LLn = L1
k = 0
while len(LLn)>1:
k += 1
print("開始第%d輪搜索……"%k)
print("數目:%d"%len(LLn))
LL_all.append(LLn)
# 連接步:
df = pd.DataFrame([dict.fromkeys(key,1) for key in LLn.keys()],index=LLn.keys()).fillna(0)
LL = {}
for itemsets in itertools.combinations(df.columns[df.sum()>=k],k+1):
# 剪切步:可以在這裏對itemsets的每一個子集是否在頻繁項進行過濾減少查找頻率
if np.sum(df.ix[:,itemsets].sum(axis=1)==k) != k+1:
continue
snum = getsupport(itemsets)
if snum >= support_num:
LL[itemsets] = snum
# 產生關聯規則
for i in range(1,k+1):
for cs in itertools.combinations(itemsets,i):
# 置信度 P(B|A) = P(AB)/P(A)
cf = snum/LL_all[i-1][cs]
if cf>=confidence:
name = "".join(["--".join(cs),"->","--".join(set(itemsets).difference(cs))])
result[name] = (snum/lend,cf)
LLn = LL
return pd.DataFrame(result).T.rename(columns = {0:"support",1:"confidence"}).sort_values(by=["support","confidence"])