基础概念:
频繁项集: 如果项集I 的相对支持度满足预定义的最小支持度阈值,则I 是频繁项集。
先验性质:频繁项集的所有非空子集也一定是频繁的。
Apriori算法使用一种称为逐层搜索的迭代方法,其中k项集用于搜索(k+1)项集。首先,通过扫描数据库,累计每个项的个数,并收集满足最小支持度的项,找出频繁1项集的集合。该集合记为L1,。然后,使用L1,通过连接、剪枝两步走,找到频繁2项集的集合L2,使用L2找到L3,如此下去,直到不能再找出频繁k项集。
连接步:为找出Lk,通过将L(k-1)与自身连接产生候选k项集的集合Ck。 前提:项集中的项按字典序排序,前k-2个项相同。
剪枝步:使用先验性质,如果一个候选k项集的(k-1)项子集不在L(k-1)中,则该候选也不可能是频繁的,可以从Ck中删除。
简单来说,
1、发现频繁项集,过程为(1)扫描(2)计数(3)比较(4)产生频繁项集(5)连接、剪枝,产生候选项集 重复步骤(1)~(5)直到不能发现更大的频集
2、直接由频繁项集产生强关联规则(满足最小支持度和最小置信度):
a、对于每个频繁项集 l,产生 l 的所有非空子集。
b、对于 l 的每个非空子集s,如果 P(l - s | s ) >= 最小置信度,则输出规则 s ⇒ (l - s)。
算法过程(伪代码):
伪代码描述:
// 找出频繁 1 项集
L1 =find_frequent_1-itemsets(D);
For(k=2;Lk-1 !=null;k++){
// 产生候选,并剪枝
Ck =apriori_gen(Lk-1 );
// 扫描 D 进行候选计数
For each 事务t in D{
Ct =subset(Ck,t); // 得到 t 的子集
For each 候选 c 属于 Ct
c.count++;
}
//返回候选项集中不小于最小支持度的项集
Lk ={c 属于 Ck | c.count>=min_sup}
}
Return L= 所有的频繁集;
第一步:连接(join)
Procedure apriori_gen (Lk-1 :frequent(k-1)-itemsets)
For each 项集 l1 属于 Lk-1
For each 项集 l2 属于 Lk-1
If( (l1 [1]=l2 [1])&&( l1 [2]=l2 [2])&& ……&& (l1 [k-2]=l2 [k-2])&&(l1 [k-1]<l2 [k-1]) )
then{
c = l1 连接 l2 // 连接步:产生候选
//若k-1项集中已经存在子集c则进行剪枝
if has_infrequent_subset(c, Lk-1 ) then
delete c; // 剪枝步:删除非频繁候选
else add c to Ck;
}
Return Ck;
第二步:剪枝(prune)
Procedure has_infrequent_sub (c:candidate k-itemset; Lk-1 :frequent(k-1)-itemsets)
For each (k-1)-subset s of c
If s 不属于 Lk-1 then
Return true;
Return false;
模型评估:
提升度:项集A的出现独立于项集B的出现,如果P(A∪B)= P(A)P(B);否则,作为事件,项集A和B是依赖的和相关的。
如果上述公式的值小于1,则A的出现与B的出现是负相关的。如果大于1,则A和B是正相关的,以为一个出现可能导致另一个也出现。
算法优缺点:
优点:使用先验性质,大大提高了频繁项集逐层产生的效率;简单易理解;数据集要求低。
缺点:1、候选频繁K项集数量巨大。2、在验证候选频繁k项集的时候需要对整个数据库进行扫描,非常耗时。
算法优化:
1、基于散列的技术(散列项集到对应的桶中),显著压缩需要考虑的k项集,特别是k=2时。
2、事务压缩(压缩进一步迭代扫描的事务数),不包含任何频繁k项集的事务可以删除或标记。
3、划分(为找候选项集划分数据),两次数据库扫描,局部频繁项集的扫描形成全局频繁项集。
4、抽样(对给定数据的一个子集上挖掘),牺牲了精度换取了有效性。
5、动态项集计数(在扫描的不同点添加候选项集),如果一个候选项集已经满足最少支持度,则在可以直接将它添加到频繁项集,而不必在这次扫描的以后对比中继续计算。
6、在逐层搜索循环过程的第k步中,在产生k-1维频繁项目集时,我们可以实现对该集中出现元素的个数进行计数处理,因此对某元素而言,若它的计数个数不到k-1的话,可以事先删除该元素,从而排除由该元素将引起的大规格所有组合。
7、FP-growth算法,只进行2次数据库扫描且它不使用侯选集,直接压缩数据库成一个频繁模式树,最后通过这棵树生成关联规则。
案例分析:
从某一食品杂货店一个月的真实交易数据(9835条交易和169个项)中,发掘消费者对于这些商品的购买行为之间是否有关联性,以及关联性有多强,并将获取的信息付诸于实际应用。
代码:
# install.packages("arules")
library(arules)
# data()
data("Groceries")
# 查看数据基本信息。
summary(Groceries)
# 数据类型
class(Groceries)
# 展示前10条购买记录
inspect(Groceries[1:10])
# 初次探查(minsup = 0.001,mincon = 0.5)
rules0 <- apriori(Groceries,
parameter = list(support = 0.001,confidence = 0.5))
# 观测rules0中前10条规则
inspect(rules0[1:10])
# 规则太多,强度控制(默认值:0.1,0.8)
rules1 <- apriori(Groceries) # 0 rules
# 1. 支持度、置信度共同控制
# (关注规则在总体的占比,则提供支持度;注重规则本身的可靠性,则多提高置信度)
rules2 <- apriori(Groceries,
parameter = list(support = 0.005,confidence = 0.5)) #120
rules3 <- apriori(Groceries,
parameter = list(support = 0.005,confidence = 0.60)) #22
rules4 <- apriori(Groceries,
parameter = list(support = 0.005,confidence = 0.64)) #4
inspect(rules4)
# 2. 仅控制支持度(按支持度排序)
rules.sorted_sup <- sort(rules0,by = "support")
inspect(rules.sorted_sup[1:5])
# 3. 仅控制置信度(按置信度降序)
rules.sorted_con <- sort(rules0,by = "confidence")
inspect(rules.sorted_con[1:5])
# 4. 提升度的控制 (最可靠的指标)
rules.sorted_lift <- sort(rules0,by = "lift")
inspect(rules.sorted_lift[1:5])
# 促销芥末
rules5 <- apriori(Groceries,parameter = list(maxlen = 2,support = 0.001,conf = 0.1),
appearance = list(rhs = "mustard",default = "lhs"))
inspect(rules5) # 蛋黄酱
# 销量最高的商品
itemsets_apr <- apriori(Groceries,parameter = list(supp = 0.001,target = "frequent itemsets"),
control = list(sort = -1))
inspect(itemsets_apr[1:5])
# 利用eclat()函数获取最适合捆绑销售的5对商品。
itemsets_ecl <- eclat(Groceries,parameter = list(minlen = 1,maxlen = 3,supp = 0.001,
target = "frequent itemsets"),
control = list(sort = -1))
inspect(itemsets_ecl[1:5])
# 规则可视化
# install.packages("arulesViz")
library(arulesViz)
rules6 <- apriori(Groceries,parameter = list(support = 0.002,confidence = 0.5))
# 对规则做散点图
plot(rules6)
# 变换横纵坐标,及颜色条所对应的变量。
plot(rules6,measure = c("support","lift"), shading = "confidence")
# 互动获取具体规则
plot(rules6,interactive = T)
# 颜色条为order,规则包含商品种类。
plot(rules6,shading = "order",control = list(main = "Two-key plot"))
# 图形类型改为group
plot(rules6,method = "grouped")
参考文献: