简介
Apriori是一种流行的算法,用于在关联规则学习中提取频繁项集。Apriori算法被设计用于对包含交易的数据库进行操作,例如商店客户的购买。如果项目集满足用户指定的支持阈值,则该项目集被视为“频繁”。例如,如果支持度阈值设置为0.5(50%),则频繁项目集被定义为在数据库中所有事务的至少50%中一起发生的项目集合
定义
支持度(support):support(A=>B) = P(A∪B),表示A和B同时出现的概率。
置信度(confidence):confidence(A=>B)=support(A∪B) / support(A),表示A和B同时出现的概率占A出现概率的比值。
频繁项集:在项集中频繁出现并满足最小支持度阈值的集合,例如{牛奶,面包}、{手机,手机壳}等。
强关联规则:满足最小支持度和最小置信度的关联规则。
算法步骤
- 从记录中计算所有的候选1项集,并计算频繁1项集及支持度。
- 由频繁1项集生成k项候选集,并由k项候选集计算k项频繁集。
- 用k项频繁集生成所有关联规则,计算生成规则置信度,筛选符合最小置信度的关联规则
频繁项挖掘
任一频繁项的所有非空子集也必须是频繁的。也就是当生成k项候选集的时候,如果候选集中的元素不在k-1项频繁集中,则该元素一定不是频繁集,这个时候不需要计算支持度,直接去除即可。
比如说我们有0,1,2,3组成的集合,下面是其所有的项集组合:
从1项集开始计算k项集的支持度,在2项集候选集中当我们计算出{0,1}集合是非频繁的,那么它的所有子集都是非频繁的,即2项集{0,1,2}和{0,1,3}也是非频繁的,它们的子集{0,1,2,3}同样是非频繁的,对于非频繁集我们就不需要去计算支持度。
当找出所有的频繁后需要从频繁集中挖掘所有的关联规则,假设频繁项集{0,1,2,3},下图表示其生成的所有关联规则,对于阴影部分的低可信度的规则,它们的子集同样也会是低可信度的。
Python实现
- 数据集
data = [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
- 创建初始候选集
这里使用frozenset不可变集合是为了后续计算支持度字典是将集合作为键
def apriori(data_set):
# 候选项1项集
c1 = set()
for items in data_set:
for item in items:
item_set = frozenset([item])
c1.add(item_set)
结果:{frozenset({2}), frozenset({3}), frozenset({1}), frozenset({5}), frozenset({4})}
- 从候选项集中选出频繁项集
如下图所以我们需要从初始的候选项集中计算k项频繁项集,所以这里封装函数用于每次计算频繁项集及支持度,当候选项集中集合中的每个元素都存在事务记录集合中是计数并保存到字典中,计算支持度后输出频繁项集和支持度
def generate_freq_supports(data_set, item_set, min_support):
freq_set = set() # 保存频繁项集元素
item_count = {} # 保存元素频次,用于计算支持度
supports = {} # 保存支持度
# 如果项集中元素在数据集中则计数
for record in data_set:
for item in item_set:
if item.issubset(record):
if item not in item_count:
item_count[item] = 1
else:
item_count[item] += 1
data_len = float(len(data_set))
# 计算项集支持度
for item in item_count:
if (item_count[item] / data_len) >= min_support:
freq_set.add(item)
supports[item] = item_count[item] / data_len
return freq_set, supports
- 生成新组合
由初始候选集会生成{1,2,3,5}的频繁项集,后续需要生成新的候选项集Ck
def generate_new_combinations(freq_set, k):
new_combinations = set() # 保存新组合
sets_len = len(freq_set) # 集合含有元素个数,用于遍历求得组合
freq_set_list = list(freq_set) # 集合转为列表用于索引
for i in range(sets_len):
for j in range(i + 1, sets_len):
l1 = list(freq_set_list[i])
l2 = list(freq_set_list[j])
l1.sort()
l2.sort()
# 项集若有相同的父集则合并项集
if l1[0:k-2] == l2[0:k-2]:
freq_item = freq_set_list[i] | freq_set_list[j]
new_combinations.add(freq_item)
return new_combinations
- 循环生成候选集频繁集
def apriori(data_set, min_support, max_len=None):
max_items = 2 # 初始项集元素个数
freq_sets = [] # 保存所有频繁项集
supports = {} # 保存所有支持度
# 候选项1项集
c1 = set()
for items in data_set:
for item in items:
item_set = frozenset([item])
c1.add(item_set)
# 频繁项1项集及其支持度
l1, support1 = generate_freq_supports(data_set, c1, min_support)
freq_sets.append(l1)
supports.update(support1)
if max_len is None:
max_len = float('inf')
while max_items and max_items <= max_len:
ci = generate_new_combinations(freq_sets[-1], max_items) # 生成候选集
li, support = generate_freq_supports(data_set, ci, min_support) # 生成频繁项集和支持度
# 如果有频繁项集则进入下个循环
if li:
freq_sets.append(li)
supports.update(support)
max_items += 1
else:
max_items = 0
return freq_sets, supports
- 生成关联规则
def association_rules(freq_sets, supports, min_conf):
rules = []
max_len = len(freq_sets)
# 生成关联规则,筛选符合规则的频繁集计算置信度,满足最小置信度的关联规则添加到列表
for k in range(max_len - 1):
for freq_set in freq_sets[k]:
for sub_set in freq_sets[k + 1]:
if freq_set.issubset(sub_set):
conf = supports[sub_set] / supports[freq_set]
rule = (freq_set, sub_set - freq_set, conf)
if conf >= min_conf:
rules.append(rule)
return rules
- 主程序
if __name__ == '__main__':
data = [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
L, support_data = apriori(data, min_support=0.5)
association_rules = association_rules(L, support_data, min_conf=0.7)
结果:
L:
support_data:
association_rules:
从频繁集中挖掘关联规则
关联规则来源于每一轮迭代中产生的频繁项集
关联规则的搜索一样可以遵循频繁项集的层次迭代搜索方法,即按照频繁项集的层次结构,进行逐层搜索
如果{0,1,2}➞{3}是一条低可信度规则,那么所有其他以3作为后件(箭头右部包含3)的规则均为低可信度的。即如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求。
反之,如果{0,1,3}->{2},则说明{2}这个频繁项作为后件,可以进入到下一轮的迭代层次搜索中,继续和本轮得到的规则列表的右部进行组合。直到搜索一停止为止