关联规则挖掘最经典的例子就是购物篮分析。也就是根据顾客购买行为模式,分析出商品与商品之间的联系。比如买了炸鸡,和可能接下来去买啤酒。这对于商品的布局,库存安排以及商业推销都有很大帮助。
而我项目中也用到了关联规则算法,第一个是挖掘店铺和店铺之间的关系,第二个是挖掘店铺内商品与商品之间的关系。(这点我觉得分析意义不大,因为店铺内其实数据不大,种类也不是很多,挖掘的意义不大,但是领导有安排,咱就得做。不过对于超市来说还是非常有意义的。)
挖掘计算出来最终得到3个指标,还是以啤酒和尿布来解释,我看过网上很多对这三个概念的解释,很多人提升度基本上都解释错了。而且也只说明了支持度怎么计算,置信度,提升度根本就没有计算,也没有代码参考。
这里假如1000个消费者购买了商品,购买了尿布的人有800个,购买了啤酒的人有400个,同时购买了尿布和啤酒的人有200个。
这里要说明下,买啤酒>买尿布和买尿布>买啤酒是两种不同的情况,但是它们的支持度和提升度是一样的,置信度不一样。
支持度:同时购买了尿布和啤酒的人占比。200/1000=20%
置信度:
购买了尿布后购买啤酒的人占比。200/800=25%
购买了啤酒后购买尿布的人占比。200/400=50%
提升度:购买了尿布后购买啤酒的人占比(置信度)/购买啤酒的人占比 = 25%/40%=62.5%
购买了啤酒后购买尿布的人占比(置信度)/购买尿布的人占比 = 50%/80%=62.5%
至于我刚才说的结论为什么是这样,大家可以利用下面的公式推导一下。
支持度 | 假设存在关联规则A⇒B,此规则支持度为: support(A⇒B)=count(A⋃B)/|T|=P(A⋃B) |
置信度 | 假设存在关联规则A⇒B,此规则置信度为: confidence(A⇒B)=P(A⋃B)/P(A)=support(A⇒B)/support(A) |
提升度 | 假设存在关联规则A⇒B,此规则提升度为: Lift(A⇒B)=confidence(A⇒B)/support(B) |
说完基本概念(对fpgrwoth不知道是什么的先查查其他资料),这里再说下spark实现的fpgrowth做了什么。
spark提供的fpgrowth计算出了频繁项集,然后提供了一个generateAssociationRules方法,但是这个方法最后返回的rdd只有前后项以及置信度,真是想不通,为啥功能只做了一半,没有返回支持度和提升度。所以我们只能自己实现了。
自己实现的代码:
//计算出频繁项集
val model = new FPGrowth().
setMinSupport(minSupport).
setNumPartitions(numPartition).
run(data)
//计算出总量
val count = data.count()
//注解1
val modelFilter: RDD[FPGrowth.FreqItemset[String]] = model.freqItemsets.filter(_.items.length <= 2)
modelFilter.cache()
//注解2
val candidates = modelFilter.flatMap { itemset =>
val items = itemset.items
items.flatMap { item =>
items.partition(_ == item) match {
case (consequent, antecedent) if !antecedent.isEmpty =>
Some((antecedent.toSeq.head, (consequent.toSeq.head, itemset.freq)))
case _ => None
}
}
}
//注解3
val singleItmes: RDD[(String, Long)] = modelFilter.filter(_.items.length == 1).map( x =>(x.items.head,x.freq))
//注解4,计算出支持度,置信度,提升度
val result = candidates.join(singleItmes).map(x => (x._2._1._1,(x._1,x._2._1._2,x._2._2))).join(singleItmes)
//前项,后项,前项频繁值/总数=支持度,前后项频繁值/前项频繁值=置信度,前后项频繁值/前项频繁值/后项频繁值*总数=提升度
.map(x => (x._2._1._1,x._1,x._2._1._2.toDouble/ count,x._2._1._2.toDouble /x._2._1._3.toDouble,x._2._1._2.toDouble /x._2._1._3.toDouble/x._2._2.toDouble * count))
.filter(_._4 >= minConfidence)
.map(x => (x._1, x._2, f"${x._3}%.5f", f"${x._4}%.5f", f"${x._5}%.5f"))
modelFilter.unpersist()
result
代码说明:
这段代码的注解2是来自源码的AssociationRules.scala,主要是过滤掉前后项为空的数据。
注解1和注解3的代码都是我自己加的,大家可以自行选择是否需要。主要功能是频繁项集太多太多了。比如买了AB,可能买C的情况,买了ABD,可能买C的情况。而我添加的这段代码就是过滤出来A>B,A>C,也就是说我只考虑单项对单项的情况,不考虑复杂项的情况。
注解4就是核心代码了,计算支持度,置信度,提升度。计算的公式前面也给大家了,套进去就行了,每一项的说明我在代码里也都注释了。