背景
关联规则应用,一般是为了寻求:已知某些项在一定概率下推导出另一项,这样的组合。
当然在数据量比较小的时候,这样的问题可以穷尽的,但是在数据量比较大时,搜索将成为瓶颈。
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"])