数据挖掘-关联分析频繁模式挖掘Apriori、FP-Growth及Eclat算法的JAVA及C++实现

(update 2012.12.28 关于本项目下载及运行的常见问题 FAQ见newsgroup18828文本分类器、文本聚类器、关联分析频繁模式挖掘算法的Java实现工程下载及运行FAQ)

一、Apriori算法

Apriori是非常经典的关联分析频繁模式挖掘算法,其思想简明,实现方便,只是效率很低,可以作为频繁模式挖掘的入门算法。其主要特点是

1、k-1项集连接规律:若有两个k-1项集,每个项集保证有序,如果两个k-1项集的前k- 2个项相同,而最后一个项不同,则证明它们是可连接的,可连接生成k项集。
2、反单调性。如果一个项集是频繁的,那么它的所有子集都是频繁的。即若一个项集的 子集不是频繁项集,则该项集肯定也不是频繁项集。
主要算法流程:
1. 扫描数据库,生成候选1项集和频繁1项集。
2. 从2项集开始循环,由频繁k-1项集生成频繁频繁k项集。
2.1 频繁k-1项集两两组合,判定是否可以连接,若能则连接生成k项集。
2.2 对k项集中的每个项集检测其子集是否频繁,舍弃掉子集不是频繁项集即 不在频繁k-1项集中的项集。
2.3 扫描数据库,计算2.3步中过滤后的k项集的支持度,舍弃掉支持度小于阈值的项集,生成频繁k项集。
3. 若当前k项集中只有一个项集时循环结束。
伪代码如下:

JAVA实现代码
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. packagecom.pku.yangliu;
  2. importjava.io.BufferedReader;
  3. importjava.io.File;
  4. importjava.io.FileReader;
  5. importjava.io.FileWriter;
  6. importjava.io.IOException;
  7. importjava.util.ArrayList;
  8. importjava.util.HashMap;
  9. importjava.util.HashSet;
  10. importjava.util.List;
  11. importjava.util.Map;
  12. importjava.util.Set;
  13. importjava.util.TreeSet;
  14. /**频繁模式挖掘算法Apriori实现
  15. *
  16. */
  17. publicclassAprioriFPMining{
  18. privateintminSup;//最小支持度
  19. privatestaticList<Set<String>>dataTrans;//以List<Set<String>>格式保存的事物数据库,利用Set的有序性
  20. publicintgetMinSup(){
  21. returnminSup;
  22. }
  23. publicvoidsetMinSup(intminSup){
  24. this.minSup=minSup;
  25. }
  26. /**
  27. *@paramargs
  28. */
  29. publicstaticvoidmain(String[]args)throwsIOException{
  30. AprioriFPMiningapriori=newAprioriFPMining();
  31. double[]threshold={0.25,0.20,0.15,0.10,0.05};
  32. StringsrcFile="F:/DataMiningSample/FPmining/Mushroom.dat";
  33. StringshortFileName=srcFile.split("/")[3];
  34. StringtargetFile="F:/DataMiningSample/FPmining/"+shortFileName.substring(0,shortFileName.indexOf("."))+"_fp_threshold";
  35. dataTrans=apriori.readTrans(srcFile);
  36. for(intk=0;k<threshold.length;k++){
  37. System.out.println(srcFile+"threshold:"+threshold[k]);
  38. longtotalItem=0;
  39. longtotalTime=0;
  40. FileWritertgFileWriter=newFileWriter(targetFile+(threshold[k]*100));
  41. apriori.setMinSup((int)(dataTrans.size()*threshold[k]));//原始蘑菇的数据0.25只需要67秒跑出结果
  42. longstartTime=System.currentTimeMillis();
  43. Map<String,Integer>f1Set=apriori.findFP1Items(dataTrans);
  44. longendTime=System.currentTimeMillis();
  45. totalTime+=endTime-startTime;
  46. //频繁1项集信息得加入支持度
  47. Map<Set<String>,Integer>f1Map=newHashMap<Set<String>,Integer>();
  48. for(Map.Entry<String,Integer>f1Item:f1Set.entrySet()){
  49. Set<String>fs=newHashSet<String>();
  50. fs.add(f1Item.getKey());
  51. f1Map.put(fs,f1Item.getValue());
  52. }
  53. totalItem+=apriori.printMap(f1Map,tgFileWriter);
  54. Map<Set<String>,Integer>result=f1Map;
  55. do{
  56. startTime=System.currentTimeMillis();
  57. result=apriori.genNextKItem(result);
  58. endTime=System.currentTimeMillis();
  59. totalTime+=endTime-startTime;
  60. totalItem+=apriori.printMap(result,tgFileWriter);
  61. }while(result.size()!=0);
  62. tgFileWriter.close();
  63. System.out.println("共用时:"+totalTime+"ms");
  64. System.out.println("共有"+totalItem+"项频繁模式");
  65. }
  66. }
  67. /**由频繁K-1项集生成频繁K项集
  68. *@parampreMap保存频繁K项集的map
  69. *@paramtgFileWriter输出文件句柄
  70. *@returnint频繁i项集的数目
  71. *@throwsIOException
  72. */
  73. privateMap<Set<String>,Integer>genNextKItem(Map<Set<String>,Integer>preMap){
  74. //TODOAuto-generatedmethodstub
  75. Map<Set<String>,Integer>result=newHashMap<Set<String>,Integer>();
  76. //遍历两个k-1项集生成k项集
  77. List<Set<String>>preSetArray=newArrayList<Set<String>>();
  78. for(Map.Entry<Set<String>,Integer>preMapItem:preMap.entrySet()){
  79. preSetArray.add(preMapItem.getKey());
  80. }
  81. intpreSetLength=preSetArray.size();
  82. for(inti=0;i<preSetLength-1;i++){
  83. for(intj=i+1;j<preSetLength;j++){
  84. String[]strA1=preSetArray.get(i).toArray(newString[0]);
  85. String[]strA2=preSetArray.get(j).toArray(newString[0]);
  86. if(isCanLink(strA1,strA2)){//判断两个k-1项集是否符合连接成k项集的条件 
  87. Set<String>set=newTreeSet<String>();
  88. for(Stringstr:strA1){
  89. set.add(str);
  90. }
  91. set.add((String)strA2[strA2.length-1]);//连接成k项集
  92. //判断k项集是否需要剪切掉,如果不需要被cut掉,则加入到k项集列表中
  93. if(!isNeedCut(preMap,set)){//由于单调性,必须保证k项集的所有k-1项子集都在preMap中出现,否则就该剪切该k项集
  94. result.put(set,0);
  95. }
  96. }
  97. }
  98. }
  99. returnassertFP(result);//遍历事物数据库,求支持度,确保为频繁项集
  100. }
  101. /**检测k项集是否该剪切。由于单调性,必须保证k项集的所有k-1项子集都在preMap中出现,否则就该剪切该k项集
  102. *@parampreMapk-1项频繁集map
  103. *@paramset待检测的k项集
  104. *@returnboolean是否该剪切
  105. *@throwsIOException
  106. */
  107. privatebooleanisNeedCut(Map<Set<String>,Integer>preMap,Set<String>set){
  108. //TODOAuto-generatedmethodstub
  109. booleanflag=false;
  110. List<Set<String>>subSets=getSubSets(set);
  111. for(Set<String>subSet:subSets){
  112. if(!preMap.containsKey(subSet)){
  113. flag=true;
  114. break;
  115. }
  116. }
  117. returnflag;
  118. }
  119. /**获取k项集set的所有k-1项子集
  120. *@paramset频繁k项集
  121. *@returnList<Set<String>>所有k-1项子集容器
  122. *@throwsIOException
  123. */
  124. privateList<Set<String>>getSubSets(Set<String>set){
  125. //TODOAuto-generatedmethodstub
  126. String[]setArray=set.toArray(newString[0]);
  127. List<Set<String>>result=newArrayList<Set<String>>();
  128. for(inti=0;i<setArray.length;i++){
  129. Set<String>subSet=newHashSet<String>();
  130. for(intj=0;j<setArray.length;j++){
  131. if(j!=i)subSet.add(setArray[j]);
  132. }
  133. result.add(subSet);
  134. }
  135. returnresult;
  136. }
  137. /**遍历事物数据库,求支持度,确保为频繁项集
  138. *@paramallKItem候选频繁k项集
  139. *@returnMap<Set<String>,Integer>支持度大于阈值的频繁项集和支持度map
  140. *@throwsIOException
  141. */
  142. privateMap<Set<String>,Integer>assertFP(
  143. Map<Set<String>,Integer>allKItem){
  144. //TODOAuto-generatedmethodstub
  145. Map<Set<String>,Integer>result=newHashMap<Set<String>,Integer>();
  146. for(Set<String>kItem:allKItem.keySet()){
  147. for(Set<String>data:dataTrans){
  148. booleanflag=true;
  149. for(Stringstr:kItem){
  150. if(!data.contains(str)){
  151. flag=false;
  152. break;
  153. }
  154. }
  155. if(flag)allKItem.put(kItem,allKItem.get(kItem)+1);
  156. }
  157. if(allKItem.get(kItem)>=minSup){
  158. result.put(kItem,allKItem.get(kItem));
  159. }
  160. }
  161. returnresult;
  162. }
  163. /**检测两个频繁K项集是否可以连接,连接条件是只有最后一个项不同
  164. *@paramstrA1k项集1
  165. *@paramstrA1k项集2
  166. *@returnboolean是否可以连接
  167. *@throwsIOException
  168. */
  169. privatebooleanisCanLink(String[]strA1,String[]strA2){
  170. //TODOAuto-generatedmethodstub
  171. booleanflag=true;
  172. if(strA1.length!=strA2.length){
  173. returnfalse;
  174. }else{
  175. for(inti=0;i<strA1.length-1;i++){
  176. if(!strA1[i].equals(strA2[i])){
  177. flag=false;
  178. break;
  179. }
  180. }
  181. if(strA1[strA1.length-1].equals(strA2[strA1.length-1])){
  182. flag=false;
  183. }
  184. }
  185. returnflag;
  186. }
  187. /**将频繁i项集的内容及支持度输出到文件格式为模式:支持度
  188. *@paramf1Map保存频繁i项集的容器<i项集,支持度>
  189. *@paramtgFileWriter输出文件句柄
  190. *@returnint频繁i项集的数目
  191. *@throwsIOException
  192. */
  193. privateintprintMap(Map<Set<String>,Integer>f1Map,FileWritertgFileWriter)throwsIOException{
  194. //TODOAuto-generatedmethodstub
  195. for(Map.Entry<Set<String>,Integer>f1MapItem:f1Map.entrySet()){
  196. for(Stringp:f1MapItem.getKey()){
  197. tgFileWriter.append(p+"");
  198. }
  199. tgFileWriter.append(":"+f1MapItem.getValue()+"\n");
  200. }
  201. tgFileWriter.flush();
  202. returnf1Map.size();
  203. }
  204. /**生成频繁1项集
  205. *@paramfileDir事务文件目录
  206. *@returnMap<String,Integer>保存频繁1项集的容器<1项集,支持度>
  207. *@throwsIOException
  208. */
  209. privateMap<String,Integer>findFP1Items(List<Set<String>>dataTrans){
  210. //TODOAuto-generatedmethodstub
  211. Map<String,Integer>result=newHashMap<String,Integer>();
  212. Map<String,Integer>itemCount=newHashMap<String,Integer>();
  213. for(Set<String>ds:dataTrans){
  214. for(Stringd:ds){
  215. if(itemCount.containsKey(d)){
  216. itemCount.put(d,itemCount.get(d)+1);
  217. }else{
  218. itemCount.put(d,1);
  219. }
  220. }
  221. }
  222. for(Map.Entry<String,Integer>ic:itemCount.entrySet()){
  223. if(ic.getValue()>=minSup){
  224. result.put(ic.getKey(),ic.getValue());
  225. }
  226. }
  227. returnresult;
  228. }
  229. /**读取事务数据库
  230. *@paramfileDir事务文件目录
  231. *@returnList<String>保存事务的容器
  232. *@throwsIOException
  233. */
  234. privateList<Set<String>>readTrans(StringfileDir){
  235. //TODOAuto-generatedmethodstub
  236. List<Set<String>>records=newArrayList<Set<String>>();
  237. try{
  238. FileReaderfr=newFileReader(newFile(fileDir));
  239. BufferedReaderbr=newBufferedReader(fr);
  240. Stringline=null;
  241. while((line=br.readLine())!=null){
  242. if(line.trim()!=""){
  243. Set<String>record=newHashSet<String>();
  244. String[]items=line.split("");
  245. for(Stringitem:items){
  246. record.add(item);
  247. }
  248. records.add(record);
  249. }
  250. }
  251. }catch(IOExceptione){
  252. System.out.println("读取事务文件失败。");
  253. System.exit(-2);
  254. }
  255. returnrecords;
  256. }
  257. }
硬件环境:Intel Core 2 Duo CPU T5750 2GHZ, 2G内存
实验结果
F:/DataMiningSample/FPmining/Mushroom.dat threshold: 0.25
共用时:54015ms
共有5545项频繁模式
F:/DataMiningSample/FPmining/Mushroom.dat threshold: 0.2
共用时:991610ms
共有53663项频繁模式
F:/DataMiningSample/FPmining/Mushroom.dat threshold: 0.15
结论:对Mushroom.dat挖掘出来的频繁模式及支持度、频繁模式总数正确,但是算法速度很慢,对大数据量如T10I4D100K低阈值挖掘时间太长
解决办法:改用C++写FP-Growth算法做频繁模式挖掘!

二、FP-Growth算法
FP-Growth算法由数据挖掘界大牛Han Jiawei教授于SIGMOD 00‘大会提出,提出根据事物数据库构建FP-Tree,然后基于FP-Tree生成频繁模式集。主要算法流程如下
Step1 读取数据库,构造频繁1项集及FP-tree

Step2 遍历FP-tree的头表,对于每个频繁项x,累积项x的所有前缀路径形成x的条件模式库CPB

Step3 对CPB上每一条路径的节点更新计数为x的计数,根据CPB构造条件FP-tree
Step4 从条件FP-tree中找到所有长路径,对该路径上的节点找出所有组合方式,然后合并计数
Step5 将Step4中的频繁项集与x合并,得到包含x的频繁项集
Step2-5 循环,直到遍历头表中的所有项

由于时间关系,主要基于芬兰教授Bart Goethals的开源代码实现,源码下载见点击打开链接,文件结构及运行结果如下

Mushroom.dat,accidents.dat和T10I4D100K.dat三个数据集做频繁模式挖掘的结果如下



三、Eclat算法
Eclat算法加入了倒排的思想,加快频繁集生成速度,其算法思想是 由频繁k项集求交集,生成候选k+1项集 。对候选k+1项集做裁剪,生成频繁k+1项集,再求交集生成候选k+2项集。如此迭代,直到项集归一。
算法过程:
1.一次扫描数据库,获得初始数据。包括频繁1项集,数据库包含的所有items,事务总数(行)transNum,最小支持度minsup=limitValue*trans。
2.二次扫描数据库,获得频繁2项集。
3.按照Eclat算法,对频繁2项集迭代求交集,做裁剪,直到项集归一。
JAVA实现如下
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. packagecom.pku.yhf;
  2. importjava.io.BufferedReader;
  3. importjava.io.BufferedWriter;
  4. importjava.io.File;
  5. importjava.io.FileInputStream;
  6. importjava.io.FileNotFoundException;
  7. importjava.io.FileReader;
  8. importjava.io.FileWriter;
  9. importjava.io.IOException;
  10. importjava.io.InputStreamReader;
  11. importjava.util.ArrayList;
  12. importjava.util.BitSet;
  13. importjava.util.Iterator;
  14. importjava.util.Set;
  15. importjava.util.TreeMap;
  16. importjava.util.TreeSet;
  17. publicclassEclatRelease{
  18. privateFilefile=newFile("D:/mushroom.dat.txt");
  19. privatefloatlimitValue=0.25f;
  20. privateinttransNum=0;
  21. privateArrayList<HeadNode>array=newArrayList<HeadNode>();
  22. privateHashHeadNode[]hashTable;//存放临时生成的频繁项集,作为重复查询的备选集合
  23. publiclongnewItemNum=0;
  24. privateFiletempFile=null;
  25. privateBufferedWriterbw=null;
  26. publicstaticlongmodSum=0;
  27. /**
  28. *第一遍扫描数据库,确定Itemset,根据阈值计算出支持度数
  29. */
  30. publicvoidinit()
  31. {
  32. SetitemSet=newTreeSet();
  33. MyMap<Integer,Integer>itemMap=newMyMap<Integer,Integer>();
  34. intitemNum=0;
  35. Set[][]a;
  36. try{
  37. FileInputStreamfis=newFileInputStream(file);
  38. BufferedReaderbr=newBufferedReader(newInputStreamReader(fis));
  39. Stringstr=null;
  40. //第一次扫描数据集合
  41. while((str=br.readLine())!=null)
  42. {
  43. transNum++;
  44. String[]line=str.split("");
  45. for(Stringitem:line)
  46. {
  47. itemSet.add(Integer.parseInt(item));
  48. itemMap.add(Integer.parseInt((item)));
  49. }
  50. }
  51. br.close();
  52. //System.out.println("itemMaplastKey:"+itemMap.lastKey());
  53. //System.out.println("itemsize:"+itemSet.size());
  54. //System.out.println("trans:"+transNum);
  55. //ItemSet.limitSupport=(int)Math.ceil(transNum*limitValue);//上取整
  56. ItemSet.limitSupport=(int)Math.floor(transNum*limitValue);//下取整
  57. ItemSet.ItemSize=(Integer)itemMap.lastKey();
  58. ItemSet.TransSize=transNum;
  59. hashTable=newHashHeadNode[ItemSet.ItemSize*3];//生成项集hash表
  60. for(inti=0;i<hashTable.length;i++)
  61. {
  62. hashTable[i]=newHashHeadNode();
  63. }
  64. //System.out.println("limitSupport:"+ItemSet.limitSupport);
  65. tempFile=newFile(file.getParent()+"/"+file.getName()+".dat");
  66. if(tempFile.exists())
  67. {
  68. tempFile.delete();
  69. }
  70. tempFile.createNewFile();
  71. bw=newBufferedWriter(newFileWriter(tempFile));
  72. SetoneItem=itemMap.keySet();
  73. intcountOneItem=0;
  74. for(Iteratorit=oneItem.iterator();it.hasNext();)
  75. {
  76. intkey=(Integer)it.next();
  77. intvalue=(Integer)itemMap.get(key);
  78. if(value>=ItemSet.limitSupport)
  79. {
  80. bw.write(key+""+":"+""+value);
  81. bw.write("\n");
  82. countOneItem++;
  83. }
  84. }
  85. bw.flush();
  86. modSum+=countOneItem;
  87. itemNum=(Integer)itemMap.lastKey();
  88. a=newTreeSet[itemNum+1][itemNum+1];
  89. array.add(newHeadNode());//空项
  90. for(shorti=1;i<=itemNum;i++)
  91. {
  92. HeadNodehn=newHeadNode();
  93. //hn.item=i;
  94. array.add(hn);
  95. }
  96. BufferedReaderbr2=newBufferedReader(newFileReader(file));
  97. //第二次扫描数据集合,形成2-项候选集
  98. intcounter=0;//事务
  99. intmax=0;
  100. while((str=br2.readLine())!=null)
  101. {max++;
  102. String[]line=str.split("");
  103. counter++;
  104. for(inti=0;i<line.length;i++)
  105. {
  106. intsOne=Integer.parseInt(line[i]);
  107. for(intj=i+1;j<line.length;j++)
  108. {
  109. intsTwo=Integer.parseInt(line[j]);
  110. if(a[sOne][sTwo]==null)
  111. {
  112. Setset=newTreeSet();
  113. set.add(counter);
  114. a[sOne][sTwo]=set;
  115. }
  116. else{
  117. a[sOne][sTwo].add(counter);
  118. }
  119. }
  120. }
  121. }
  122. //将数组集合转换为链表集合
  123. for(inti=1;i<=itemNum;i++)
  124. {
  125. HeadNodehn=array.get(i);
  126. for(intj=i+1;j<=itemNum;j++)
  127. {
  128. if(a[i][j]!=null&&a[i][j].size()>=ItemSet.limitSupport)
  129. {
  130. hn.items++;
  131. ItemSetis=newItemSet(true);
  132. is.item=2;
  133. is.items.set(i);
  134. is.items.set(j);
  135. is.supports=a[i][j].size();
  136. bw.write(i+""+j+""+":"+is.supports);
  137. bw.write("\n");
  138. //统计频繁2-项集的个数
  139. modSum++;
  140. for(Iteratorit=a[i][j].iterator();it.hasNext();)
  141. {
  142. intvalue=(Integer)it.next();
  143. is.trans.set(value);
  144. }
  145. if(hn.first==null)
  146. {
  147. hn.first=is;
  148. hn.last=is;
  149. }
  150. else{
  151. hn.last.next=is;
  152. hn.last=is;
  153. }
  154. }
  155. }
  156. }
  157. bw.flush();
  158. }catch(FileNotFoundExceptione){
  159. e.printStackTrace();
  160. }catch(IOExceptione){
  161. e.printStackTrace();
  162. }
  163. }
  164. publicvoidstart()
  165. {
  166. booleanflag=true;
  167. //TreeSetts=newTreeSet();//临时存储项目集合,防止重复项集出现,节省空间
  168. intcount=0;
  169. ItemSetshareFirst=newItemSet(false);
  170. while(flag)
  171. {
  172. flag=false;
  173. //System.out.println(++count);
  174. for(inti=1;i<array.size();i++)
  175. {
  176. HeadNodehn=array.get(i);
  177. if(hn.items>1)//项集个数大于1
  178. {
  179. generateLargeItemSet(hn,shareFirst);
  180. flag=true;
  181. }
  182. clear(hashTable);
  183. }
  184. }try{
  185. bw.close();
  186. }catch(IOExceptione){
  187. e.printStackTrace();
  188. }
  189. }
  190. publicvoidgenerateLargeItemSet(HeadNodehn,ItemSetshareFirst){
  191. BitSetbsItems=newBitSet(ItemSet.ItemSize);//存放链两个k-1频繁项集的ItemSet交
  192. BitSetbsTrans=newBitSet(ItemSet.TransSize);//存放两个k-1频繁项集的Trans交
  193. BitSetcontainItems=newBitSet(ItemSet.ItemSize);//存放两个k-1频繁项集的ItemSet的并
  194. BitSetbsItems2=newBitSet(ItemSet.ItemSize);//临时存放容器BitSet
  195. ItemSetoldCurrent=null,oldNext=null;
  196. oldCurrent=hn.first;
  197. longcountItems=0;
  198. ItemSetnewFirst=newItemSet(false),newLast=newFirst;
  199. while(oldCurrent!=null)
  200. {
  201. oldNext=oldCurrent.next;
  202. while(oldNext!=null)
  203. {
  204. //生成k—项候选集,由两个k-1项频繁集生成
  205. bsItems.clear();
  206. bsItems.or(oldCurrent.items);
  207. bsItems.and(oldNext.items);
  208. if(bsItems.cardinality()<oldCurrent.item-1)
  209. {
  210. break;
  211. }
  212. //新合并的项集是否已经存在
  213. containItems.clear();
  214. containItems.or(oldCurrent.items);//将k-1项集合并
  215. containItems.or(oldNext.items);
  216. if(!containItems(containItems,bsItems2,newFirst)){
  217. bsTrans.clear();
  218. bsTrans.or(oldCurrent.trans);
  219. bsTrans.and(oldNext.trans);
  220. if(bsTrans.cardinality()>=ItemSet.limitSupport)
  221. {
  222. ItemSetis=null;
  223. if(shareFirst.next==null)//没有共享ItemSet链表
  224. {
  225. is=newItemSet(true);
  226. newItemNum++;
  227. }
  228. else
  229. {
  230. is=shareFirst.next;
  231. shareFirst.next=shareFirst.next.next;
  232. is.items.clear();
  233. is.trans.clear();
  234. is.next=null;
  235. }
  236. is.item=(oldCurrent.item+1);//生成k—项候选集,由两个k-1项频繁集生成
  237. is.items.or(oldCurrent.items);//将k-1项集合并
  238. is.items.or(oldNext.items);//将k-1项集合并
  239. is.trans.or(oldCurrent.trans);//将bs1的值复制到bs中
  240. is.trans.and(oldNext.trans);
  241. is.supports=is.trans.cardinality();
  242. writeToFile(is.items,is.supports);//将频繁项集及其支持度写入文件
  243. countItems++;
  244. modSum++;
  245. newLast.next=is;
  246. newLast=is;
  247. }
  248. }
  249. oldNext=oldNext.next;
  250. }
  251. oldCurrent=oldCurrent.next;
  252. }
  253. ItemSettemp1=hn.first;
  254. ItemSettemp2=hn.last;
  255. temp2.next=shareFirst.next;
  256. shareFirst.next=temp1;
  257. hn.first=newFirst.next;
  258. hn.last=newLast;
  259. hn.items=countItems;
  260. }
  261. publicbooleancontainItems(BitSetcontainItems,BitSetbsItems2,ItemSetfirst)
  262. {
  263. longsize=containItems.cardinality();//项集数目
  264. intitemSum=0;
  265. inttemp=containItems.nextSetBit(0);
  266. while(true)
  267. {
  268. itemSum+=temp;
  269. temp=containItems.nextSetBit(temp+1);
  270. if(temp==-1)
  271. {
  272. break;
  273. }
  274. }
  275. inthash=itemSum%(ItemSet.ItemSize*3);
  276. HashNodehn=hashTable[hash].next;
  277. Nodepre=hashTable[hash];
  278. while(true)
  279. {
  280. if(hn==null)//不包含containItems
  281. {
  282. HashNodenode=newHashNode();
  283. node.bs.or(containItems);
  284. pre.next=node;
  285. returnfalse;
  286. }
  287. if(hn.bs.isEmpty())
  288. {
  289. hn.bs.or(containItems);
  290. returnfalse;
  291. }
  292. bsItems2.clear();
  293. bsItems2.or(containItems);
  294. bsItems2.and(hn.bs);
  295. if(bsItems2.cardinality()==size)
  296. {
  297. returntrue;
  298. }
  299. pre=hn;
  300. hn=hn.next;
  301. }
  302. }
  303. publicvoidclear(HashHeadNode[]hashTable)
  304. {
  305. for(inti=0;i<hashTable.length;i++)
  306. {
  307. HashNodenode=hashTable[i].next;
  308. while(node!=null)
  309. {
  310. node.bs.clear();
  311. node=node.next;
  312. }
  313. }
  314. }
  315. publicvoidwriteToFile(BitSetitems,intsupports)
  316. {
  317. StringBuildersb=newStringBuilder();
  318. //sb.append("<");
  319. inttemp=items.nextSetBit(0);
  320. sb.append(temp);
  321. while(true)
  322. {
  323. temp=items.nextSetBit(temp+1);
  324. if(temp==-1)
  325. {
  326. break;
  327. }
  328. //sb.append(",");
  329. sb.append("");
  330. sb.append(temp);
  331. }
  332. sb.append(":"+""+supports);
  333. try{
  334. bw.write(sb.toString());
  335. bw.write("\n");
  336. }catch(IOExceptione){
  337. e.printStackTrace();
  338. }
  339. }
  340. publicstaticvoidmain(String[]args){
  341. EclatReleasee=newEclatRelease();
  342. longbegin=System.currentTimeMillis();
  343. e.init();
  344. e.start();
  345. longend=System.currentTimeMillis();
  346. doubletime=(double)(end-begin)/1000;
  347. System.out.println("共耗时"+time+"秒");
  348. System.out.println("频繁模式数目:"+EclatRelease.modSum);
  349. }
  350. }
  351. classMyMap<T,E>extendsTreeMap
  352. {
  353. publicvoidadd(Tobj)
  354. {
  355. if(this.containsKey(obj))
  356. {
  357. intvalue=(Integer)this.get(obj);
  358. this.put(obj,value+1);
  359. }
  360. else
  361. this.put(obj,1);
  362. }
  363. }
ItemSet类如下
[java] view plain copy 在CODE上查看代码片 派生到我的代码片
  1. packagecom.pku.yhf;
  2. importjava.util.BitSet;
  3. publicclassItemSet{
  4. publicstaticintlimitSupport;//根据阈值计算出的最小支持度数
  5. publicstaticintItemSize;//Items数目
  6. publicstaticintTransSize;//事务数目
  7. publicbooleanflag=true;//true,表示作为真正的ItemSet,false只作为标记节点,只在HashTabel中使用
  8. publicintitem=0;//某项集
  9. publicintsupports=0;//项集的支持度
  10. publicBitSetitems=null;
  11. publicBitSettrans=null;
  12. //publicTreeSetitems=newTreeSet();//项集
  13. //publicTreeSettrans=newTreeSet();//事务集合
  14. publicItemSetnext=null;//下一个项集
  15. publicItemSet(booleanflag)
  16. {
  17. this.flag=flag;
  18. if(flag)
  19. {
  20. item=0;//某项集
  21. supports=0;//项集的支持度
  22. items=newBitSet(ItemSize+1);
  23. trans=newBitSet(TransSize+1);
  24. }
  25. }
  26. }
对mushroom.dat的频繁模式挖掘结果如下


后期打算实现北大邓志鸿老师提出的PPV-Tree算法(基于节点列表的频繁模式挖掘算法),挖掘速度超过Han Jiawei教授的FP-Growth算法,敬请关注:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值