(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项集中只有一个项集时循环结束。
2. 从2项集开始循环,由频繁k-1项集生成频繁频繁k项集。
2.1 频繁k-1项集两两组合,判定是否可以连接,若能则连接生成k项集。
2.2 对k项集中的每个项集检测其子集是否频繁,舍弃掉子集不是频繁项集即 不在频繁k-1项集中的项集。
2.3 扫描数据库,计算2.3步中过滤后的k项集的支持度,舍弃掉支持度小于阈值的项集,生成频繁k项集。
3. 若当前k项集中只有一个项集时循环结束。
伪代码如下:

JAVA实现代码
package com.pku.yangliu;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**频繁模式挖掘算法Apriori实现
*
*/
public class AprioriFPMining {
private int minSup;//最小支持度
private static List<Set<String>> dataTrans;//以List<Set<String>>格式保存的事物数据库,利用Set的有序性
public int getMinSup() {
return minSup;
}
public void setMinSup(int minSup) {
this.minSup = minSup;
}
/**
* @param args
*/
public static void main(String[] args) throws IOException {
AprioriFPMining apriori = new AprioriFPMining();
double [] threshold = {0.25, 0.20, 0.15, 0.10, 0.05};
String srcFile = "F:/DataMiningSample/FPmining/Mushroom.dat";
String shortFileName = srcFile.split("/")[3];
String targetFile = "F:/DataMiningSample/FPmining/" + shortFileName.substring(0, shortFileName.indexOf("."))+"_fp_threshold";
dataTrans = apriori.readTrans(srcFile);
for(int k = 0; k < threshold.length; k++){
System.out.println(srcFile + " threshold: " + threshold[k]);
long totalItem = 0;
long totalTime = 0;
FileWriter tgFileWriter = new FileWriter(targetFile + (threshold[k]*100));
apriori.setMinSup((int)(dataTrans.size() * threshold[k]));//原始蘑菇的数据0.25只需要67秒跑出结果
long startTime = System.currentTimeMillis();
Map<String, Integer> f1Set = apriori.findFP1Items(dataTrans);
long endTime = System.currentTimeMillis();
totalTime += endTime - startTime;
//频繁1项集信息得加入支持度
Map<Set<String>, Integer> f1Map = new HashMap<Set<String>, Integer>();
for(Map.Entry<String, Integer> f1Item : f1Set.entrySet()){
Set<String> fs = new HashSet<String>();
fs.add(f1Item.getKey());
f1Map.put(fs, f1Item.getValue());
}
totalItem += apriori.printMap(f1Map, tgFileWriter);
Map<Set<String>, Integer> result = f1Map;
do {
startTime = System.currentTimeMillis();
result = apriori.genNextKItem(result);
endTime = System.currentTimeMillis();
totalTime += endTime - startTime;
totalItem += apriori.printMap(result, tgFileWriter);
} while(result.size() != 0);
tgFileWriter.close();
System.out.println("共用时:" + totalTime + "ms");
System.out.println("共有" + totalItem + "项频繁模式");
}
}
/**由频繁K-1项集生成频繁K项集
* @param preMap 保存频繁K项集的map
* @param tgFileWriter 输出文件句柄
* @return int 频繁i项集的数目
* @throws IOException
*/
private Map<Set<String>, Integer> genNextKItem(Map<Set<String>, Integer> preMap) {
// TODO Auto-generated method stub
Map<Set<String>, Integer> result = new HashMap<Set<String>, Integer>();
//遍历两个k-1项集生成k项集
List<Set<String>> preSetArray = new ArrayList<Set<String>>();
for(Map.Entry<Set<String>, Integer> preMapItem : preMap.entrySet()){
preSetArray.add(preMapItem.getKey());
}
int preSetLength = preSetArray.size();
for (int i = 0; i < preSetLength - 1; i++) {
for (int j = i + 1; j < preSetLength; j++) {
String[] strA1 = preSetArray.get(i).toArray(new String[0]);
String[] strA2 = preSetArray.get(j).toArray(new String[0]);