Apriori算法: 关联分析
Apriori算法概览
什么是关联分析?
找出大规模数据集中寻找物品间的隐含关系
Apriori算法: 创建函数频繁项集高效发现的函数,从而从频繁项集中抽取关联规则
- Apriori算法的优缺点
优点: 易编码实现
缺点: 在数据集上较慢
使用数据类型: 数值型或者标称型
关联分析关键词:
- 频繁项集: 经常一起出现
- 关联规则: 暗示两种物品之间可能存在很强的关系
如何量化频繁项集?频繁项集是指那些经常出现在一起的物品
答:引入: 支持度和可信度—
- 支持度:数据集中包含该项集的记录所占的比例
- 可信度或置信度: 针对一条关联规则定义来进行定义的
例如:某个集合或某个元素集合—>推导出另一个元素
假设:定义一条关联规则 {豆奶 莴笋} —> {莴笋} 意味着: 购买豆奶的同时,购买莴笋的概率也大 但是反之不成立 —-在逻辑上称为 前件–>后件
可信度规则量化: support(p|H) / supprot(P)
Apriori算法–频繁项集
Apriori算法是发现频繁项集的一种方法
Apriori算法的两个参数分别为最小支持度和数据集
算法思路:
step1: 首先生成单个物品的项集列表
step2: 接着扫描交易记录来查看哪些项集满足最小支持度要求 将那些不满足最小支持度的项集会被去掉
step3: 然后对剩下来的集合进行组合以生成包含两个元素的项集, 重新扫描交易记录,去掉不满足最小支持度的项集
step4: 该过程重复进行直到所有项集都被去掉
伪代码
当集合中的个数大于0时
构建一个k项组成的候选项集
检查数据以确认每个项集都是频繁的
保留频繁项集并构建k+1项组成的候选项集列表
返回 满足支持度的所有频繁项集与其支持(字典形式) 以及 满足支持度的所有频繁项集(列表形式)
具体实现
def load_data():
"""
加载数据集
:return:
"""
return [[1, 3, 4], [2, 3, 5], [1, 2, 3, 5], [2, 5]]
def single_set(data_set):
"""
生成单个物品的频繁项集
:param data_set:
:return:
"""
single_list = list()
for i in data_set:
for j in i:
if [j] not in single_list:
single_list.append([j])
single_list.sort()
return map(frozenset, single_list)
def calc_support(data_set, single_list, limit_support=0.5):
"""
计算项集的支持度 去掉不满足最小支持度的项集
:param data_set: 数据集
:param single_list: 单个项集'物品'
:param limit_support: 最小支持度
:return
frequent_to_rate_dict
frequent_list
"""
frequent_to_rate_dict = dict()
frequent_list = []
m = len(data_set)
for i in single_list:
# print(i)
count = 0
for j in data_set:
# print(j)
if i.issubset(j):
count += 1
# print('count', count)
# print('divide count m', count/m)
if (count/m) >= limit_support:
frequent_to_rate_dict[i] = count/m
frequent_list.append(i)
# print('frequent_to_rate_dict', frequent_to_rate_dict)
# print('frequent_list', frequent_list)
return frequent_to_rate_dict, frequent_list
def build_items(support_list, k):
"""
构建一个k项的候选项集
:param support_list: 频繁项集
:param k: k个项
:return:
candidate_list 候选项集
"""
range_list = len(support_list)
# print('range_list', range_list)
candidate_list = list()
# print('support_list', support_list)
# print('xxxxx', support_list[0])
for i in range(range_list):
# print('i', i)
for j in range(i+1, range_list):
if type(support_list[i]).__name__ == 'frozenset' and type(support_list[j]).__name__ == 'frozenset':
# print('support_list[i]', support_list[i])
# print('support_list[j]', support_list[j])
union_set = support_list[i] | (support_list[j]) # | 并集
# print('union_set', union_set, len(set(union_set)))
if union_set not in candidate_list and len(union_set) == k:
candidate_list.append(union_set)
# print('candidate_list', candidate_list)
# print('result candidate list', candidate_list)
return candidate_list
def apriori(data_set, min_support=0.5):
"""
Apriori 算法---频繁项集
检查数据以确认每个项集都是频繁的
保留频繁项集并构建k+1项组成的候选项集的列表
:param data_set: 数据集
:param min_support: 最小支持度
:return:
frequent_to_rate_dict 满足支持度的所有频繁项集与其支持度
frequent_list 满足支持度的所有频繁项集
"""
base_list = single_set(data_set)
frequent_to_rate_dict, frequent_list = calc_support(data_set, base_list, min_support)
frequent_lists = [frequent_list]
k = 2
# print('frequent_lists[k-2]', frequent_lists[k-2])
while len(frequent_lists[-1]) > 0:
candidate_list = build_items(frequent_lists[-1], k)
frequent_to_rate_dict1, frequent_list1 = calc_support(data_set, candidate_list, min_support)
# print('frequent_to_rate_dict1', frequent_to_rate_dict1)
# print('frequent_list1', frequent_list1)
frequent_to_rate_dict.update(frequent_to_rate_dict1)
if len(frequent_list1) == 0:
break
frequent_lists.append(frequent_list1)
k += 1
return frequent_to_rate_dict, frequent_lists
Apriori算法–关联规则
关联规则:support(p|H) / supprot(P)
目前已知: 频繁项集与 频繁项集对应的支持度
求关联规则
关联规则— 多个物品对少个物品之间关系的描述
因此分情况讨论:
(1)当频繁项集中元素len=2
{2个物品}与{1个物品}之间的关联规则
可以直接计算置信度(可信度)
(2)当频繁项集中元素len>2
{3个物品}与{1个物品}
{3个物品}与{2个物品}
因此,此时需要不断递归出候选项集
再计算置信度(可信度)
Apriori算法–关联规则 算法实现
def generate_rules(frequent_to_rate_dict, frequent_lists, min_conf=0.7):
"""
关联规则生成函数
:param frequent_to_rate_dict: 满足支持度的所有频繁项集与其支持度
:param frequent_lists: 满足支持度的所有频繁项集
:param min_conf: 最小可信度设置
:return:
rule_lists 关联规则列表
"""
rule_lists = list()
for i in range(1, len(frequent_lists)):
for frequent_set in frequent_lists[i]:
print('frequent_set', frequent_set)
items = [frozenset([i]) for i in frequent_set] # 从频繁项集中拆解出单个的项
print('items', items)
if i > 1:
rules_from_consequent(frequent_set, items, frequent_to_rate_dict, rule_lists, min_conf)
else:
calc_conf(frequent_set, items, frequent_to_rate_dict, rule_lists, min_conf)
print('rule_lists func', rule_lists)
return rule_lists
def calc_conf(frequent_set, items, frequent_to_rate_dict, rule_lists, min_conf):
"""
可信度计算
:param frequent_set: 频繁项集中的元素
:param items: 频繁项集中的元素的集合
:param frequent_to_rate_dict: 所有元素的支持度字典
:param rule_lists: 关联规则列表的空数组
:param min_conf: 最小可信度
:return:
conf_list 记录 可信度大于阈值的集合
"""
conf_list = list()
for conseq in items:
# print('conseq', conseq, 'frequent_set', frequent_set)
conf = frequent_to_rate_dict[frequent_set] / frequent_to_rate_dict[conseq]
# print('conf', conf)
if conf >= min_conf:
print('frequent_set', frequent_set, '>>>>', 'conseq', conseq, conf)
print('conf', conf)
rule_lists.append((frequent_set, conseq, conf))
conf_list.append(conseq)
return conf_list
def rules_from_consequent(frequent_set, items, frequent_to_rate_dict, rule_lists, min_conf=0.7):
"""
生成候选规则集合
:param frequent_set: 频繁项集中的元素
:param items: 频繁项集中的元素的集合
:param frequent_to_rate_dict: 所有元素的支持度的字典
:param rule_lists: 关联规则列表的数组
:param min_conf: 最小可信度
"""
m = len(items[0])
# print('m', m)
# print('len(frequent_set)', len(frequent_set))
if len(frequent_set) > (m + 1):
hmp1 = build_items(items, m+1)
print('hmp1', hmp1)
hmp1 = calc_conf(frequent_set, hmp1, frequent_to_rate_dict, rule_lists, min_conf)
if len(hmp1) > 1:
print('应该继续迭代')
rules_from_consequent(frequent_set, hmp1, frequent_to_rate_dict, rule_lists, min_conf)
def main():
data_set = load_data()
# single_list = single_set(data_set)
# print('single list', single_list)
# for i in single_list:
# print(i, type(i))
# if i.issubset([1, 2, 3]):
# print('True')
# print('False')
# frequent_to_rate_dict, frequent_list = calc_support(data_set, single_list)
# candidate_list = build_items(frequent_list, k=2)
# print('候选集项', candidate_list)
frequent_to_rate_dict, frequent_list = apriori(data_set, min_support=0.5) # 至此找出了频繁项集
print('frequent_to_rate_dict', frequent_to_rate_dict, 'length', len(frequent_to_rate_dict))
print('frequent_list', frequent_list)
rule_list = generate_rules(frequent_to_rate_dict, frequent_list, min_conf=0.7)
print('rule_list', rule_list)
if __name__ == '__main__':
main()
Apriori算法 概念以及解释
- 项与项集: 设 itemsetitem1,item2,...,itemm是所有项的集合,其中,itemk(k=1,2,...m)成为项。项的集合称为项集(itemset),包含k个项的项集称为k项集 i t e m s e t i t e m 1 , i t e m 2 , . . . , i t e m m 是 所 有 项 的 集 合 , 其 中 , i t e m k ( k = 1 , 2 , . . . m ) 成 为 项 。 项 的 集 合 称 为 项 集 ( i t e m s e t ) , 包 含 k 个 项 的 项 集 称 为 k 项 集
- 事务与事务集:一个事务T是一个项集,它是itemset的一个子集,每个事务均与一个唯一标识符号Tid相联系,不同的事务一起组成了事务集D,构成了关联规则发现的事务数据库
- 关联规则:关联规则是形如A=>B的蕴含式,其中A、B均为itemset的子集且均不为空集,而A交B为空
- 支持度:数据集中包含该项集的记录所占的比例
实质上: support(A=>B)=P(A∪B) s u p p o r t ( A => B ) = P ( A ∪ B )
其中 P(A∪B)表示事务包含集合A和B的并(即包含A和B中的每个项)的概率,注意P(AorB)区别,后者表示事务包含A或B的概率 P ( A ∪ B ) 表 示 事 务 包 含 集 合 A 和 B 的 并 ( 即 包 含 A 和 B 中 的 每 个 项 ) 的 概 率 , 注 意 P ( A o r B ) 区 别 , 后 者 表 示 事 务 包 含 A 或 B 的 概 率 - 置信度: 实质上就是事件A发生时,B发生的概率
confidence(A=>B)=P(B|A)=support(A∪B)support(A) c o n f i d e n c e ( A => B ) = P ( B | A ) = s u p p o r t ( A ∪ B ) s u p p o r t ( A ) - 频繁项集: 如果项集I的相对支持度满足事先定义好的最小支持度阈值(即I的出现频度大于相应的最小出现频度),则I是频繁项集 如 果 项 集 I 的 相 对 支 持 度 满 足 事 先 定 义 好 的 最 小 支 持 度 阈 值 ( 即 I 的 出 现 频 度 大 于 相 应 的 最 小 出 现 频 度 ) , 则 I 是 频 繁 项 集
强关联规则:满足最小支持度和最小置信度的关联规则,即待挖掘的关联规则
剪枝策略:预先剪枝 —- 对不满足最小支持度的项集不予考虑,直接删除
参考文献
《机器学习实战》
《数据挖掘:概念与技术》