Fp关联规则算法计算置信度及MapReduce实现思路

说明:參考Mahout FP算法相关相关源代码。

算法project能够在FP关联规则计算置信度下载:(仅仅是单机版的实现,并没有MapReduce的代码)

使用FP关联规则算法计算置信度基于以下的思路:

1. 首先使用原始的FP树关联规则挖掘出全部的频繁项集及其支持度;这里须要注意,这里是输出全部的频繁项集,并没有把频繁项集合并,所以须要改动FP树的相关代码,在某些步骤把全部的频繁项集输出;(ps:參考Mahout的FP树单机版的实现,进行了改动,暂不确定是否已经输出了全部频繁项集)

为举例简单,能够以以下的数据为例(原始事务集):

牛奶,鸡蛋,面包,薯片
鸡蛋,爆米花,薯片,啤酒
鸡蛋,面包,薯片
牛奶,鸡蛋,面包,爆米花,薯片,啤酒
牛奶,面包,啤酒
鸡蛋,面包,啤酒
牛奶,面包,薯片
牛奶,鸡蛋,面包,黄油,薯片
牛奶,鸡蛋,黄油,薯片

2. 得到全部的频繁项集例如以下:

0,2,3=4
2,4=3
0,1,2,3=3
3=6
2=7
1,2=5
1=7
0=7
0,3=5
0,2=6
0,1=5
4=4
0,1,2=4
0,1,3=4
1,3=5
1,4=3

上面的频繁项集中,等号后面的是支持度;每条频繁项集显示的是经过编码的,编码的规则例如以下:{薯片=0, 牛奶=3, 鸡蛋=2, 面包=1, 啤酒=4}。同一时候。能够看到上面的频繁项集中的编码是依照顺序排列的(从小到大);

计算每条频繁项集的置信度(仅仅计算2项和2项以上的频繁项集):

1) 对于频繁n项集,查找其前向(前向定义为前面n-1项集。比方频繁项集:0,2,3那么其前向为0,2)的支持度。假设频繁n项集存在。那么其前向(频繁n-1项集)必定存在(假设频繁项集是全部的频繁项集的话,这个规则一定是成立的);

2)使用n项集的支持度除以n项集的前向的支持度就可以得到n项集的置信度。

3. 依照2中的计算方法是能够计算全部的频繁项集的置信度的。可是这里有个问题:仅仅能计算比方0,2,3这个频繁项集的置信度,而不能计算0,3,2这个频繁项集的置信度(FP算法中频繁项集0,2,3和0,3,2是一样的频繁项集。可是计算置信度的时候就会不一样);

4. 针对3的问题,能够给出以下的解决方式。

针对每条记录(包括n个项)。把每一个项作为后向(定义为最后一个项。比方频繁项集0,1,2,3能够分别把0、1、2、3作为后向。输出相对于置信度不同的频繁项集),其它前向保持相对顺序不变。

比方针对频繁项集:0,1,2,3 =3,应该输出:

1,2,3,0=3

0,2,3,1=3

0,1,3,2=3

0,1,2,3=3

因为针对同一个后向,其前向的顺序事实上对于计算置信度是没有影响的(比方针对0作为后向,1,2,3和2,1,3和3,2,1其支持度应该是一样的),这样对于算法来说其输出的含有置信度的频繁项集是比較完备的;

使用4的方法把原来FP树的频繁项集进行扩充就可以得到2中计算方法的数据了。

5. 针对4的输出(4的输出事实上仅仅是频繁项集和支持度,较3的结果来说仅仅是把1条记录变为了n条而已),计算各个频繁项集的置信度,事实上就是两个表的互查,即以A表的n项频繁集參考B表的n-1项频繁集来计算n项置信度。A表和B表是一样的。能够使用MapReduce的思路。稍后细说。

參考Mahout的单机FP实现,给出的计算置信度的代码主要例如以下:

1. 因为mahout里面的实现其交互是和HDFS文件交互的,这里能够和本地文件进行交互,或者直接存入内存,本文的实现是直接存入内存的,假设要存入文件也是能够的(只是可能要经过过滤反复记录的操作);

所以把单机版的FP中某些代码做了改动。比方以下的代码:

//		generateTopKFrequentPatterns(new TransactionIterator<A>(
//				transactionStream, attributeIdMapping), attributeFrequency,
//				minSupport, k, reverseMapping.size(), returnFeatures,
//				new TopKPatternsOutputConverter<A>(output, reverseMapping),
//				updater);

改动为以下的代码:

generateTopKFrequentPatterns(new TransactionIterator<A>(
				transactionStream, attributeIdMapping), attributeFrequency,
				minSupport, k, reverseMapping.size(), returnFeatures,reverseMapping
				);

这种改动在FPTree里面有非常多,就不一一赘述,详情參考本文源代码下载的project;

2. 因为mahout的FP树最后输出的频繁项集是经过整合的,所以有些频繁项集没有输出(即仅仅输出了最大频繁项集),而上面提出的算法是须要全部频繁项集都进行输出的。所以在函数generateSinglePathPatterns(FPTree tree, int k,long minSupport) 和函数generateSinglePathPatterns(FPTree tree,int k,long minSupport)的return中加上一句:

addFrequentPatternMaxHeap(frequentPatterns);

这种方法的详细代码为:

/**
   * 存储全部频繁项集
   * @param patternsOut
   */
  private static void addFrequentPatternMaxHeap(FrequentPatternMaxHeap patternsOut){
		String[] pStr=null;

		// 这里的Pattern有问题。临时使用字符串解析
		for(Pattern p:patternsOut.getHeap()){

			pStr=p.toString().split("-");
			if(pStr.length<=0){
				continue;
			}
//			对字符串进行下处理,这样能够降低存储
			pStr[0]=pStr[0].replaceAll(" ", "");
			pStr[0]=pStr[0].substring(1,pStr[0].length()-1);
			if(patterns.containsKey(pStr[0])){
				if(patterns.get(pStr[0])<p.support()){// 仅仅取支持度最大的
					patterns.remove(pStr[0]);
					patterns.put(pStr[0], p.support());
				}
			}else{
				patterns.put(pStr[0], p.support());
			}
		}

	}

这里假定这种操作能够得到全部的频繁项集。而且存入到了patterns静态map变量中。

3. 依据思路第4中的描写叙述。把FP产生的频繁项集进行扩充:

/**
   * 依据排序频繁相机支持度 生成多频繁项集支持度
   */
  public void generateFatPatterns(){
	  int[] patternInts=null;
	  for(String p :patterns.keySet()){
		  patternInts = getIntsFromPattern(p);
		  if(patternInts.length==1){// 针对频繁一项集
			  fatPatterns.put(String.valueOf(patternInts[0]), patterns.get(p));
		  }else{
			  putInts2FatPatterns(patternInts,patterns.get(p));
		  }

	  }
  }

/**
   * 把数组中的每一项作为后向进行输出,加入到fatpatterns中
   * @param patternInts
 * @param support
   */
  private void putInts2FatPatterns(int[] patternInts, Long support) {
	// TODO Auto-generated method stub
	String patternStr =Ints2Str(patternInts);
	fatPatterns.put(patternStr, support);// 处理最后一个后向
	for(int i=0;i<patternInts.length-1;i++){//  最后一个后向在前面已经处理
		// 不能使用同一个数组
		patternStr=Ints2Str(swap(patternInts,i,patternInts.length-1));
		fatPatterns.put(patternStr, support);
	}

  }

4. 针对上面输出的频发项集进行置信度的计算:

 public void savePatterns(String output,Map<String,Long> map){
	  // 清空patternsMap
	  patternsMap.clear();

	  String preItem=null;
	  for(String p:map.keySet()){
		  // 单项没有前向。不用找
		  if(p.lastIndexOf(",")==-1){
			  continue;
		  }
		  // 找出前向
		  preItem = p.substring(0, p.lastIndexOf(","));
		  if(map.containsKey(preItem)){
			  // patterns.get(p) 支持度,patterns.get(preItem)前向支持度
			  patternsMap.put(p, map.get(p)*1.0/map.get(preItem));
		  }
	  }
	  FPTreeDriver.createFile(patternsMap, output);
  }

因为把频繁项集和支持度都放入了Map中,所以这样计算比較简单。

对照使用扩充的和没有使用扩充的频繁项集产生的关联规则例如以下图所看到的:

这里能够看到扩充后的关联规则1,3和3,1 是不一样的,其置信度一个是0.714,一个是0.8。所以能够解释为从1推出3的概率没有从3推出1的概率大。举个生活简单的实例:买了电视机。再买遥控器的概率肯定比买了遥控器再买电视机的概率大。

可是假设全部扩充后的频繁项集和支持度数据太大而不能全然放入内存应该怎样操作呢。
这里能够使用MapReduce的思路来实现。

MapReduce实现计算置信度的思路:

0.  这里假设已经得到了扩充后的频繁项集的支持度,并存在与HDFS文件系统上面。假设为文件A。
1.  把文件A复制一份得到文件B;

2. 參考《hadoop多文件格式输入》http://blog.csdn.net/fansy1990/article/details/26267637,设计两个不同的Mapper,一个处理A,一个处理B。

对A的处理为直接输出频繁项集,输出的key为频繁项集,value是支持度和A的标签;对B的处理为输出全部的频繁项集中项大于1的频繁项集,其输出的key是频繁项集的前向(定义为频繁项集前面n-1个项)。value是频繁项集的后向(后向定义为频繁项集的最后一项)和支持度和标签。

3. 在2中不同的Mapper进行处理的数据会在Reducer中进行汇集。在Reducer中进行例如以下的处理:针对同样的key。遍历其value集合。假设被贴了A标签那么就赋值一个变量,用于做分母,假设是B标签那么就进行计算。计算是把B标签的数据的支持度除以刚才A标签的变量。得到置信度confidence,输出的key为输入的key+B标签的后向,value是confidence。

比方A的输出为 <(0,2,3),5+A>;  当中(0,2,3)为频繁项集,是key。5+A是value。当中5是支持度。A是标签

B中的输出为:

<(0,2,3),4+3+B>  ; 当中(0,2,3,4)为频繁项集。key是前向(0,2,3);4+3+B是value,当中4是后向,3是支持度,B是标签;

<(0,2,3),5+3+B> ; 当中(0,2,3,5)为频繁项集。key是前向(0,2,3);5+3+B是value。当中5是后向,3是支持度,B是标签;

<(0,2,3),6+2+B>。当中(0,2,3,6)为频繁项集,key是前向(0,2,3);6+2+B是value。当中6是后向。2是支持度,B是标签。

那么Reducer中汇总的数据就是:

<(0,2,3),[(5+A),(4+3+B),(5+3+B),(6+2+B)>;

遍历当中的value集合,首先,把标签A的支持度作为分母,即分母是5;

接着, 遍历B的标签,比方(4+3+B),因为是B的标签那么就计算支持度除以A的分母为3/5 , 输出为<(0,2,3,4),3/5>;

接着遍历,就可以输出:<(0,2,3,5),3/5>; <(0,2,3,6),2/5>; 等记录;

这里须要注意

1)当Reducer中仅仅有A的标签数据时。这时是不须要进行输出的,因为这个是最大频繁项集。不能作为不论什么频繁项集的前向;

2)上面的value能够自行设计为自己定义Writable类型,而不是简单的字符串。

3) 计算置信度的MapReduce代码暂没有实现,本文提供的下载是单机版的。且扩充频繁项集是能够放入内存的;

分享,成长,快乐

转载请注明blog地址:http://blog.csdn.net/fansy1990

时间: 2024-10-12 23:27:37

Fp关联规则算法计算置信度及MapReduce实现思路的相关文章

HotSpot关联规则算法(1)-- 挖掘离散型数据

提到关联规则算法,一般会想到Apriori或者FP,一般很少有想到HotSpot的,这个算法不知道是应用少还是我查资料的手段太low了,在网上只找到很少的内容,这篇http://wiki.pentaho.com/display/DATAMINING/HotSpot+Segmentation-Profiling ,大概分析了一点,其他好像就没怎么看到了.比较好用的算法类软件,如weka,其里面已经包含了这个算法,在Associate--> HotSpot里面即可看到,运行算法界面一般如下: 其中,

Aprior算法、FP Growth算法

数据挖掘中有一个很重要的应用,就是Frequent Pattern挖掘,翻译成中文就是频繁模式挖掘.这篇博客就想谈谈频繁模式挖掘相关的一些算法. 定义 何谓频繁模式挖掘呢?所谓频繁模式指的是在样本数据集中频繁出现的模式.举个例子,比如在超市的交易系统中,记载了很多次交易,每一次交易的信息包括用户购买的商品清单.如果超市主管是个有心人的话,他会发现尿不湿,啤酒这两样商品在许多用户的购物清单上都出现了,而且频率非常高.尿不湿,啤酒同时出现在一张购物单上就可以称之为一种频繁模式,这样的发掘就可以称之为

HotSpot关联规则算法(2)-- 挖掘连续型和离散型数据

本篇代码可在 http://download.csdn.net/detail/fansy1990/8502323下载. 前篇<HotSpot关联规则算法(1)-- 挖掘离散型数据>分析了离散型数据的HotSpot关联规则,本篇分析离散型和连续型数据的HotSpot关联规则挖掘. 1. 首先看下数据格式(txt文档): @attribute outlook {sunny, overcast, rainy} @attribute temperature numeric @attribute hum

FP—Growth算法

FP_growth算法是韩家炜老师在2000年提出的关联分析算法,该算法和Apriori算法最大的不同有两点: 第一,不产生候选集,第二,只需要两次遍历数据库,大大提高了效率,用31646条测试记录,最小支持度是2%, 用Apriori算法要半个小时但是用FP_growth算法只要6分钟就可以了,效率非常明显. 它的核心是FP_tree,一种树型数据结构,特点是尽量把相同元素用一个节点表示,这样就大大减少了空间,和birch算法有类似的思想.还是以如下数据为例. 每一行表示一条交易,共有9行,既

FP Tree算法原理总结

在Apriori算法原理总结中,我们对Apriori算法的原理做了总结.作为一个挖掘频繁项集的算法,Apriori算法需要多次扫描数据,I/O是很大的瓶颈.为了解决这个问题,FP Tree算法(也称FP Growth算法)采用了一些技巧,无论多少数据,只需要扫描两次数据集,因此提高了算法运行的效率.下面我们就对FP Tree算法做一个总结. 1. FP Tree数据结构 为了减少I/O次数,FP Tree算法引入了一些数据结构来临时存储数据.这个数据结构包括三部分,如下图所示: 第一部分是一个项

Canopy算法计算聚类的簇数

Kmeans算是是聚类中的经典算法.步骤例如以下: 选择K个点作为初始质心 repeat 将每一个点指派到近期的质心,形成K个簇 又一次计算每一个簇的质心 until 簇不发生变化或达到最大迭代次数 算法中的K须要人为的指定.确定K的做法有非常多,比方多次进行试探.计算误差.得出最好的K.这样须要比較长的时间.我们能够依据Canopy算法来粗略确定K值(能够觉得相等).看一下Canopy算法的过程: (1)设样本集合为S.确定两个阈值t1和t2,且t1>t2. (2)任取一个样本点p.作为一个C

小算法-计算下一个排列

2 8 5 3 1 1.从后往前,找到第一个逆序的数 pivot 2.从后往前,找到第一个比pivot大的数 change 3.交换 pivot 和 change的值 4.把pivot这个位置后面的数 reverse,就是 8 5 2 1变成 1 2 5 8 最终为3 1 2 5 8 #include <iostream> #include <vector> #include <algorithm> using namespace std; /* * num.begin

Frequent Pattern 挖掘之二(FP Growth算法)(转)

FP树构造 FP Growth算法利用了巧妙的数据结构,大大降低了Aproir挖掘算法的代价,他不需要不断得生成候选项目队列和不断得扫描整个数据库进行比对.为了达到这样的效果,它采用了一种简洁的数据结构,叫做frequent-pattern tree(频繁模式树).下面就详细谈谈如何构造这个树,举例是最好的方法.请看下面这个例子: 这张表描述了一张商品交易清单,abcdefg代表商品,(ordered)frequent items这一列是把商品按照降序重新进行了排列,这个排序很重要,我们操作的所

算法 计算多个顺序区间的总长

List<Point> list = Arrays.asList(new Point(1, 5), new Point(2, 3), new Point(2, 8), new Point(9, 13)); int sum = list.get(0).y - list.get(0).x,currenty=list.get(0).y; Point pnext; for (int i = 1, len = list.size(); i < len; i++) { pnext = list.ge