关联规则分析也称“购物篮”分析,最早是为了发现超市销售数据库中不同的商品之间的关联关系。
例如购买了面包的顾客同时非常有可能会购买牛奶,这就导出了一条关联规则“面包=》牛奶”,其中,面包称为规则的前项,牛奶称为后项。通过对面包降低售价促销,适当提高牛奶售价,关联销售出的牛奶就有可能增加超市整体的利润。
常用的关联规则算法:
算法名称 | 算法描述 |
---|---|
apriori法 | 最经典的挖掘频繁项集的算法,通过连接产生候选项及其支持度,然后通过剪枝生成频繁项集 |
灰色关联度法 | 分析和确定各因素之间的影响程度或若干子因素对主因素的贡献度 |
1.支持度:项集A,B同时发生的概率,也称相对支持度
S u p p o r t ( A ⟹ B ) = P ( A ∪ B ) = A , B 同 时 发 生 的 事 务 数 所 有 的 事 务 数 Support(A\implies B)=P(A\cup B) =\frac{A,B同时发生的事务数}{所有的事务数} Support(A⟹B)=P(A∪B)=所有的事务数A,B同时发生的事务数
2.置信度:项集A发生,则项集B发生的概率
C o n f i d e n c e ( A ⟹ B ) = P ( A ∣ B ) = A , B 同 时 发 生 的 事 务 数 A 发 生 的 事 务 数 Confidence(A\implies B)=P(A|B)=\frac{A,B同时发生的事务数}{A发生的事务数} Confidence(A⟹B)=P(A∣B)=A发生的事务数A,B同时发生的事务数
3.最小支持度和最小置信度是通过专家给出的,同时满足小于最小支持度阈值和最小置信度阈值的规则称为强规则。
4 通过计算1.和2.中的支持度和置信度,与给定的最小支持度阈值和最小置信度阈值比较可判断该规则是否为强规则。
5 频繁项集
如果项集I的相对支持度<给定的最小支持度阈值,则称I是频繁项集
1.列出所有可能的项集
2.剪枝,将子集不是频繁项集的项集剔除
3.计算剪枝后的项集的支持度,去除<最小支持度阈值的项集
采取餐饮业实例,总共有10个订单,订单数据中包括客户序号和菜品id,a表示健康麦香包,b是排骨粥,c是豆浆,d是燕麦包,e是炒河粉。
txt数据如下(注:数据中没有客户序号):
a c e
b d
b c
a b c d
a b
b c
a b
a b c e
a b c
a c e
代码有两个.py文件,一个是自定义的apriori1算法,一个apriori实现的代码。
1.apriori1算法
# -*- 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) # 结果整理,输出
print(u'\n结果为:')
print(result)
return result
2.apriori算法
#-*- coding: utf-8 -*-
#使用Apriori算法挖掘菜品订单关联规则
from __future__ import print_function
import pandas as pd
from apriori1 import * #导入自行编写的apriori函数
inputfile = 'E:/未来方向/《Python数据分析与挖掘实战》源数据和代码.(1)/Python数据分析与挖掘实战/chapter5/demo/data/menu_orders.xls'
outputfile = 'E:/未来方向/《Python数据分析与挖掘实战》源数据和代码.(1)/Python数据分析与挖掘实战/chapter5/demo/data/apriori_rules.xls' #结果文件
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.values) #用map方式执行
print(b)
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) #保存结果
以第一条输出结果解释:客户同时点菜品e的同时点菜品a的概率为30%,先点菜品e,再点菜品a的概率为100%。
参考书目:《python数据分析与挖掘实战》 张良均.机械工业出版社
该书中代码有些错误,可能是python版本等原因导致,本文中代码是本人调试后的版本。