关联规则(Association Rules)是反映一个事物与其他事物之间的相互依存性和关联性,是数据挖掘的一个重要技术,用于从大量数据中挖掘出有价值的数据项之间的相关关系。
常见的购物篮分析
该过程通过发现顾客放人其购物篮中的不同商品之间的联系,分析顾客的购买习惯。通过了解哪些商品频繁地被顾客同时购买,这种关联的发现可以帮助零售商制定营销策略。其他的应用还包括价目表设计、商品促销、商品的排放和基于购买模式的顾客划分。
可从数据库中关联分析出形如“由于某些事件的发生而引起另外一些事件的发生”之类的规则
常用的频繁项集的评估标准有支持度,置信度和提升度三个
原理:如果一个项集是频繁项集,则它的所有子集都是频繁项集
如果一个集合不是频繁项集,则它的所有父集(超集)都不是频繁项集
关联分析的目标:
Apriori算法采用了迭代的方法
下图来自博客:https://www.cnblogs.com/pinard/p/6293298.html
输入:数据集合D,支持度阈值αα
输出:最大的频繁k项集
1)扫描整个数据集,得到所有出现过的数据,作为候选频繁1项集。k=1,频繁0项集为空集。
2)挖掘频繁k项集
a) 扫描数据计算候选频繁k项集的支持度
b) 去除候选频繁k项集中支持度低于阈值的数据集,得到频繁k项集。如果得到的频繁k项集为空,则直接返回频繁k-1项集的集合作为算法结果,算法结束。如果得到的频繁k项集只有一项,则直接返回频繁k项集的集合作为算法结果,算法结束。
c) 基于频繁k项集,连接生成候选频繁k+1项集。
3) 令k=k+1,转入步骤2。
# Apriori算法
"""
由于Apriori算法假定项集中的项是按字典序排序的,而集合本身是无序的,所以我们在必要时需要进行set和list的转换;
由于要使用字典(support_data)记录项集的支持度,需要用项集作为key,而可变集合无法作为字典的key,因此在合适时机应将项集转为固定集合frozenset。
支持度
置信度
"""
class apriori_algorithm:
# 算法初始化
def __init__(self, minSupport, dataSet):
self.minSupport = minSupport # 最小支持度
self.dataSet = dataSet # 数据集
# 加载数据集
def loaddata(self):
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
# 生成单个物品的项集列表
def generateC1(self, dataSet):
C1 = [] # 用于存放生成的单个物品的项集列表
# 遍历数据集
for data in dataSet:
for item in data:
if [item] not in C1:
C1.append([item])
C1.sort()
return C1
# 遍历数据集,和Ck对比,计数
def generateLk_by_Ck(self, dataSet, Ck, minSupport, support_data):
"""
Generate Lk by executing a delete policy from Ck.
Args:
data_set: 数据集
Ck: A set which contains all all frequent candidate k-itemsets.
min_support: The minimum support.
support_data: A dictionary. The key is frequent itemset and the value is support.
Returns:
Lk: A set which contains all all frequent k-itemsets.
"""
D = map(set, dataSet)
C = map(frozenset, Ck)
C1 = list(C) # 关于map对象的遍历,在内循环中遍历完最后一个元素后,再次访问时会放回空列表,所以外循环第二次进入的时候是空的,需要将其转为list处理
countData = dict()
for d in D: # set遍历
for c in C1:
if c.issubset(d): # 子集判断,并非元素判断
if c not in countData.keys(): # 将集合作为字典的键使用,c为[]型
countData[c] = 1
else:
countData[c] += 1
numItems = float(len(list(dataSet)))
returnList = []
supportData = dict()
# 遍历前面得到的计数字典
for key in countData:
support = countData[key] / numItems
if support >= minSupport:
returnList.insert(0, key) # insert() 函数用于将指定对象插入列表的指定位置
support_data[key] = support
return returnList
def generate_L(self, dataSet, k, min_support):
"""
Generate all frequent itemsets.
Args:
data_set:数据集
k: 频繁项集中含有的最多的元素
min_support: 最小支持度
Returns:
L: 出现的所有频繁项集
support_data: 每个频繁项集对应的支持度
"""
support_data = {}
C1 = self.generateC1(dataSet)
L1 = self.generateLk_by_Ck(dataSet, C1, min_support, support_data)
Lksub1 = L1.copy()
L = []
L.append(Lksub1)
for i in range(2, k + 1):
Ci = self.generateCK(Lksub1, i)
Li = self.generateLk_by_Ck(dataSet, Ci, min_support, support_data)
Lksub1 = Li.copy()
L.append(Lksub1)
return L, support_data
# generateCK 候选频繁项集产生 参数 Lk频繁项集,k:项集元素个数
def generateCK(self, Lk, k):
Ck = set()
len_Lk = len(list(Lk))
list_Lk = list(Lk)
for i in range(len_Lk):
for j in range(1, len_Lk):
l1 = list(list_Lk[i])
l2 = list(list_Lk[j])
l1.sort()
l2.sort()
if l1[0:k - 2] == l2[0:k - 2]:
Ck_item = list_Lk[i] | list_Lk[j]
if self.isCk(Ck_item, list_Lk):
Ck.add(Ck_item)
# Ck.add(Ck_item)
return Ck
# 频繁项集判断
def isCk(self, Ck_item, list_Lk):
for item in Ck_item:
sub_Ck = Ck_item - frozenset([item])
if sub_Ck not in list_Lk:
return False
return True
# 生成关联规则
def generate_big_rules(self, L, support_data, min_conf):
"""
Generate big rules from frequent itemsets.
Args:
L: 所有频繁项集的列表
support_data: 每个频繁项集对应的支持度
min_conf: 最小可信度
"""
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):
conf = support_data[freq_set] / support_data[freq_set - sub_set]
big_rule = (freq_set - sub_set, sub_set, conf)
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)
sub_set_list.append(freq_set)
return big_rule_list
if __name__ == '__main__':
minS = 0.5
dataSet = [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
apriori = apriori_algorithm(minSupport=minS, dataSet=dataSet)
L, support_data = apriori.generate_L(dataSet, 3, minS)
print(L)
print(support_data)
big_rule_list = apriori.generate_big_rules(L, support_data, 0.7)
结果:
所有的频繁项集L:
[[frozenset({5}), frozenset({2}), frozenset({3}), frozenset({1})], [frozenset({2, 5}), frozenset({2, 3}), frozenset({3, 5}), frozenset({1, 3})], [frozenset({2, 3, 5})]]
所有频繁项集对应的支持度:
{frozenset({1}): 0.5, frozenset({3}): 0.75, frozenset({2}): 0.75, frozenset({5}): 0.75, frozenset({1, 3}): 0.5, frozenset({3, 5}): 0.5, frozenset({2, 3}): 0.5, frozenset({2, 5}): 0.75, frozenset({2, 3, 5}): 0.5}
生成关联规则:
frozenset({2}) => frozenset({5}) conf: 1.0
frozenset({5}) => frozenset({2}) conf: 1.0
frozenset({1}) => frozenset({3}) conf: 1.0
frozenset({2, 3}) => frozenset({5}) conf: 1.0
frozenset({3, 5}) => frozenset({2}) conf: 1.0
参考文献:
https://www.jianshu.com/p/469dff109fae,
https://www.cnblogs.com/pinard/p/6293298.html,
https://www.cnblogs.com/llhthinker/p/6719779.html