Spark的模式挖掘—FPGrowth算法

来源:互联网 发布:java优缺点 编辑:程序博客网 时间:2024/06/06 15:02

Spark的模式挖掘—FPGrowth算法

一、实验介绍

1.1 内容介绍

模式挖掘也叫关联规则,其实就是从大量的数据中挖掘出比较有用的数据,挖掘频繁项。比如说超市有大量的购物数据,从而可以根据用户的购物数据找到哪些商品关联性比较大。也可以进行用户推荐。下面我们说一个真实的案例。

我想可能有些同学一定听说过尿布和啤酒的故事吧。就是在一家超市里尿布和啤酒摆在一起出售。但是这个奇怪的举措却使尿布和啤酒的销量双双增加了。这不是一个笑话,而是发生在美国沃尔玛连锁店超市的真实案例,并一直为商家所津津乐道。沃尔玛拥有世界上最大的数据仓库系统,为了能够准确了解顾客在其门店的购买习惯,沃尔玛对其顾客的购物行为进行购物篮分析,想知道顾客经常一起购买的商品有哪些。沃尔玛数据仓库里集中了其各门店的详细原始交易数据。在这些原始交易数据的基础上,沃尔玛利用数据挖掘方法对这些数据进行分析和挖掘。一个意外的发现是:"跟尿布一起购买最多的商品竟是啤酒!经过大量实际调查和分析,揭示了一个隐藏在"尿布与啤酒"背后的美国人的一种行为模式:在美国,一些年轻的父亲下班后经常要到超市去买婴儿尿布,而他们中有30%~40%的人同时也为自己买一些啤酒。产生这一现象的原因是:美国的太太们常叮嘱她们的丈夫下班后为小孩买尿布,而丈夫们在买尿布后又随手带回了他们喜欢的啤酒。该节内容选在百度百科。

沃尔玛就是根据自己超市里面的售物数据,通过数据挖掘,这里指的就是关联规则算法分析,从而从大量的数据中找到了啤酒和尿布是最搭配的,然后他们就将两者放在一起出售,取得了较好的经济效应。可想而知,数据挖掘在现实生活中还是挺有用的吧。

1.2 实验知识点

  • Scala 基础编程
  • RDD的基本操作。Transformation和Actions
  • Spark Mlib的FPGrowth的算法应用

1.3 实验环境

  • Ubuntu14.04
  • Spark1.6.1
  • Xfce终端

1.4 适合人群

该项目难度一般,属于中等偏下难度,该项目适合有一定的Spark基础,对MLib有一定的了解,并热爱机器学习。

二、实验原理

通过将数据转换成需要的数据类型,然后将数据使用Mlib算法进行模式挖掘。在该实验中的数据格式是RDD[Array[String]],当然在Spark中还有其他的数据类型,比如说Vector,LabeledPoint,Matrix等数据类型。

2.1 实验流程图

此处输入图片的描述

2.2 算法详解

关联规则用于表示数据内隐藏的关联性。比如说上面说到的故事。啤酒和尿布湿的关系,买尿布湿的消费者往往也会买啤酒。这就表明了数据之间的某种隐藏联系。但是分开看两者没有任何联系。关联规则算法发展到现在一共有三个算法:FP-Tree算法、Apriori算法、Eclat算法,这三个算法我们主要是讲解FP-Tree算法。FP-Tree是一种不产生候选模式而采用频繁模式增长的方法挖掘频繁模式的算法;此算法只扫描两次,第一次扫描数据是得到频繁项集,第二次扫描是利用支持度过滤掉非频繁项,同时生成FP树。然后后面的模式挖掘就是在这棵树上进行。此算法与Apriori算法最大不同的有两点:不产生候选集,只遍历两次数据,大大提升了效率。

下面我们就来讲讲该算法的实现过程:

假设有这么一批数据:

此处输入图片的描述

第一次扫描数据得到频繁项集合,统计所有商品出现的次数:

此处输入图片的描述

假设最小支持度为3,那调整后的频繁项集合就是:

此处输入图片的描述

第二次遍历数据构建频繁项集合树:

此处输入图片的描述

FPTree建立的规则就是树的根,为根节点,ROOT,定义为NULL,然后将数据里面的每一条数据进行插入节点操作,每个节点包含一个名称,和一个次数的属性,例如上图的a:4,a就是Item中的名称,4代表的是出现的次数。如果插入新事务时,树中已经包含该节点,这不用创建树节点,直接在节点上的次数加一就行。

2.3 实验拓展

当然这只是个简单的项目,想要拓展的话,可以加上前端效果,进行效果展示,同理该算法也可以应用到其他的场景上,比如说书本推荐,博客推荐系统等等。

三、项目实现

3.1 进入开发环境

进入到实验环境,双击桌面上的Xfce,效果如下图

此处输入图片的描述

3.2 数据准备

下载Groceries.csv杂货店数据。在数据是在CSDN上面分享的免积分文件。下载地址为:http://download.csdn.net/detail/sanqima/9301589 数据我已经整理好上传到实验楼上了。Get地址为:http://labfile.oss.aliyuncs.com/courses/815/Groceries.txt

请输入以下代码获取数据集

wget http://labfile.oss.aliyuncs.com/courses/815/Groceries.txt

此处输入图片的描述

下载好数据后,我们看看里面的数据格式。在Linux中打开csv文件,查看该数据,如下图所示,这个csv文件包含9835条数据,下面我们就来介绍该数据文件,首先第一行items指的是标题栏是没有用的数据,其中{}中的数据,就是一次性购买的物品,每一行都有一个数字作为他的标签,在这里我们不将他作为行数标记,我们将他认为是用户ID,我们也可以针对某一用户进行商品推荐。

此处输入图片的描述

3.3 启动spark shell

请在终端中输入如下代码:

spark-shell

此处输入图片的描述

进入到spark的REPL环境,相当于就是spark的Console。

3.4 导入数据并转换数据

下面我们就进入到实验的关键位置,进行数据的导入,并进行必要的数据格式处理。将数据清洗成我们需要的数据格式。

3.4.1 导入数据

拓展:Spark textFile进行数据的导入,将外部数据导入到Spark中来,并将其转换成RDD。

键入如下命令:

val data = sc.textFile("file:////home/shiyanlou/Groceries.txt")

此处输入图片的描述

从图中我们可以看到我们引入了/home/shiyanlou下面的Groceries.txt文件。在最后我们也了解到了当前的数据格式为RDD[String]类型的数据。

现在我们可以看看当前data的数据样式。我们查看data的前十行数据。

拓展:这里使用到RDD Action操作,take(num)函数,take的作用就是获取RDD中下标0到num-1的元素。foreach遍历,并打印

键入命令:

data.take(10).foreach(println)

此处输入图片的描述

3.4.2 去除无用数据

在之前我们就已经了解到,我们不需要该文件的第一行数据,他只是一个标签行,并没有真正的购物数据。

键入如下命令删除第一行数据:

拓展: RDD filter,filter函数是应用于RDD的每一个元素,会过滤掉不符合条件的元素,返回新的RDD,其实新的RDD的内容就是filter里面返回值为True的元素。

val dataNoHead = data.filter(line => !line.contains("items"))

此处输入图片的描述

现在我们查看dataNoHead的前五行,看是否已经去除了第一行数据。结果如下:

键入命令:

dataNoHead.take(5).foreach(println)

此处输入图片的描述

从图上可以看出,我们已经去除了第一行。

3.4.3 获取购物数据

我们的目的是针对购物数据进行数据关联分析,在此用户id是没有用的数据,在这里我们选择将其抛弃,只获取我们需要的购物数据。具体操作如下:使用rdd的map函数,我们将用户id和购物商品分开,然后只取购物信息。

键入如下命令:

val dataS = dataNoHead.map(line => line.split("\\{"))

结果如下:

此处输入图片的描述

从上图可以了解到,dataS的数据格式为RDD[Array[String]]数据,接下来我们看看数据内容。如下图:

此处输入图片的描述

然后我们获取购物数据就简单了,就是dataS数据里面的Array里面的第二个元素,并去除里面的“}”“字符。

键入如下代码:

val dataGoods = dataS.map(s => s(1).replace("}\"",""))

实现效果如下:

此处输入图片的描述

同理,我们可以看到dataGoods的数据格式是RDD[String]了,我们看看该rdd里面的数据样式。

键入命令和上面的一样,我相信通过这几步练习,已经有所了解了吧。效果如下:

此处输入图片的描述

在这里,我们能够看到我们已经完全获取到了我们需要的购物数据。然后我们将这些数据以逗号分割开,用于FPGrowth的建模数据。

拆分数据,将其转换为建模数据的格式。需要的格式可以查看FPGrowth的API查看我们需要传入什么格式的数据,通过了解需要传入RDD[Array[String]]。将购物数据按逗号拆分,转换成建模数据。并将其cache到内存中,方便我们多次使用该数据。

键入如下命令:

val fpData = dataGoods.map(_.split(",")).cache

结果如下图:

此处输入图片的描述

同样,我们查看一下该RDD里面的内容。

键入如下命令:

fpData.take(5).foreach(line => line.foreach(print))

此处输入图片的描述

这样我们就将数据按照每一行,拆分成单独的商品,以RDD[Array[String]]的数据格式存在。到此我们整个的数据准备过程就结束了。

3.4.4 FPGrowth模型建立

我们先了解FP的三个基本概念。支持度与置信度与提升度。在这里主要介绍支持度和置信度两个概念。

支持度:比如说A对B的支持度,就是表示AB同时出现的事件除以总事件的概率。

置信度:比如说A对B的置信度,就是AB同时出现的事件除以A的总事件的概率。

提升度:同样A对B,表示在包含A的条件下同时包含B的概率,除以不含A的条件下含有B的概率。

下面我们举一个列子。比如说有1000个顾客,有400人买了物品A,400人买了物品B,有200人买了AB两个商品。

那么A的支持度为(400+200)/1000

AB的支持度为:200/1000

A对B的置信度为:200/400 (AB/A)

B对A的置信度为:200/400 (AB/B)

接下来我们开始建立模型:

  1. 引入FPGrowth包 键入命令:
import org.apache.spark.mllib.fpm.FPGrowth

实例化FPGrowth并且设置支持度为0.05,不满足该支持度的数据将被去除和分区为3。

输入如下命令:

val fpGroup = new FPGrowth().setMinSupport(0.05).setNumPartitions(3)

结果图如下:

此处输入图片的描述

  1. 开始创建模型 使用向前准备好的fpData数据,进行FP模型的建立。调用FPGrowth里面的run方法,进行模型的创建。 输入如下命令:
val fpModel = fpGroup.run(fpData)

创建模型后最后会有如下输出:

此处输入图片的描述

获取满足支持度条件的频繁项集。

输入如下命令:

val freqItems = fpModel.freqItemsets.collect

查找频繁项,看哪些商品关联性高

打印频繁项内容。输入命令:

freqItems.foreach(f=>println("FrequentItem:"+f.items.mkString(",")+"OccurrenceFrequency:"+f.freq))//FrequentItem:频繁项,OccurrenceFrequency:出现次数

结果如下:

此处输入图片的描述

从中我们可以看出牛奶和酸奶酪还是比较配的,频繁项次数是551次,两个同时出现的次数。当然我只截取了一部分数据,这也是一部分小数据。随着数据的增加就会有更好的效果。

  1. 进行用户商品推荐

前面我们看到用户ID为3的用户只购买了牛奶(whole milk),我们可以向他推荐什么商品呢。

定义一个用户ID为3的变量(排序从0开始)。

命令如下:

val userID = 2

获取用户3购买的物品。

键入命令:

val usrList = fpData.take(3)( userID)

结果如下:

此处输入图片的描述

我们可以看看userList的输出.

键入命令

usrList

此处输入图片的描述

我们获取了该用户的商品后,在频繁项中找出该商品出现的次数,用于后面计算商品之间的置信度。

定义一个变量用于存储该商品的次数。

输入命令:

var goodsFreq = 0L

查找频繁项集的次数

输入如下命令:

for(goods <- freqItems){         if(goods.items.mkString == usrList.mkString){        goodsFreq = goods.freq }}println(GoodsNumber:" + goodsFreq)

结果如下:

此处输入图片的描述

由于数据量的原因,在这里我们置信度设置为0.1,当商品的置信度大于0.1这个阈值,我们就将其推荐给用户。在推荐过程中需要去除用户已经购买了的商品。

输入如下命令:

 for(f <- freqItems){      if(f.items.mkString.contains(usrList.mkString) && f.items.size > usrList.size) {        val conf:Double = f.freq.toDouble / goodsFreq.toDouble        if(conf >= 0.1) {          var item = f.items          for (i <- 0 until usrList.size) {            item = item.filter(_ != usrList(i))           }          for (str <- item) {          println(str+"  ==="+conf)          }  }   }   }

结果如下:

此处输入图片的描述

红色框中是输入的代码,紫色的框中就是推荐的商品,后面就是其置信度的值。我们看看当3号用户买牛奶的时候会给我们推荐什么商品?

Yogurt: 酸乳酪 vegettables: 菜蔬 rolls/buns: 小面包或点心

看到推荐的这些商品,是不是感觉和牛奶很配呢。

到此我们的实验就结束了。当然也会存在推荐商品没有的情况,这种情况我们就可以将频繁项集里面的出现次数最高的几件商品推荐给用户。

原创粉丝点击