先验算法(Apriori)
1.概述
在计算机科学以及数据挖掘领域中,先验算法(Apriori Algorithm)是关联规则学习的经典算法之一。
先验算法的设计目的是为了处理包含交易信息内容的数据库。例如,顾客购买的商品清单或者网页常访清单等。
先验算法采用广度优先搜索算法进行搜索并采用树结构来对候选项集进行高效计数。通过长度为k-1的候选项集来产生长度为k的候选项集,然后从中删除包含不常见子模式的候选项。根据向下封闭性引理,该候选项目集包含所有长度为k的频繁项目集。之后,就可以通过扫描交易数据库来决定候选项目集中的频繁项目集。
1.1 问题引入
啤酒与尿布的故事
有一个故事发生于20世纪90年代的美国超市中,超市管理人员分析销售数据时发现了一个令人难于理解的现象:在某些特定的情况下,“啤酒”与“尿布”两件看上去毫无关系的商品会经常出现在同一个购物篮中,这种独特的销售现象引起了管理人员的注意,经过后续调查发现,这种现象出现在年轻的父亲身上。
故事起因在美国有婴儿的家庭中,一般是母亲在家中照看婴儿,年轻的父亲前去超市购买尿布。父亲在购买尿布的同时,往往会顺便为自己购买啤酒,这样就会出现啤酒与尿布这两件看上去不相干的商品经常会出现在同一个购物篮的现象。
如果这个年轻的父亲在卖场只能买到两件商品之一,则他很有可能会放弃购物而到另一家商店,直到可以一次同时买到啤酒与尿布为止。
超市发现了这一独特的现象,开始在卖场尝试将啤酒与尿布摆放在相同的区域,让年轻的父亲可以同时找到这两件商品,并很快地完成购物。
这个故事是因为有数据分析的结果支持才会获得成功并得到广泛传播,通过分析购物篮中的商品集合数据,找出商品之间的关联关系,发现客户的购买行为,从而获得更多的商品销售收入。
1.2 基本概念
许多商业企业在日复一日的运营中积累了大量的数据。例如,食品商店的收银台每天都收集大量的顾客购物数据,其中,一位顾客一次购买商品的记录就是一条事务,称为购物篮事务(market basket transaction)。零售商对分析这些数据很感兴趣,以便了解他们的顾客的购买行为,可以使用这种有价值的信息来支持各种商务应用,如市场促销,库存管理和顾客关系管理等。
关联分析是用于发现隐藏在大型数据集中有意义的联系,所发现的联系可以用关联规则或频繁项集的形式表示。除了购物篮数据外,关联分析也可以应用于其他领域,如生物信息学、医疗诊断、网页挖掘和科学数据分析等。
在对购物篮数据进行关联分析时,需要处理两个关键的问题:第一,从大型事务数据集中发现模式可能在计算上要付出很高的代价;第二,所发现的某些模式可能是虚假的,因为它们可能是偶然发生的。
项集:在关联分析中,包含0个或多个项的集合被称为项集。
频繁项集(frequent item sets):集合内商品数量大于阈值的项集,经常出现在一块的物品的集合。
关联规则(associational rules):形如X⟶Y的蕴含表达式,其中X和Y是不相交的项集,即X∩Y=∅,暗示两种物品之间可能存在很强的关系。
支持度(support):确定规则可以用于给定数据集的频繁程度。
置信度(confidence):确定Y在包含X的事务中出现频繁程度。
提升度(lift): 置信度除以规则后件Y的支持度(引入这个指标的原因是置信度忽视了规则后件带来的影响,也就是说置信度很高可能仅仅是因为规则后件支持度很高造成的,该规则可能没有实际意义)。
**K项集 **:如果事件A中包含k个元素,那么称这个事件A为k项集,并且事件A满足最小支持度阈值的事件称为频繁k项集。
规则的产生:其目标是从上一步发现的频繁项集中提取所有高置信度的规则,这些规则称作强规则。
获取候选K频繁项集
通常采取合并K-1频繁项集的方法来获得K频繁项集。
1.合并:由于频繁项集是有序的,所以若两个K-1频繁项集的前K-2个相同,则考虑合并。
2.剪枝:合并后。只能确定原来的两个K-1项集是频繁的。还需要根据先验原理,检验K项集是否频繁。即逐个判定该K项集的子K-1项集是否频繁。
产生规则
一个K频繁项可以产生多个规则。同样,需要根据先验原理,去除置信度低于阈值的规则。(频繁项集产生的规则必定满足支持度,故无需考虑支持度)
初始化候选规则,即规则前件含有K-1个项
依次计算候选规则的置信度,大于阈值则存储规则,反之抛弃。
根据上一轮规则集合,合并前件产生新一轮的候选规则, 转步骤2。直到候选规则为空。
2.算法实现
2.1 算法思想
- 首先找出所有的频集,这些项集出现的频繁性至少和预定义的最小支持度一样。
- 然后由频集产生强关联规则,这些规则必须满足最小支持度和最小可信度。
- 然后使用第1步找到的频集产生期望的规则,产生只包含集合的项的所有规则。一旦这些规则被生成,那么只有那些大于用户给定的最小可信度的规则才被留下来。
2.2 算法过程
第一步:通过迭代,检索出事务数据库中的所有频繁项集,即支持度不低于用户设定的阈值的项集;
第二步:利用频繁项集构造出满足用户最小信任度的规则。
- 具体做法就是:首先找出频繁1-项集,记为L1;
- 然后利用L1来产生候选项集C2,对C2中的项进行判定挖掘出L2,即频繁2-项集;
- 不断如此循环下去直到无法发现更多的频繁k-项集为止。每挖掘一层Lk就需要扫描整个数据库一遍。
- 算法利用了一个性质:任一频繁项集的所有非空子集也必须是频繁的。
2.3 算法原理
假设我们一共有 4 个商品: 商品0, 商品1,商品2, 商品3。
所有可能的情况如下:如果我们计算所有组合的支持度,需要计算 15 次。随着物品的增加,计算的次数将呈指数增长 。若使用Apriori 原理,即某个项集是频繁的,那么它的所有子集也是频繁的。能得到,如果 {0, 1} 是频繁的,那么 {0}, {1} 也是频繁的。反之,如果一个项集是非频繁项集,那么它的所有超集也是非频繁项集,如上图所示。
假设已知 {2,3} 是 非频繁项集,那么{0,2,3} {1,2,3} {0,1,2,3} 都是 非频繁的。 也就是说,计算出 {2,3} 的支持度,知道它是非频繁的之后,就不需要再计算 {0,2,3} ,{1,2,3} ,{0,1,2,3} 的支持度,因为我们知道这些集合不会满足我们的要求。 使用该原理就可以避免项集数目的指数增长,从而在更短更合理的时间内计算出频繁项集。
2.4 算法优缺点
优点
- 易于理解、易于在大型数据集上实现 。
缺点
-
需要扫描整个数据集,对计算能力要求高,如果是大型数据集,计算会十分耗时。
-
适用数据类型:数值型或者标准型数据。
2.5 实例
假设有4000个客户交易,然后我们计算两种产品的Support、Confidence 和 Lift,比如说饼干和巧克力,因为客户经常一起购买这两种商品。在 4000 笔交易中,其中400笔包含饼干,而其中600笔包含巧克力,这600笔交易中包括200笔包含饼干和巧克力的交易。使用这些数据,我们将找出支持度、置信度和提升度:
支持度(饼干) = (饼干) / (总交易) = 400/4000 = 10%
置信度 = (饼干和巧克力) / (饼干) = 200/400 = 50%,这意味着 50% 的购买饼干的顾客也购买了巧克力。
提升度 = (置信度 (饼干和巧克力)/ (支持度(饼干) = 50/10 = 5
这意味着人们同时购买饼干和巧克力的概率是单独购买饼干的概率的五倍。如果提升度低于 1,则人们不太可能同时购买这两种物品。 值越大,组合一起被购买的几率越大。
2.6 python实现
案例一
本案例是使用超市的销售记录作为数据集。
代码
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#读取数据
Data = pd.read_csv(r'C:\Users\我的电脑\OneDrive\桌面\AlgorithmDebugging\FrequentPattern\数据\Market_Basket_Optimisation.csv', header = None)
#print(Data)
#转换为列表
# Intializing the list
transacts = []
# populating a list of transactions
for i in range(0, 7501):
transacts.append([str(Data.values[i,j]) for j in range(0, 20)])
#训练先验模型
from apyori import apriori
rule = apriori(transactions = transacts, min_support = 0.003, min_confidence = 0.2, min_lift = 3, min_length = 2, max_length = 2)
#可视化结果
output = list(rule) # returns a non-tabular output
# putting output into a pandas dataframe
def inspect(output):
lhs = [tuple(result[2][0][0])[0] for result in output]
rhs = [tuple(result[2][0][1])[0] for result in output]
support = [result[1] for result in output]
confidence = [result[2][0][2] for result in output]
lift = [result[2][0][3] for result in output]
return list(zip(lhs, rhs, support, confidence, lift))
output_DataFrame = pd.DataFrame(inspect(output), columns = ['Left_Hand_Side', 'Right_Hand_Side', 'Support', 'Confidence', 'Lift'])
#print(output_DataFrame)
# 按Lift列降序排列的结果
Lift = output_DataFrame.nlargest(n = 10, columns = 'Lift')
print(Lift)
结果
未排序结果:
按Lift列降序排列的结果:
案例二
通过Apriori算法进行关联规则挖掘,分析出导演一般喜欢哪些演员,哪个演员一般和哪个演员在一块演电影。
相关数据是从豆瓣电影上爬取的,此次我爬取了张艺谋导演和宁浩导演的电影,爬取的电影截图如下:
代码
from efficient_apriori import apriori
import csv
director = '宁浩'
file_name = 'C:/Users/我的电脑/OneDrive/桌面/AlgorithmDebugging/FrequentPattern/Apriori/webcrawler/'+director+'.csv'
lists = csv.reader(open(file_name, 'r', encoding='utf-8-sig'))
# 数据加载
data = []
for names in lists:
name_new = []
for name in names:
# 去掉演员数据中的空格
name_new.append(name.strip())
data.append(name_new[1:]) # 去掉电影名, 加入列表
# 挖掘频繁项集和关联规则
itemsets, rules = apriori(data, min_support=0.3, min_confidence=0.8)
print(itemsets)
print(rules)
from efficient_apriori import apriori
import csv
file_name = 'C:/Users/我的电脑/OneDrive/桌面/AlgorithmDebugging/FrequentPattern/Apriori/webcrawler/张艺谋.csv'
lists = csv.reader(open(file_name,'r',encoding='utf-8-sig'))
#数据加载
data = []
for names in lists:
data.append(names[1:])
#挖掘频繁项集和关联规则
itemesets,rules = apriori(data,min_support=0.1,min_confidence=1)
print(itemesets)
print(rules)
结果
在我爬取的宁浩导演的数据中,徐峥一共单独出现6次,黄渤一共单独出现7次,(徐峥,黄渤)组合一共出现6次,它认为黄渤对徐峥的出现有帮助,徐峥对黄渤的出现也有帮助。
在我爬取的张艺谋导演的数据中,巩俐单独出现9次,李雪健单独出现5次。