//注:本代码实现Apriori的产生频繁集操作,没有产生关联规则,代码测试没有问题
package com.test;
 import java.util.Map; 

 import java.util.HashMap; 

 import java.util.Set; 

 import java.util.HashSet; 

 import java.util.List; 

 import java.util.LinkedList; 

 import java.io.BufferedReader; 

 import java.io.FileNotFoundException; 

 import java.io.FileReader; 

 import java.io.IOException; 

 import java.util.Collections; 



 public class Apriori { 

int i = 1; 

public static String SPLIT = "、"; 

public static void main(String[] args) throws IOException { 
 

double minsup = 0.3; 

         Apriori ap = new Apriori(); 

         List<Set<String>> data = ap.getData(); 

         ap.operateFunc(data, null, minsup, 1); 

} 

 /** 

  * 实施Apriori的核心方法 

  * @param data  原始数据集 

  * @param fData  频繁集 

  * @param minsup  最小支持度 

  */ 

public void operateFunc(List<Set<String>> data, List<Set<String>> fData, Double minsup, int k){ 

Map<Set<String>, Double> keySupport  = new HashMap<Set<String>, Double>(); 

List<Set<String>> cData = new LinkedList<Set<String>>(); 

if(fData == null){            //产生f1频繁集的数据来源 

Set<String> items = getItems(data); 
 

   for(String str: items){    //原理上是不用将items重新添加到Set中,但这样的话 f1项集的数据来源为Set<String> 在计算最小支持度和减枝操作都不能使用数据类型为List<Set<String>> 的方法了,为了统一,不用写countSupport方法和prune方法的重载,故将其添加到Set集合中 

    
 Set<String> set = new HashSet<String>(); 

    
 set.add(str); 

    
 cData.add(set); 

   } 

} 

else{ 

   cData = combine(fData, ++k); 

} 

 

 

for(Set<String> set: cData){ 

keySupport.put(set, countSupport(data, set)); //根据候选集计算其每一个候选条目的支持度 

} 

List<Set<String>> newFData = prune(keySupport, minsup); //候选集经过减枝成为新一轮的频繁集 

 

//k+1项频繁集为空,结束 

if(newFData.isEmpty()){ 

return; 
  

} 
  

System.out.println("第 " + i +" 次迭代"); 

for(Set<String> res: newFData){ 

System.out.println( keySupport.get(res) + " " + res); 

} 

i++; 

operateFunc(data, newFData, minsup, k); 
 

} 

 

/** 

* 自连接操作 

* @param fData 每一次迭代所产生的频繁集数据 

* @param k 代表第k次的迭代 

* @return 

*/ 

public List<Set<String>> combine(List<Set<String>> fData, int k){ 

List<Set<String>> comRes = new LinkedList<Set<String>>(); 

 for(int i = 0; i < fData.size(); i++){ 

 Set<String> set1 = fData.get(i); 

 for(int j = i + 1; j < fData.size(); j++){ 

 Set<String> set2 = new HashSet<String>(fData.get(j)); 

 set2.addAll(set1); 

 if(!comRes.contains(set2) && set2.size() == k){     //set无序 例如set1集合有{"a","b"}, set2集合有{"b","a"}采用list的contains方法可以检测出set1和set2是一样的, 

 comRes.add(set2);           //在数据上没有什么区别,不会因为顺序的不同而认为这是两组不同的数据,这在自连接的时候不我们去编写 函数去判断 

 } 
   

 } 
   

 } 
  

return comRes; 

} 



/** 

* 计算单个条目在原始数据的支持度 

* @param data   原始数据集合 

* @param subSet  单个候选条目 

* @return   返回每一个条目在原始数据的支持度 

*/ 

public Double countSupport(List<Set<String>> data, Set<String> subSet){ 

int count = 0; 

for(Set<String> dat: data){ 

if(dat.containsAll(subSet)){ 

count++; 

} 

} 

return 1.0 * count / data.size(); 

} 

 

/** 

* 得到新的频繁集 

* @param cData  每次迭代产生的候选集 

* @param minsup  最小支持度 

* @return 经过减枝得到新的频繁集 

*/ 

public List<Set<String>> prune(Map<Set<String>, Double> cData, Double minsup){ 

List<Set<String>> pruRes = new LinkedList<Set<String>>(); 

for(Map.Entry<Set<String>, Double> entry: cData.entrySet()){ 

if(entry.getValue() > minsup){ 

pruRes.add(entry.getKey()); 

} 

} 
  

return pruRes; 

} 

 

/** 

* 获取原始数据库的不重复的项 

* @param data 传入的原始文本数据 

* @return  返回不重复的数据条目 

*/ 

public Set<String> getItems(List<Set<String>> data){ 
 

Set<String> items = new HashSet<String>(); 

for(Set<String> lineData: data){ 
 

for(String str: lineData){ 

items.add(str); 

} 
  

} 
  

return items; 

} 

/** 

* @return 返回文本数据 List<Set<String>>类型 

* @throws IOException 

*/ 

    public List<Set<String>> getData() throws IOException{ 

  String path = System.getProperty("user.dir") + "/data.txt"; 

  List<Set<String>> data = new LinkedList<Set<String>>();    

  try { 

  FileReader fr = new FileReader(path); 

@SuppressWarnings("resource") 

BufferedReader br  = new BufferedReader(fr); 

String line  = br.readLine(); 

while(line != null){ 

Set<String> set = new HashSet<String>(); 

   Collections.addAll(set, line.split(SPLIT)); 

   data.add(set); 

   line = br.readLine(); 

} 

  } 

catch (FileNotFoundException e) { 

e.printStackTrace(); 

  } 
   

   return data; 

    } 

}




数据  在第一层目录下建立data.txt 文本文件(中药数据)

苍术、厚朴、半夏、人参、茯苓、草果、藿香、橘皮、甘草
半夏、白术、生姜、茯苓、人参、桂心、甘草
乌药、人参、白术、川芎、当归、茯神、甘草、白芷
人参、白术、茯苓、山药、陈皮、木香、砂仁、炙黄芪、当归
人参、鹿茸、补骨脂、巴戟天、当归、杜仲、牛膝、茯苓