mysql中怎么实现Apriori_Apriori算法实现

本文详细介绍了Apriori算法的实现过程,包括扫描事务数据库计算频繁项集、使用先验知识进行剪枝等关键步骤。通过Java代码展示了如何在MySQL环境中应用Apriori算法,同时提供了测试类以验证算法效果。
摘要由CSDN通过智能技术生成

import java.util.HashMap;

import java.util.HashSet;

import java.util.Iterator;

import java.util.Map;

import java.util.Set;

import java.util.TreeMap;

/**

* 关联规则挖掘:Apriori算法

*

*

按照Apriori算法的基本思想来实现

*

* @author king

* @since 2013/06/27

*

*/

public class Apriori {

private Map> txDatabase; // 事务数据库

private Float minSup; // 最小支持度

private Float minConf; // 最小置信度

private Integer txDatabaseCount; // 事务数据库中的事务数

private Map>> freqItemSet; // 频繁项集集合

private Map, Set>> assiciationRules; // 频繁关联规则集合

public Apriori(

Map> txDatabase,

Float minSup,

Float minConf) {

this.txDatabase = txDatabase;

this.minSup = minSup;

this.minConf = minConf;

this.txDatabaseCount = this.txDatabase.size();

freqItemSet = new TreeMap>>();

assiciationRules = new HashMap, Set>>();

}

/**

* 扫描事务数据库,计算频繁1-项集

* @return

*/

public Map, Float> getFreq1ItemSet() {

Map, Float> freq1ItemSetMap = new HashMap, Float>();

Map, Integer> candFreq1ItemSet = this.getCandFreq1ItemSet();

Iterator, Integer>> it = candFreq1ItemSet.entrySet().iterator();

while(it.hasNext()) {

Map.Entry, Integer> entry = it.next();

// 计算支持度

Float supported = new Float(entry.getValue().toString())/new Float(txDatabaseCount);

if(supported>=minSup) {

freq1ItemSetMap.put(entry.getKey(), supported);

}

}

return freq1ItemSetMap;

}

/**

* 计算候选频繁1-项集

* @return

*/

public Map, Integer> getCandFreq1ItemSet() {

Map, Integer> candFreq1ItemSetMap = new HashMap, Integer>();

Iterator>> it = txDatabase.entrySet().iterator();

// 统计支持数,生成候选频繁1-项集

while(it.hasNext()) {

Map.Entry> entry = it.next();

Set itemSet = entry.getValue();

for(String item : itemSet) {

Set key = new HashSet();

key.add(item.trim());

if(!candFreq1ItemSetMap.containsKey(key)) {

Integer value = 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 freqMItemSet 频繁(k-1)-项集

* @return

*/

public Set> aprioriGen(int m, Set> freqMItemSet) {

Set> candFreqKItemSet = new HashSet>();

Iterator> it = freqMItemSet.iterator();

Set originalItemSet = null;

while(it.hasNext()) {

originalItemSet = it.next();

Iterator> itr = this.getIterator(originalItemSet, freqMItemSet);

while(itr.hasNext()) {

Set identicalSet = new HashSet(); // 两个项集相同元素的集合(集合的交运算)

identicalSet.addAll(originalItemSet);

Set set = itr.next();

identicalSet.retainAll(set); // identicalSet中剩下的元素是identicalSet与set集合中公有的元素

if(identicalSet.size() == m-1) { // (k-1)-项集中k-2个相同

Set differentSet = new HashSet(); // 两个项集不同元素的集合(集合的差运算)

differentSet.addAll(originalItemSet);

differentSet.removeAll(set); // 因为有k-2个相同,则differentSet中一定剩下一个元素,即differentSet大小为1

differentSet.addAll(set); // 构造候选k-项集的一个元素(set大小为k-1,differentSet大小为k)

if(!this.has_infrequent_subset(differentSet, freqMItemSet))

candFreqKItemSet.add(differentSet); // 加入候选k-项集集合

}

}

}

return candFreqKItemSet;

}

/**

* 使用先验知识,剪枝。若候选k项集中存在k-1项子集不是频繁k-1项集,则删除该候选k项集

* @param candKItemSet

* @param freqMItemSet

* @return

*/

private boolean has_infrequent_subset(Set candKItemSet, Set> freqMItemSet) {

Set tempSet = new HashSet();

tempSet.addAll(candKItemSet);

Iterator itItem = candKItemSet.iterator();

while(itItem.hasNext()) {

String item = itItem.next();

tempSet.remove(item);// 该候选去掉一项后变为k-1项集

if(!freqMItemSet.contains(tempSet))// 判断k-1项集是否是频繁项集

return true;

tempSet.add(item);// 恢复

}

return false;

}

/**

* 根据一个频繁k-项集的元素(集合),获取到频繁k-项集的从该元素开始的迭代器实例

* @param itemSet

* @param freqKItemSet 频繁k-项集

* @return

*/

private Iterator> getIterator(Set itemSet, Set> freqKItemSet) {

Iterator> it = freqKItemSet.iterator();

while(it.hasNext()) {

if(itemSet.equals(it.next())) {

break;

}

}

return it;

}

/**

* 根据频繁(k-1)-项集,调用aprioriGen方法,计算频繁k-项集

*

* @param k

* @param freqMItemSet 频繁(k-1)-项集

* @return

*/

public Map, Float> getFreqKItemSet(int k, Set> freqMItemSet) {

Map, Integer> candFreqKItemSetMap = new HashMap, Integer>();

// 调用aprioriGen方法,得到候选频繁k-项集

Set> candFreqKItemSet = this.aprioriGen(k-1, freqMItemSet);

// 扫描事务数据库

Iterator>> it = txDatabase.entrySet().iterator();

// 统计支持数

while(it.hasNext()) {

Map.Entry> entry = it.next();

Iterator> kit = candFreqKItemSet.iterator();

while(kit.hasNext()) {

Set kSet = kit.next();

Set set = new HashSet();

set.addAll(kSet);

set.removeAll(entry.getValue()); // 候选频繁k-项集与事务数据库中元素做差运算

if(set.isEmpty()) { // 如果拷贝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);

}

}

}

}

// 计算支持度,生成频繁k-项集,并返回

return support(candFreqKItemSetMap);

}

/**

* 根据候选频繁k-项集,得到频繁k-项集

*

* @param candFreqKItemSetMap 候选k项集(包含支持计数)

* @return freqKItemSetMap 频繁k项集及其支持度(比例)

*/

public Map, Float> support(Map, Integer> candFreqKItemSetMap) {

Map, Float> freqKItemSetMap = new HashMap, Float>();

Iterator, Integer>> it = candFreqKItemSetMap.entrySet().iterator();

while(it.hasNext()) {

Map.Entry, Integer> entry = it.next();

// 计算支持度

Float supportRate = new Float(entry.getValue().toString())/new Float(txDatabaseCount);

if(supportRate

it.remove();

}

else {

freqKItemSetMap.put(entry.getKey(), supportRate);

}

}

return freqKItemSetMap;

}

/**

* 挖掘全部频繁项集

*/

public void mineFreqItemSet() {

// 计算频繁1-项集

Set> freqKItemSet = this.getFreq1ItemSet().keySet();

freqItemSet.put(1, freqKItemSet);

// 计算频繁k-项集(k>1)

int k = 2;

while(true) {

Map, Float> freqKItemSetMap = this.getFreqKItemSet(k, freqKItemSet);

if(!freqKItemSetMap.isEmpty()) {

this.freqItemSet.put(k, freqKItemSetMap.keySet());

freqKItemSet = freqKItemSetMap.keySet();

}

else {

break;

}

k++;

}

}

/**

*

挖掘频繁关联规则

*

首先挖掘出全部的频繁项集,在此基础上挖掘频繁关联规则

*/

public void mineAssociationRules() {

freqItemSet.remove(1); // 删除频繁1-项集

Iterator>>> it = freqItemSet.entrySet().iterator();

while(it.hasNext()) {

Map.Entry>> entry = it.next();

for(Set itemSet : entry.getValue()) {

// 对每个频繁项集进行关联规则的挖掘

mine(itemSet);

}

}

}

/**

* 对从频繁项集集合freqItemSet中每迭代出一个频繁项集元素,执行一次关联规则的挖掘

* @param itemSet 频繁项集集合freqItemSet中的一个频繁项集元素

*/

public void mine(Set itemSet) {

int n = itemSet.size()/2; // 根据集合的对称性,只需要得到一半的真子集

for(int i=1; i<=n; i++) {

// 得到频繁项集元素itemSet的作为条件的真子集集合

Set> properSubset = ProperSubsetCombination.getProperSubset(i, itemSet);

// 对条件的真子集集合中的每个条件项集,获取到对应的结论项集,从而进一步挖掘频繁关联规则

for(Set conditionSet : properSubset) {

Set conclusionSet = new HashSet();

conclusionSet.addAll(itemSet);

conclusionSet.removeAll(conditionSet); // 删除条件中存在的频繁项

confide(conditionSet, conclusionSet); // 调用计算置信度的方法,并且挖掘出频繁关联规则

}

}

}

/**

* 对得到的一个条件项集和对应的结论项集,计算该关联规则的支持计数,从而根据置信度判断是否是频繁关联规则

* @param conditionSet 条件频繁项集

* @param conclusionSet 结论频繁项集

*/

public void confide(Set conditionSet, Set conclusionSet) {

// 扫描事务数据库

Iterator>> it = txDatabase.entrySet().iterator();

// 统计关联规则支持计数

int conditionToConclusionCnt = 0; // 关联规则(条件项集推出结论项集)计数

int conclusionToConditionCnt = 0; // 关联规则(结论项集推出条件项集)计数

int supCnt = 0; // 关联规则支持计数

while(it.hasNext()) {

Map.Entry> entry = it.next();

Set txSet = entry.getValue();

Set set1 = new HashSet();

Set set2 = new HashSet();

set1.addAll(conditionSet);

set1.removeAll(txSet); // 集合差运算:set-txSet

if(set1.isEmpty()) { // 如果set为空,说明事务数据库中包含条件频繁项conditionSet

// 计数

conditionToConclusionCnt++;

}

set2.addAll(conclusionSet);

set2.removeAll(txSet); // 集合差运算:set-txSet

if(set2.isEmpty()) { // 如果set为空,说明事务数据库中包含结论频繁项conclusionSet

// 计数

conclusionToConditionCnt++;

}

if(set1.isEmpty() && set2.isEmpty()) {

supCnt++;

}

}

// 计算置信度

Float conditionToConclusionConf = new Float(supCnt)/new Float(conditionToConclusionCnt);

if(conditionToConclusionConf>=minConf) {

if(assiciationRules.get(conditionSet) == null) { // 如果不存在以该条件频繁项集为条件的关联规则

Set> conclusionSetSet = new HashSet>();

conclusionSetSet.add(conclusionSet);

assiciationRules.put(conditionSet, conclusionSetSet);

}

else {

assiciationRules.get(conditionSet).add(conclusionSet);

}

}

Float conclusionToConditionConf = new Float(supCnt)/new Float(conclusionToConditionCnt);

if(conclusionToConditionConf>=minConf) {

if(assiciationRules.get(conclusionSet) == null) { // 如果不存在以该结论频繁项集为条件的关联规则

Set> conclusionSetSet = new HashSet>();

conclusionSetSet.add(conditionSet);

assiciationRules.put(conclusionSet, conclusionSetSet);

}

else {

assiciationRules.get(conclusionSet).add(conditionSet);

}

}

}

/**

* 经过挖掘得到的频繁项集Map

*

* @return 挖掘得到的频繁项集集合

*/

public Map>> getFreqItemSet() {

return freqItemSet;

}

/**

* 获取挖掘到的全部的频繁关联规则的集合

* @return 频繁关联规则集合

*/

public Map, Set>> getAssiciationRules() {

return assiciationRules;

}

}

测试类如下:

import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;

import java.util.HashMap;

import java.util.HashSet;

import java.util.Map;

import java.util.Set;

import java.util.TreeSet;

import junit.framework.TestCase;

/**

* Apriori算法测试类

*

* @author king

* @date 2013/07/28

*/

public class AprioriTest extends TestCase {

private Apriori apriori;

private Map> txDatabase;

private Float minSup = new Float("0.50");

private Float minConf = new Float("0.70");

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

AprioriTest at = new AprioriTest();

at.setUp();

long from = System.currentTimeMillis();

at.testGetFreqItemSet();

long to = System.currentTimeMillis();

System.out.println("耗时:" + (to-from));

}

@Override

protected void setUp() throws Exception {

// create(); // 构造事务数据库

this.buildData(Integer.MAX_VALUE, "f_faqk_.dat");

apriori = new Apriori(txDatabase, minSup, minConf);

}

/**

* 构造模拟事务数据库txDatabase

*/

public void create() {

txDatabase = new HashMap>();

Set set1 = new TreeSet();

set1.add("A");

set1.add("B");

set1.add("C");

set1.add("E");

txDatabase.put(1, set1);

Set set2 = new TreeSet();

set2.add("A");

set2.add("B");

set2.add("C");

txDatabase.put(2, set2);

Set set3 = new TreeSet();

set3.add("C");

set3.add("D");

txDatabase.put(3, set3);

Set set4 = new TreeSet();

set4.add("A");

set4.add("B");

set4.add("E");

txDatabase.put(4, set4);

}

/**

* 构造数据集

* @param fileName 存储事务数据的文件名

* @param totalcount 获取的事务数

*/

public void buildData(int totalCount, String...fileName) {

txDatabase = new HashMap>();

if(fileName.length !=0){

File file = new File(fileName[0]);

int count = 0;

try {

BufferedReader reader = new BufferedReader(new FileReader(file));

String line;

while( (line = reader.readLine()) != null){

String []arr = line.split(" ");

Set set = new HashSet();

for(String s : arr)

set.add(s);

count++;

this.txDatabase.put(count, set);

if(count >= totalCount) return;

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}else{

}

}

/**

* 测试挖掘频繁1-项集

*/

public void testFreq1ItemSet() {

System.out.println("挖掘频繁1-项集 : " + apriori.getFreq1ItemSet());

}

/**

* 测试aprioriGen方法,生成候选频繁项集

*/

public void testAprioriGen() {

System.out.println(

"候选频繁2-项集 : " +

this.apriori.aprioriGen(1, this.apriori.getFreq1ItemSet().keySet())

);

}

/**

* 测试挖掘频繁2-项集

*/

public void testGetFreq2ItemSet() {

System.out.println(

"挖掘频繁2-项集 :" +

this.apriori.getFreqKItemSet(2, this.apriori.getFreq1ItemSet().keySet())

);

}

/**

* 测试挖掘频繁3-项集

*/

public void testGetFreq3ItemSet() {

System.out.println(

"挖掘频繁3-项集 :" +

this.apriori.getFreqKItemSet(

3,

this.apriori.getFreqKItemSet(2, this.apriori.getFreq1ItemSet().keySet()).keySet()

)

);

}

/**

* 测试挖掘全部频繁项集

*/

public void testGetFreqItemSet() {

this.apriori.mineFreqItemSet(); // 挖掘频繁项集

System.out.println("挖掘频繁项集 :" + this.apriori.getFreqItemSet());

}

/**

* 测试挖掘全部频繁关联规则

*/

public void testMineAssociationRules() {

this.apriori.mineFreqItemSet(); // 挖掘频繁项集

this.apriori.mineAssociationRules();

System.out.println("挖掘频繁关联规则 :" + this.apriori.getAssiciationRules());

}

}

在此基础上添加了has_infrequent_subset方法,此方法使用先验知识进行剪枝,是典型Apriori算法必备的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值