1、数据挖掘课后作业 5.4(实现项目)使用你熟悉的程序设计语言(如C++或Java),实现本章介绍的三种频繁项集挖掘算法:(1)Apriori [AS94B],(2)FP增长[HPY00]和(3)ECLAT [Zak00](使用垂直数据格式挖掘)。在各种类型的大型数据集上比较每种算法的性能。写一个报告,分析在哪些情况下(如数据大小、数据分布、最小支持阀度值设置和模式的稠密度),某种算法比其他算法好,并陈述理由。 三种算法的比较 1、对与项集较大,频繁项集较分散,是一个稀疏型的数据集,性能为Apriori>FP-growth>Eclat 2、对与数据集的项集较小,数据非常稠密的数据
2、集,性能为:FP-growth>Apriori>Eclat 各算法采用的数据表示模式及挖掘策略不同。采用优化措施后的 Apriori算法,对于非稠密数据己经具有较高的效率,其性能甚至优于FP-growth 算法;但由于其采用的是广度优先的挖掘策略,对稠密数据效率仍较差。而 Eclat 算法采用的纵向表示法,对数据集较小的稠密数据,效率相对较高;但对于数据集较大的稀疏数据,效率较低,FP一树浓缩了数据库的主要信息,分而治之的挖掘策略也使挖掘问题的复杂程度有所降低。 答:(1)Apriori算法的实现:使用Java语言实现Apriori算法,AprioriAlgorithm类包含了频繁项集
3、的挖掘过程和频繁关联规则的挖掘过程;ProperSubsetCombination辅助类用于计算一个频繁项集的真子集,采用组合原理,基于数值编码原理实现的组合求解集合的真子集。 Apriori算法的核心实现类为AprioriAlgorithm,实现的Java代码如下所示: (一)核心类 package org.shirdrn.datamining.association; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; imp
4、ort java.util.Set; import java.util.TreeMap; /** * 关联规则挖掘:Apriori算法 * *
该算法基本上按照Apriori算法的基本思想来实现的。
*/
public class AprioriAlgorithm {
private Map
5、eCount; // 事务数据库中的事务数
private Map
6、atabase;
this.minSup = minSup;
this.minConf = minConf;
this.txDatabaseCount = this.txDatabase.size();
freqItemSet = new TreeMap
7、Set
8、t.hasNext()) {
Map.Entry
9、}
/**
* 计算候选频繁1-项集
* @return
*/
public Map
10、ile(it.hasNext()) {
Map.Entry
11、 = 1; candFreq1ItemSetMap.put(key, value); } else { Integer value = 1+candFreq1ItemSetMap.get(key); candFreq1ItemSetMap.put(key, value); } } } return candFreq1ItemSetMap; } /** * 根据频繁(k-1)-项集计算候选频繁k-项集 * * @param m 其中m=k-1 * @param freqMIt
12、emSet 频繁(k-1)-项集
* @return
*/
public Set
13、 originalItemSet = it.next();
Iterator
14、xt();
identicalSet.retainAll(set); // identicalSet中剩下的元素是identicalSet与set集合中公有的元素
if(identicalSet.size() == m-1) { // (k-1)-项集中k-2个相同
Set
15、l(set); // 因为有k-2个相同,则differentSet中一定剩下一个元素,即differentSet大小为1 differentSet.addAll(set); // 构造候选k-项集的一个元素(set大小为k-1,differentSet大小为k) candFreqKItemSet.add(differentSet); // 加入候选k-项集集合 } } } return candFreqKItemSet; } /** * 根据一个频繁k-项集的元素(集合),获取到频繁k-项集的从该元素开始的迭代器实例
16、
* @param itemSet
* @param freqKItemSet 频繁k-项集
* @return
*/
private Iterator
17、
}
return it;
}
/**
* 根据频繁(k-1)-项集,调用aprioriGen方法,计算频繁k-项集
*
* @param k
* @param freqMItemSet 频繁(k-1)-项集
* @return
*/
public Map
18、 Integer>();
// 调用aprioriGen方法,得到候选频繁k-项集
Set 19、>> entry = it.next();
Iterator 20、mpty()) { // 如果拷贝set为空,支持数加1
if(candFreqKItemSetMap.get(kSet) == null) {
Integer value = 1;
candFreqKItemSetMap.put(kSet, value);
}
else {
Integer value = 1+candFreqKItemSetMap.get(kSet);
candFreqKItemSetMap.put(kSet, value);
}
}
21、 }
}
// 计算支持度,生成频繁k-项集,并返回
return support(candFreqKItemSetMap);
}
/**
* 根据候选频繁k-项集,得到频繁k-项集
*
* @param candFreqKItemSetMap 候选k项集(包含支持计数)
*/
public Map 22、w HashMap 23、atabaseCount);
if(supportRate 24、emSet = this.getFreq1ItemSet().keySet();
freqItemSet.put(1, freqKItemSet);
// 计算频繁k-项集(k>1)
int k = 2;
while(true) {
Map 25、ap.keySet());
freqKItemSet = freqKItemSetMap.keySet();
}
else {
break;
}
k++;
}
}
/**
* 挖掘频繁关联规则
* 首先挖掘出全部的频繁项集,在此基础上挖掘频繁关联规则
*/
public void mineAssociationRules() {
freqItemSet.remove(1); // 删除频繁1-项集
Iterator 26、g>>>> it = freqItemSet.entrySet().iterator();
while(it.hasNext()) {
Map.Entry 27、掘
* @param itemSet 频繁项集集合freqItemSet中的一个频繁项集元素
*/
public void mine(Set 28、t);
// 对条件的真子集集合中的每个条件项集,获取到对应的结论项集,从而进一步挖掘频繁关联规则
for(Set 29、et); // 调用计算置信度的方法,并且挖掘出频繁关联规则
}
}
}
/**
* 对得到的一个条件项集和对应的结论项集,计算该关联规则的支持计数,从而根据置信度判断是否是频繁关联规则
* @param conditionSet 条件频繁项集
* @param conclusionSet 结论频繁项集
*/
public void confide(Set 30、String>>> it = txDatabase.entrySet().iterator();
// 统计关联规则支持计数
int conditionToConclusionCnt = 0; // 关联规则(条件项集推出结论项集)计数
int conclusionToConditionCnt = 0; // 关联规则(结论项集推出条件项集)计数
int supCnt = 0; // 关联规则支持计数
while(it.hasNext()) {
Map.Entry 31、
Set 32、 conditionToConclusionCnt++;
}
set2.addAll(conclusionSet);
set2.removeAll(txSet); // 集合差运算:set-txSet
if(set2.isEmpty()) { // 如果set为空,说明事务数据库中包含结论频繁项conclusionSet
// 计数
conclusionToConditionCnt++;
}
if(set1.isEmpty() && set2.isEmpty()) {
supCn 33、t++;
}
}
// 计算置信度
Float conditionToConclusionConf = new Float(supCnt)/new Float(conditionToConclusionCnt);
if(conditionToConclusionConf>=minConf) {
if(assiciationRules.get(conditionSet) == null) { // 如果不存在以该条件频繁项集为条件的关联规则
Set 34、t 35、nCnt);
if(conclusionToConditionConf>=minConf) {
if(assiciationRules.get(conclusionSet) == null) { // 如果不存在以该结论频繁项集为条件的关联规则
Set 36、et);
}
else {
assiciationRules.get(conclusionSet).add(conditionSet);
}
}
}
/**
* 经过挖掘得到的频繁项集Map
*
* @return 挖掘得到的频繁项集集合
*/
public Map 37、ap 38、
* 求频繁项集元素(集合)的非空真子集集合
* 从一个集合(大小为n)中取出m(m属于2~n/2的闭区间)个元素的组合实现类,获取非空真子集的集合
*/
public class ProperSubsetCombination {
private static String[] array;
private static BitSet startBitSet; // 比特集合起始状态
private static BitSet endBitSet; // 比特集合终止状态,用来控制循环
private static Set 39、erSubset; // 真子集集合
/**
* 计算得到一个集合的非空真子集集合
*
* @param n 真子集的大小
* @param itemSet 一个频繁项集元素
* @return 非空真子集集合
*/
public static Set 40、y);
properSubset = new HashSet 41、et.set(i, true);
}
// 根据起始startBitSet,将一个组合加入到真子集集合中
get(startBitSet);
while(!startBitSet.equals(endBitSet)) {
int zeroCount = 0; // 统计遇到10后,左边0的个数
int oneCount = 0; // 统计遇到10后,左边1的个数
int pos = 0; // 记录当前遇到10的索引位置
// 遍历startBitSet来确定10出现的位置
fo 42、r (int i=0; i 43、k;
}
}
// 将遇到10后,左侧的1全部移动到最左侧
int counter = Math.min(zeroCount, oneCount);
int startIndex = 0;
int endIndex = 0;
if(pos>1 && counter>0) {
pos--;
endIndex = pos;
for (int i=0; i 44、tBitSet.set(endIndex, false);
startIndex = i+1;
pos--;
if(pos>0) {
endIndex = pos;
}
}
}
get(startBitSet);
}
return properSubset;
}
/**
* 根据一次移位操作得到的startBitSet,得到一个真子集
* @param bitSet
*/
private static void get(BitSet bitSet) {
45、 Set 46、include 47、tor 48、 cout< 49、 head_table;
void insert(Item * root,Item **vec,int curP,int maxSize,int );
public :
Item * root;
vector 50、 vector






