java实现Apriori算法

//注:本代码实现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 文本文件(中药数据)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值