用C++ 实现的 可以 到下载 不过要注册扣积分的
专注于为中小企业提供网站设计、成都网站制作服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业河曲免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了千余家企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
算法实现
(一)核心类
Apriori算法的核心实现类为AprioriAlgorithm,实现的Java代码如下所示:
package org.shirdrn.datamining.association;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* B关联规则挖掘:Apriori算法/B
*
* P该算法基本上按照Apriori算法的基本思想来实现的。
*
* @author shirdrn
* @date 2009/07/22 22:56:23
* @msn shirdrn#hotmail.com(#→@)
* @qq 187071722
*/
public class AprioriAlgorithm {
private MapInteger, SetString txDatabase; // 事务数据库
private Float minSup; // 最小支持度
private Float minConf; // 最小置信度
private Integer txDatabaseCount; // 事务数据库中的事务数
private MapInteger, SetSetString freqItemSet; // 频繁项集集合
private MapSetString, SetSetString assiciationRules; // 频繁关联规则集合
public AprioriAlgorithm(
MapInteger, SetString txDatabase,
Float minSup,
Float minConf) {
this.txDatabase = txDatabase;
this.minSup = minSup;
this.minConf = minConf;
this.txDatabaseCount = this.txDatabase.size();
freqItemSet = new TreeMapInteger, SetSetString();
assiciationRules = new HashMapSetString, SetSetString();
}
/**
* 扫描事务数据库,计算频繁1-项集
* @return
*/
public MapSetString, Float getFreq1ItemSet() {
MapSetString, Float freq1ItemSetMap = new HashMapSetString, Float();
MapSetString, Integer candFreq1ItemSet = this.getCandFreq1ItemSet();
IteratorMap.EntrySetString, Integer it = candFreq1ItemSet.entrySet().iterator();
while(it.hasNext()) {
Map.EntrySetString, 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 MapSetString, Integer getCandFreq1ItemSet() {
MapSetString, Integer candFreq1ItemSetMap = new HashMapSetString, Integer();
IteratorMap.EntryInteger, SetString it = txDatabase.entrySet().iterator();
// 统计支持数,生成候选频繁1-项集
while(it.hasNext()) {
Map.EntryInteger, SetString entry = it.next();
SetString itemSet = entry.getValue();
for(String item : itemSet) {
SetString key = new HashSetString();
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 SetSetString aprioriGen(int m, SetSetString freqMItemSet) {
SetSetString candFreqKItemSet = new HashSetSetString();
IteratorSetString it = freqMItemSet.iterator();
SetString originalItemSet = null;
while(it.hasNext()) {
originalItemSet = it.next();
IteratorSetString itr = this.getIterator(originalItemSet, freqMItemSet);
while(itr.hasNext()) {
SetString identicalSet = new HashSetString(); // 两个项集相同元素的集合(集合的交运算)
identicalSet.addAll(originalItemSet);
SetString set = itr.next();
identicalSet.retainAll(set); // identicalSet中剩下的元素是identicalSet与set集合中公有的元素
if(identicalSet.size() == m-1) { // (k-1)-项集中k-2个相同
SetString differentSet = new HashSetString(); // 两个项集不同元素的集合(集合的差运算)
differentSet.addAll(originalItemSet);
differentSet.removeAll(set); // 因为有k-2个相同,则differentSet中一定剩下一个元素,即differentSet大小为1
differentSet.addAll(set); // 构造候选k-项集的一个元素(set大小为k-1,differentSet大小为k)
candFreqKItemSet.add(differentSet); // 加入候选k-项集集合
}
}
}
return candFreqKItemSet;
}
/**
* 根据一个频繁k-项集的元素(集合),获取到频繁k-项集的从该元素开始的迭代器实例
* @param itemSet
* @param freqKItemSet 频繁k-项集
* @return
*/
private IteratorSetString getIterator(SetString itemSet, SetSetString freqKItemSet) {
IteratorSetString 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 MapSetString, Float getFreqKItemSet(int k, SetSetString freqMItemSet) {
MapSetString, Integer candFreqKItemSetMap = new HashMapSetString, Integer();
// 调用aprioriGen方法,得到候选频繁k-项集
SetSetString candFreqKItemSet = this.aprioriGen(k-1, freqMItemSet);
// 扫描事务数据库
IteratorMap.EntryInteger, SetString it = txDatabase.entrySet().iterator();
// 统计支持数
while(it.hasNext()) {
Map.EntryInteger, SetString entry = it.next();
IteratorSetString kit = candFreqKItemSet.iterator();
while(kit.hasNext()) {
SetString kSet = kit.next();
SetString set = new HashSetString();
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项集(包含支持计数)
*/
public MapSetString, Float support(MapSetString, Integer candFreqKItemSetMap) {
MapSetString, Float freqKItemSetMap = new HashMapSetString, Float();
IteratorMap.EntrySetString, Integer it = candFreqKItemSetMap.entrySet().iterator();
while(it.hasNext()) {
Map.EntrySetString, Integer entry = it.next();
// 计算支持度
Float supportRate = new Float(entry.getValue().toString())/new Float(txDatabaseCount);
if(supportRateminSup) { // 如果不满足最小支持度,删除
it.remove();
}
else {
freqKItemSetMap.put(entry.getKey(), supportRate);
}
}
return freqKItemSetMap;
}
/**
* 挖掘全部频繁项集
*/
public void mineFreqItemSet() {
// 计算频繁1-项集
SetSetString freqKItemSet = this.getFreq1ItemSet().keySet();
freqItemSet.put(1, freqKItemSet);
// 计算频繁k-项集(k1)
int k = 2;
while(true) {
MapSetString, Float freqKItemSetMap = this.getFreqKItemSet(k, freqKItemSet);
if(!freqKItemSetMap.isEmpty()) {
this.freqItemSet.put(k, freqKItemSetMap.keySet());
freqKItemSet = freqKItemSetMap.keySet();
}
else {
break;
}
k++;
}
}
/**
* P挖掘频繁关联规则
* P首先挖掘出全部的频繁项集,在此基础上挖掘频繁关联规则
*/
public void mineAssociationRules() {
freqItemSet.remove(1); // 删除频繁1-项集
IteratorMap.EntryInteger, SetSetString it = freqItemSet.entrySet().iterator();
while(it.hasNext()) {
Map.EntryInteger, SetSetString entry = it.next();
for(SetString itemSet : entry.getValue()) {
// 对每个频繁项集进行关联规则的挖掘
mine(itemSet);
}
}
}
/**
* 对从频繁项集集合freqItemSet中每迭代出一个频繁项集元素,执行一次关联规则的挖掘
* @param itemSet 频繁项集集合freqItemSet中的一个频繁项集元素
*/
public void mine(SetString itemSet) {
int n = itemSet.size()/2; // 根据集合的对称性,只需要得到一半的真子集
for(int i=1; i=n; i++) {
// 得到频繁项集元素itemSet的作为条件的真子集集合
SetSetString properSubset = ProperSubsetCombination.getProperSubset(i, itemSet);
// 对条件的真子集集合中的每个条件项集,获取到对应的结论项集,从而进一步挖掘频繁关联规则
for(SetString conditionSet : properSubset) {
SetString conclusionSet = new HashSetString();
conclusionSet.addAll(itemSet);
conclusionSet.removeAll(conditionSet); // 删除条件中存在的频繁项
confide(conditionSet, conclusionSet); // 调用计算置信度的方法,并且挖掘出频繁关联规则
}
}
}
/**
* 对得到的一个条件项集和对应的结论项集,计算该关联规则的支持计数,从而根据置信度判断是否是频繁关联规则
* @param conditionSet 条件频繁项集
* @param conclusionSet 结论频繁项集
*/
public void confide(SetString conditionSet, SetString conclusionSet) {
// 扫描事务数据库
IteratorMap.EntryInteger, SetString it = txDatabase.entrySet().iterator();
// 统计关联规则支持计数
int conditionToConclusionCnt = 0; // 关联规则(条件项集推出结论项集)计数
int conclusionToConditionCnt = 0; // 关联规则(结论项集推出条件项集)计数
int supCnt = 0; // 关联规则支持计数
while(it.hasNext()) {
Map.EntryInteger, SetString entry = it.next();
SetString txSet = entry.getValue();
SetString set1 = new HashSetString();
SetString set2 = new HashSetString();
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) { // 如果不存在以该条件频繁项集为条件的关联规则
SetSetString conclusionSetSet = new HashSetSetString();
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) { // 如果不存在以该结论频繁项集为条件的关联规则
SetSetString conclusionSetSet = new HashSetSetString();
conclusionSetSet.add(conditionSet);
assiciationRules.put(conclusionSet, conclusionSetSet);
}
else {
assiciationRules.get(conclusionSet).add(conditionSet);
}
}
}
/**
* 经过挖掘得到的频繁项集Map
*
* @return 挖掘得到的频繁项集集合
*/
public MapInteger, SetSetString getFreqItemSet() {
return freqItemSet;
}
/**
* 获取挖掘到的全部的频繁关联规则的集合
* @return 频繁关联规则集合
*/
public MapSetString, SetSetString getAssiciationRules() {
return assiciationRules;
}
}
(二)辅助类
ProperSubsetCombination类是一个辅助类,在挖掘频繁关联规则的过程中,用于生成一个频繁项集元素的非空真子集,实现代码如下:
package org.shirdrn.datamining.association;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Set;
/**
* B求频繁项集元素(集合)的非空真子集集合/B
* P从一个集合(大小为n)中取出m(m属于2~n/2的闭区间)个元素的组合实现类,获取非空真子集的集合
*
* @author shirdrn
* @date 2009/07/22 22:56:23
* @msn shirdrn#hotmail.com(#→@)
* @qq 187071722
*/
public class ProperSubsetCombination {
private static String[] array;
private static BitSet startBitSet; // 比特集合起始状态
private static BitSet endBitSet; // 比特集合终止状态,用来控制循环
private static SetSetString properSubset; // 真子集集合
/**
* 计算得到一个集合的非空真子集集合
*
* @param n 真子集的大小
* @param itemSet 一个频繁项集元素
* @return 非空真子集集合
*/
public static SetSetString getProperSubset(int n, SetString itemSet) {
String[] array = new String[itemSet.size()];
ProperSubsetCombination.array = itemSet.toArray(array);
properSubset = new HashSetSetString();
startBitSet = new BitSet();
endBitSet = new BitSet();
// 初始化startBitSet,左侧占满1
for (int i=0; in; i++) {
startBitSet.set(i, true);
}
// 初始化endBit,右侧占满1
for (int i=array.length-1; i=array.length-n; i--) {
endBitSet.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出现的位置
for (int i=0; iarray.length; i++) {
if (!startBitSet.get(i)) {
zeroCount++;
}
if (startBitSet.get(i) !startBitSet.get(i+1)) {
pos = i;
oneCount = i - zeroCount;
// 将10变为01
startBitSet.set(i, false);
startBitSet.set(i+1, true);
break;
}
}
// 将遇到10后,左侧的1全部移动到最左侧
int counter = Math.min(zeroCount, oneCount);
int startIndex = 0;
int endIndex = 0;
if(pos1 counter0) {
pos--;
endIndex = pos;
for (int i=0; icounter; i++) {
startBitSet.set(startIndex, true);
startBitSet.set(endIndex, false);
startIndex = i+1;
pos--;
if(pos0) {
endIndex = pos;
}
}
}
get(startBitSet);
}
return properSubset;
}
/**
* 根据一次移位操作得到的startBitSet,得到一个真子集
* @param bitSet
*/
private static void get(BitSet bitSet) {
SetString set = new HashSetString();
for(int i=0; iarray.length; i++) {
if(bitSet.get(i)) {
set.add(array[i]);
}
}
properSubset.add(set);
}
}
测试用例
对上述Apriori算法的实现进行了简单的测试,测试用例如下所示:
package org.shirdrn.datamining.association;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.shirdrn.datamining.association.AprioriAlgorithm;
import junit.framework.TestCase;
/**
* BApriori算法测试类/B
*
* @author shirdrn
* @date 2009/07/22 22:56:23
* @msn shirdrn#hotmail.com(#→@)
* @qq 187071722
*/
public class TestAprioriAlgorithm extends TestCase {
private AprioriAlgorithm apriori;
private MapInteger, SetString txDatabase;
private Float minSup = new Float("0.50");
private Float minConf = new Float("0.70");
@Override
protected void setUp() throws Exception {
create(); // 构造事务数据库
apriori = new AprioriAlgorithm(txDatabase, minSup, minConf);
}
/**
* 构造模拟事务数据库txDatabase
*/
public void create() {
txDatabase = new HashMapInteger, SetString();
SetString set1 = new TreeSetString();
set1.add("A");
set1.add("B");
set1.add("C");
set1.add("E");
txDatabase.put(1, set1);
SetString set2 = new TreeSetString();
set2.add("A");
set2.add("B");
set2.add("C");
txDatabase.put(2, set2);
SetString set3 = new TreeSetString();
set3.add("C");
set3.add("D");
txDatabase.put(3, set3);
SetString set4 = new TreeSetString();
set4.add("A");
set4.add("B");
set4.add("E");
txDatabase.put(4, set4);
}
/**
* 测试挖掘频繁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());
}
}
测试结果:
挖掘频繁1-项集 : {[E]=0.5, [A]=0.75, [B]=0.75, [C]=0.75}
候选频繁2-项集 : [[E, C], [A, B], [B, C], [A, C], [E, B], [E, A]]
挖掘频繁2-项集 :{[A, B]=0.75, [B, C]=0.5, [A, C]=0.5, [E, B]=0.5, [E, A]=0.5}
挖掘频繁3-项集 :{[E, A, B]=0.5, [A, B, C]=0.5}
挖掘频繁项集 :{1=[[E], [A], [B], [C]], 2=[[A, B], [B, C], [A, C], [E, B], [E, A]], 3=[[E, A, B], [A, B, C]]}
挖掘频繁关联规则 :{[E]=[[A], [B], [A, B]], [A]=[[B]], [B]=[[A]], [B, C]=[[A]], [A, C]=[[B]], [E, B]=[[A]], [E, A]=[[B]]}
从测试结果看到,使用Apriori算法挖掘得到的全部频繁项集为:
{1=[[E], [A], [B], [C]], 2=[[A, B], [B, C], [A, C], [E, B], [E, A]], 3=[[E, A, B], [A, B, C]]}
使用Apriori算法挖掘得到的全部频繁关联规则为:
{E}→{A}、{E}→{B}、{E}→{A,B}、{A}→{B}、{B}→{A}、{B,C}→{A}、{A,C}→{B}、{B,E}→{A}、{A,E}→{B}。
用C++ 实现的 可以 到下载 不过要注册扣积分的
算法实现
(一)核心类
Apriori算法的核心实现类为AprioriAlgorithm,实现的Java代码如下所示:
package org.shirdrn.datamining.association;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* B关联规则挖掘:Apriori算法/B
*
* P该算法基本上按照Apriori算法的基本思想来实现的。
*
* @author shirdrn
* @date 2009/07/22 22:56:23
* @msn shirdrn#hotmail.com(#→@)
* @qq 187071722
*/
public class AprioriAlgorithm {
private MapInteger, SetString txDatabase; // 事务数据库
private Float minSup; // 最小支持度
private Float minConf; // 最小置信度
private Integer txDatabaseCount; // 事务数据库中的事务数
private MapInteger, SetSetString freqItemSet; // 频繁项集集合
private MapSetString, SetSetString assiciationRules; // 频繁关联规则集合
public AprioriAlgorithm(
MapInteger, SetString txDatabase,
Float minSup,
Float minConf) {
this.txDatabase = txDatabase;
this.minSup = minSup;
this.minConf = minConf;
this.txDatabaseCount = this.txDatabase.size();
freqItemSet = new TreeMapInteger, SetSetString();
assiciationRules = new HashMapSetString, SetSetString();
}
/**
* 扫描事务数据库,计算频繁1-项集
* @return
*/
public MapSetString, Float getFreq1ItemSet() {
MapSetString, Float freq1ItemSetMap = new HashMapSetString, Float();
MapSetString, Integer candFreq1ItemSet = this.getCandFreq1ItemSet();
IteratorMap.EntrySetString, Integer it = candFreq1ItemSet.entrySet().iterator();
while(it.hasNext()) {
Map.EntrySetString
java中调用操作系统控制台(就是命令行),控制台里运行R脚本(可以在命令行里用Rscript,不一定要在R环境底下写)。
实在不行试试weka。
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
* B关联规则挖掘:Apriori算法/B
*
* P按照Apriori算法的基本思想来实现
*
* @author king
* @since 2013/06/27
*
*/
public class Apriori {
private MapInteger, SetString txDatabase; // 事务数据库
private Float minSup; // 最小支持度
private Float minConf; // 最小置信度
private Integer txDatabaseCount; // 事务数据库中的事务数
private MapInteger, SetSetString freqItemSet; // 频繁项集集合
private MapSetString, SetSetString assiciationRules; // 频繁关联规则集合
public Apriori(
MapInteger, SetString txDatabase,
Float minSup,
Float minConf) {
this.txDatabase = txDatabase;
this.minSup = minSup;
this.minConf = minConf;
this.txDatabaseCount = this.txDatabase.size();
freqItemSet = new TreeMapInteger, SetSetString();
assiciationRules = new HashMapSetString, SetSetString();
}
/**
* 扫描事务数据库,计算频繁1-项集
* @return
*/
public MapSetString, Float getFreq1ItemSet() {
MapSetString, Float freq1ItemSetMap = new HashMapSetString, Float();
MapSetString, Integer candFreq1ItemSet = this.getCandFreq1ItemSet();
IteratorMap.EntrySetString, Integer it = candFreq1ItemSet.entrySet().iterator();
while(it.hasNext()) {
Map.EntrySetString, 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 MapSetString, Integer getCandFreq1ItemSet() {
MapSetString, Integer candFreq1ItemSetMap = new HashMapSetString, Integer();
IteratorMap.EntryInteger, SetString it = txDatabase.entrySet().iterator();
// 统计支持数,生成候选频繁1-项集
while(it.hasNext()) {
Map.EntryInteger, SetString entry = it.next();
SetString itemSet = entry.getValue();
for(String item : itemSet) {
SetString key = new HashSetString();
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 SetSetString aprioriGen(int m, SetSetString freqMItemSet) {
SetSetString candFreqKItemSet = new HashSetSetString();
IteratorSetString it = freqMItemSet.iterator();
SetString originalItemSet = null;
while(it.hasNext()) {
originalItemSet = it.next();
IteratorSetString itr = this.getIterator(originalItemSet, freqMItemSet);
while(itr.hasNext()) {
SetString identicalSet = new HashSetString(); // 两个项集相同元素的集合(集合的交运算)
identicalSet.addAll(originalItemSet);
SetString set = itr.next();
identicalSet.retainAll(set); // identicalSet中剩下的元素是identicalSet与set集合中公有的元素
if(identicalSet.size() == m-1) { // (k-1)-项集中k-2个相同
SetString differentSet = new HashSetString(); // 两个项集不同元素的集合(集合的差运算)
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(SetString candKItemSet, SetSetString freqMItemSet) {
SetString tempSet = new HashSetString();
tempSet.addAll(candKItemSet);
IteratorString 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 IteratorSetString getIterator(SetString itemSet, SetSetString freqKItemSet) {
IteratorSetString 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 MapSetString, Float getFreqKItemSet(int k, SetSetString freqMItemSet) {
MapSetString, Integer candFreqKItemSetMap = new HashMapSetString, Integer();
// 调用aprioriGen方法,得到候选频繁k-项集
SetSetString candFreqKItemSet = this.aprioriGen(k-1, freqMItemSet);
// 扫描事务数据库
IteratorMap.EntryInteger, SetString it = txDatabase.entrySet().iterator();
// 统计支持数
while(it.hasNext()) {
Map.EntryInteger, SetString entry = it.next();
IteratorSetString kit = candFreqKItemSet.iterator();
while(kit.hasNext()) {
SetString kSet = kit.next();
SetString set = new HashSetString();
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);
}
}
}
}
python3关联规则Apriori代码模版
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from numpy import *
def loadDataSet():
return [['a', 'c', 'e'], ['b', 'd'], ['b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b'], ['b', 'c'], ['a', 'b'],
['a', 'b', 'c', 'e'], ['a', 'b', 'c'], ['a', 'c', 'e']]
def createC1(dataSet):
C1 = []
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item])
C1.sort()
# 映射为frozenset唯⼀性的,可使⽤其构造字典
return list(map(frozenset, C1))
# 从候选K项集到频繁K项集(⽀持度计算)
def scanD(D, Ck, minSupport):
ssCnt = {}
for tid in D:
for can in Ck:
if can.issubset(tid):
if not can in ssCnt:
ssCnt[can] = 1
else:
ssCnt[can] += 1
numItems = float(len(D))
retList = []
supportData = {}
for key in ssCnt:
support = ssCnt[key] / numItems
if support = minSupport:
retList.insert(0, key)
supportData[key] = support
return retList, supportData
def calSupport(D, Ck, min_support):
dict_sup = {}
for i in D:
for j in Ck:
if j.issubset(i):
if not j in dict_sup:
dict_sup[j] = 1
else:
dict_sup[j] += 1
sumCount = float(len(D))
supportData = {}
relist = []
for i in dict_sup:
temp_sup = dict_sup[i] / sumCount
if temp_sup = min_support:
relist.append(i)
supportData[i] = temp_sup # 此处可设置返回全部的⽀持度数据(或者频繁项集的⽀持度数据)return relist, supportData
# 改进剪枝算法
def aprioriGen(Lk, k): # 创建候选K项集 ##LK为频繁K项集
retList = []
lenLk = len(Lk)
for i in range(lenLk):
for j in range(i + 1, lenLk):
L1 = list(Lk[i])[:k - 2]
L2 = list(Lk[j])[:k - 2]
L1.sort()
L2.sort()
if L1 == L2: # 前k-1项相等,则可相乘,这样可防⽌重复项出现
# 进⾏剪枝(a1为k项集中的⼀个元素,b为它的所有k-1项⼦集)
a = Lk[i] | Lk[j] # a为frozenset()集合
a1 = list(a)
b = []
# 遍历取出每⼀个元素,转换为set,依次从a1中剔除该元素,并加⼊到b中
for q in range(len(a1)):
t = [a1[q]]
tt = frozenset(set(a1) - set(t))
b.append(tt)
t = 0
for w in b:
# 当b(即所有k-1项⼦集)都是Lk(频繁的)的⼦集,则保留,否则删除。
if w in Lk:
t += 1
if t == len(b):
retList.append(b[0] | b[1])
return retList
def apriori(dataSet, minSupport=0.2):
C1 = createC1(dataSet)
D = list(map(set, dataSet)) # 使⽤list()转换为列表
L1, supportData = calSupport(D, C1, minSupport)
L = [L1] # 加列表框,使得1项集为⼀个单独元素
k = 2
while (len(L[k - 2]) 0):
Ck = aprioriGen(L[k - 2], k)
Lk, supK = scanD(D, Ck, minSupport) # scan DB to get Lk
supportData.update(supK)
L.append(Lk) # L最后⼀个值为空集
k += 1
del L[-1] # 删除最后⼀个空集
return L, supportData # L为频繁项集,为⼀个列表,1,2,3项集分别为⼀个元素。
# ⽣成集合的所有⼦集
def getSubset(fromList, toList):
for i in range(len(fromList)):
t = [fromList[i]]
tt = frozenset(set(fromList) - set(t))
if not tt in toList:
toList.append(tt)
tt = list(tt)
if len(tt) 1:
getSubset(tt, toList)
def calcConf(freqSet, H, supportData, ruleList, minConf=0.7):
for conseq in H:
conf = supportData[freqSet] / supportData[freqSet - conseq] # 计算置信度
# 提升度lift计算lift = p(a b) / p(a)*p(b)
lift = supportData[freqSet] / (supportData[conseq] * supportData[freqSet - conseq]) if conf = minConf and lift 1:
print(freqSet - conseq, '--', conseq, '⽀持度', round(supportData[freqSet - conseq], 2), '置信度:', conf, 'lift值为:', round(lift, 2))
ruleList.append((freqSet - conseq, conseq, conf))
# ⽣成规则
def gen_rule(L, supportData, minConf=0.7):
bigRuleList = []
for i in range(1, len(L)): # 从⼆项集开始计算
for freqSet in L[i]: # freqSet为所有的k项集
# 求该三项集的所有⾮空⼦集,1项集,2项集,直到k-1项集,⽤H1表⽰,为list类型,⾥⾯为frozenset类型,
H1 = list(freqSet)
all_subset = []
getSubset(H1, all_subset) # ⽣成所有的⼦集
calcConf(freqSet, all_subset, supportData, bigRuleList, minConf)
return bigRuleList
if__name__ == '__main__':
dataSet = loadDataSet()
L, supportData = apriori(dataSet, minSupport=0.2)
rule = gen_rule(L, supportData, minConf=0.7)
运⾏结果:
⽬录:
1.关联分析
关联分析是⼀种在⼤规模数据集中寻找有趣关系的任务。这种关系表现为两种形式:
1.频繁项集(frequency item sets):经常同时出现的⼀些元素的集合;
2.关联规则(association rules): 意味着两种元素之间存在很强的关系。
下⾯举例来说明上⾯的两个概念:
表1 ⼀个来⾃Hole Foods天⾷品店的
简单交易清单
交易号码商品
0⾖奶,莴苣
1莴苣,尿布,葡萄酒,甜菜
2莴苣,尿布,葡萄酒,橙汁
3莴苣,⾖奶,尿布,葡萄酒
4莴苣,⾖奶,尿布,橙汁
频繁项集是指经常出现在⼀起的元素的集合,上表中的集合 {葡萄酒,尿布,⾖奶} 就是频繁项集的⼀个例⼦。同样可以找到如 “尿布 -- 葡萄酒”的关联规则,意味着如果有⼈买了尿布,就很可能也会买葡萄酒。使⽤频繁项集和关联规则,商家可以更好地理解顾客的消费⾏为,所以⼤部分关联规则分析⽰例来⾃零售业。
理解关联分析⾸先需要搞清楚下⾯三个问题:
1.如何定义这些有⽤的关系?
2.这些关系的强弱程度⼜是如何定义?
3.频繁的定义是什么?
要回答上⾯的问题,最重要的是理解两个概念:⽀持度和可信度。
⽀持度:⼀个项集的⽀持度(support)被定义为数据集中包含该项集的记录占总记录的⽐例。从表1 可以看出项集 {⾖奶} 的⽀持度为 4/5
可信度或置信度(confidence):是针对⼀条诸如尿布−−葡萄酒
2. Apriori 原理
假设经营了⼀家杂货店,于是我们对那些经常在⼀起购买的商品⾮常感兴趣。假设我们只有 4 种商品:商品0,商品1,商品 2,商品3. 那么
如何得可能被⼀起购买的商品的组合?
上图显⽰了物品之间所有可能的组合,从上往下⼀个集合是 Ø
我们的⽬标是找到经常在⼀起购买的物品集合。这⾥使⽤集合的⽀持度来度量其出现的频率。⼀个集合出现的⽀持度是指有多少⽐例的交易记录包含该集合。例如,对于上图,要计算 0,3
为了降低计算时间,研究⼈员发现了 Apriori
Apriori
即如果 {0,1} 是频繁的,那么 {0}, {1} 也⼀定是频繁的。
这个原理直观上没有什么⽤,但是反过来看就有⽤了,也就是说如果⼀个项集是⾮频繁的,那么它的所有超集也是⾮频繁的。如下图所⽰:
3. 使⽤ Apriori 算法来发现频繁集
上⾯提到,关联分析的两个⽬标:发现频繁项集和发现关联规则。⾸先需要找到频繁项集,然后根据频繁项集获得关联规则。⾸先来讨论发现频繁项集。Apriori 是发现频繁项集的⼀种⽅法。
⾸先会⽣成所有单个物品的项集列表;
扫描交易记录来查看哪些项集满⾜最⼩⽀持度要求,那些不满⾜最⼩⽀持度的集合会被去掉;
对剩下的集合进⾏组合以⽣成包含两个元素的项集;
接下来重新扫描交易记录,去掉不满⾜最⼩⽀持度的项集,重复进⾏直到所有项集都被去掉。数据集扫描的伪代码:
对数据集中的每条交易记录tran:
对每个候选项集can:
检查⼀下can是否是tran的⼦集:
如果是,则增加can的计数值
对每个候选项集:
如果其⽀持度不低于最低值,则保留
返回所有频繁项集列表
¥
5.9
百度文库VIP限时优惠现在开通,立享6亿+VIP内容
立即获取
python3关联规则Apriori代码模版
python3关联规则Apriori代码模版
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from numpy import *
def loadDataSet():
return [['a', 'c', 'e'], ['b', 'd'], ['b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b'], ['b', 'c'], ['a', 'b'],
['a', 'b', 'c', 'e'], ['a', 'b', 'c'], ['a', 'c', 'e']]
def createC1(dataSet):
C1 = []
第 1 页
for transaction in dataSet:
for item in transaction:
if not [item] in C1:
C1.append([item])
C1.sort()
# 映射为frozenset唯⼀性的,可使⽤其构造字典
return list(map(frozenset, C1))
# 从候选K项集到频繁K项集(⽀持度计算)
def scanD(D, Ck, minSupport):
Apriori算法是一种发现频繁项集的基本算法。算法使用频繁项集性质的先验知识。Apriori算法使用一种称为逐层搜索的迭代方法,其中K项集用于探索(k+1)项集。首先,通过扫描数据库,累计每个项的计数,并收集满足最小支持度的项,找出频繁1项集的集合。该集合记为L1.然后,使用L1找出频繁2项集的集合L2,使用L2找到L3,如此下去,直到不能再找到频繁k项集。Apriori算法的主要步骤如下:(1)扫描事务数据库中的每个事务,产生候选1.项集的集合Cl;(2)根据最小支持度min_sup,由候选l-项集的集合Cl产生频繁1一项集的集合Ll;(3)对k=l;(4)由Lk执行连接和剪枝操作,产生候选(k+1).项集的集合Ck+l-(5)根据最小支持度min_sup,由候选(k+1)一项集的集合Ck+l产生频繁(k+1)-项集的集合Lk+1.(6)若L?≠①,则k.k+1,跳往步骤(4);否则,跳往步骤(7);(7)根据最小置信度min_conf,由频繁项集产生强关联规则,结束。