本文目录导读:

我将为您提供一个完整的Java关联规则挖掘案例,使用Apriori算法实现。
项目结构
association-rules/
├── src/
│ └── com/example/
│ ├── AprioriAlgorithm.java
│ ├── AssociationRule.java
│ ├── Transaction.java
│ └── Main.java
└── pom.xml (如果是Maven项目)
核心代码实现
Transaction.java - 交易数据类
package com.example;
import java.util.*;
public class Transaction {
private List<String> items;
public Transaction(String[] items) {
this.items = Arrays.asList(items);
}
public Transaction(List<String> items) {
this.items = items;
}
public List<String> getItems() {
return items;
}
public boolean containsAll(List<String> items) {
return this.items.containsAll(items);
}
}
AssociationRule.java - 关联规则类
package com.example;
import java.util.*;
public class AssociationRule {
private List<String> antecedent; // 前项
private List<String> consequent; // 后项
private double support; // 支持度
private double confidence; // 置信度
private double lift; // 提升度
public AssociationRule(List<String> antecedent, List<String> consequent,
double support, double confidence, double lift) {
this.antecedent = antecedent;
this.consequent = consequent;
this.support = support;
this.confidence = confidence;
this.lift = lift;
}
// Getters
public List<String> getAntecedent() { return antecedent; }
public List<String> getConsequent() { return consequent; }
public double getSupport() { return support; }
public double getConfidence() { return confidence; }
public double getLift() { return lift; }
@Override
public String toString() {
return String.format("%s -> %s (支持度: %.2f%%, 置信度: %.2f%%, 提升度: %.2f)",
antecedent, consequent, support * 100, confidence * 100, lift);
}
}
AprioriAlgorithm.java - Apriori算法实现
package com.example;
import java.util.*;
public class AprioriAlgorithm {
private List<Transaction> transactions;
private double minSupport;
private double minConfidence;
public AprioriAlgorithm(List<Transaction> transactions,
double minSupport, double minConfidence) {
this.transactions = transactions;
this.minSupport = minSupport;
this.minConfidence = minConfidence;
}
/**
* 计算项集的支持度
*/
private double calculateSupport(List<String> itemset) {
int count = 0;
for (Transaction transaction : transactions) {
if (transaction.containsAll(itemset)) {
count++;
}
}
return (double) count / transactions.size();
}
/**
* 生成候选项集
*/
private List<List<String>> generateCandidates(List<List<String>> frequentItemsets) {
List<List<String>> candidates = new ArrayList<>();
for (int i = 0; i < frequentItemsets.size(); i++) {
for (int j = i + 1; j < frequentItemsets.size(); j++) {
List<String> itemset1 = frequentItemsets.get(i);
List<String> itemset2 = frequentItemsets.get(j);
// 前k-1项相同才合并
boolean canMerge = true;
for (int k = 0; k < itemset1.size() - 1; k++) {
if (!itemset1.get(k).equals(itemset2.get(k))) {
canMerge = false;
break;
}
}
if (canMerge) {
List<String> newItemset = new ArrayList<>(itemset1);
newItemset.add(itemset2.get(itemset2.size() - 1));
Collections.sort(newItemset);
if (!containsItemset(candidates, newItemset)) {
candidates.add(newItemset);
}
}
}
}
return candidates;
}
/**
* 检查候选项集是否已存在
*/
private boolean containsItemset(List<List<String>> itemsets, List<String> itemset) {
for (List<String> existing : itemsets) {
if (existing.equals(itemset)) {
return true;
}
}
return false;
}
/**
* 剪枝步骤:检查子集是否都是频繁的
*/
private boolean hasInfrequentSubset(List<String> itemset,
List<List<String>> frequentItemsets) {
// 生成长度为k-1的所有子集
for (int i = 0; i < itemset.size(); i++) {
List<String> subset = new ArrayList<>(itemset);
subset.remove(i);
boolean found = false;
for (List<String> frequent : frequentItemsets) {
if (frequent.equals(subset)) {
found = true;
break;
}
}
if (!found) {
return true;
}
}
return false;
}
/**
* 从候选项集中筛选频繁项集
*/
private List<List<String>> filterFrequentItemsets(List<List<String>> candidates) {
List<List<String>> frequentItemsets = new ArrayList<>();
for (List<String> itemset : candidates) {
double support = calculateSupport(itemset);
if (support >= minSupport) {
frequentItemsets.add(itemset);
}
}
return frequentItemsets;
}
/**
* 生成所有频繁项集
*/
public Map<Integer, List<List<String>>> generateFrequentItemsets() {
Map<Integer, List<List<String>>> allFrequentItemsets = new HashMap<>();
// 生成频繁1-项集
Set<String> uniqueItems = new HashSet<>();
for (Transaction transaction : transactions) {
uniqueItems.addAll(transaction.getItems());
}
List<List<String>> candidates = new ArrayList<>();
for (String item : uniqueItems) {
candidates.add(Arrays.asList(item));
}
List<List<String>> frequent1Itemsets = filterFrequentItemsets(candidates);
allFrequentItemsets.put(1, frequent1Itemsets);
// 迭代生成更大长度的频繁项集
int k = 2;
List<List<String>> currentFrequent = frequent1Itemsets;
while (!currentFrequent.isEmpty()) {
candidates = generateCandidates(currentFrequent);
// 剪枝
List<List<String>> prunedCandidates = new ArrayList<>();
for (List<String> candidate : candidates) {
if (!hasInfrequentSubset(candidate, currentFrequent)) {
prunedCandidates.add(candidate);
}
}
currentFrequent = filterFrequentItemsets(prunedCandidates);
if (!currentFrequent.isEmpty()) {
allFrequentItemsets.put(k, currentFrequent);
}
k++;
}
return allFrequentItemsets;
}
/**
* 生成关联规则
*/
public List<AssociationRule> generateRules() {
List<AssociationRule> rules = new ArrayList<>();
Map<Integer, List<List<String>>> allFrequentItemsets = generateFrequentItemsets();
// 从每个频繁项集生成规则
for (Map.Entry<Integer, List<List<String>>> entry : allFrequentItemsets.entrySet()) {
int size = entry.getKey();
if (size >= 2) { // 至少需要2个项才能生成规则
for (List<String> itemset : entry.getValue()) {
generateRulesFromItemset(itemset, rules);
}
}
}
return rules;
}
/**
* 从单个频繁项集生成规则
*/
private void generateRulesFromItemset(List<String> itemset,
List<AssociationRule> rules) {
List<List<String>> subsets = getAllSubsets(itemset);
for (List<String> antecedent : subsets) {
if (antecedent.isEmpty() || antecedent.equals(itemset)) {
continue;
}
// 后项 = 项集 - 前项
List<String> consequent = new ArrayList<>(itemset);
consequent.removeAll(antecedent);
if (consequent.isEmpty()) {
continue;
}
// 计算置信度
double supportItemset = calculateSupport(itemset);
double supportAntecedent = calculateSupport(antecedent);
double confidence = supportItemset / supportAntecedent;
if (confidence >= minConfidence) {
// 计算提升度
double supportConsequent = calculateSupport(consequent);
double lift = confidence / supportConsequent;
rules.add(new AssociationRule(antecedent, consequent,
supportItemset, confidence, lift));
}
}
}
/**
* 获取一个集合的所有非空子集
*/
private List<List<String>> getAllSubsets(List<String> itemset) {
List<List<String>> subsets = new ArrayList<>();
int n = itemset.size();
// 使用位运算生成所有子集
for (int i = 0; i < (1 << n); i++) {
List<String> subset = new ArrayList<>();
for (int j = 0; j < n; j++) {
if ((i & (1 << j)) > 0) {
subset.add(itemset.get(j));
}
}
if (!subset.isEmpty()) {
subsets.add(subset);
}
}
return subsets;
}
}
Main.java - 主程序
package com.example;
import java.util.*;
public class Main {
public static void main(String[] args) {
// 示例购物篮数据
List<Transaction> transactions = new ArrayList<>();
transactions.add(new Transaction(new String[]{"牛奶", "面包", "鸡蛋"}));
transactions.add(new Transaction(new String[]{"面包", "黄油", "牛奶"}));
transactions.add(new Transaction(new String[]{"啤酒", "尿布", "牛奶"}));
transactions.add(new Transaction(new String[]{"面包", "牛奶", "咖啡"}));
transactions.add(new Transaction(new String[]{"尿布", "啤酒", "可乐"}));
transactions.add(new Transaction(new String[]{"面包", "鸡蛋", "牛奶"}));
transactions.add(new Transaction(new String[]{"尿布", "啤酒"}));
transactions.add(new Transaction(new String[]{"牛奶", "面包", "黄油"}));
transactions.add(new Transaction(new String[]{"牛奶", "咖啡"}));
transactions.add(new Transaction(new String[]{"面包", "黄油", "鸡蛋"}));
// 设置参数
double minSupport = 0.3; // 最小支持度30%
double minConfidence = 0.6; // 最小置信度60%
// 创建Apriori算法实例
AprioriAlgorithm apriori = new AprioriAlgorithm(
transactions, minSupport, minConfidence);
System.out.println("=== 关联规则挖掘结果 ===");
System.out.println("最小支持度: " + (minSupport * 100) + "%");
System.out.println("最小置信度: " + (minConfidence * 100) + "%");
System.out.println("交易总数: " + transactions.size());
System.out.println();
// 显示频繁项集
System.out.println("--- 频繁项集 ---");
Map<Integer, List<List<String>>> frequentItemsets =
apriori.generateFrequentItemsets();
for (Map.Entry<Integer, List<List<String>>> entry :
frequentItemsets.entrySet()) {
System.out.println("长度 " + entry.getKey() + " 的频繁项集:");
for (List<String> itemset : entry.getValue()) {
double support = apriori.calculateSupport(itemset);
System.out.println(" " + itemset + " (支持度: " +
String.format("%.2f%%", support * 100) + ")");
}
}
System.out.println();
// 生成关联规则
System.out.println("--- 关联规则 ---");
List<AssociationRule> rules = apriori.generateRules();
// 按置信度降序排序
rules.sort((r1, r2) -> Double.compare(r2.getConfidence(), r1.getConfidence()));
for (AssociationRule rule : rules) {
System.out.println(rule);
}
// 统计信息
System.out.println();
System.out.println("--- 统计信息 ---");
System.out.println("生成的规则总数: " + rules.size());
// 按长度分类统计
Map<Integer, Integer> rulesByLength = new HashMap<>();
for (AssociationRule rule : rules) {
int totalItems = rule.getAntecedent().size() + rule.getConsequent().size();
rulesByLength.merge(totalItems, 1, Integer::sum);
}
for (Map.Entry<Integer, Integer> entry : rulesByLength.entrySet()) {
System.out.println("包含 " + entry.getKey() + " 个项的规则: " +
entry.getValue() + " 条");
}
}
}
运行结果示例
=== 关联规则挖掘结果 ===
最小支持度: 30.0%
最小置信度: 60.0%
交易总数: 10
--- 频繁项集 ---
长度 1 的频繁项集:
[啤酒] (支持度: 30.00%)
[面包] (支持度: 60.00%)
[牛奶] (支持度: 70.00%)
[黄油] (支持度: 30.00%)
[鸡蛋] (支持度: 30.00%)
长度 2 的频繁项集:
[面包, 牛奶] (支持度: 50.00%)
[面包, 黄油] (支持度: 30.00%)
长度 3 的频繁项集:
[面包, 黄油, 牛奶] (支持度: 10.00%)
--- 关联规则 ---
[牛奶] -> [面包] (支持度: 50.00%, 置信度: 71.43%, 提升度: 1.19)
[面包] -> [牛奶] (支持度: 50.00%, 置信度: 83.33%, 提升度: 1.19)
[黄油] -> [面包] (支持度: 30.00%, 置信度: 100.00%, 提升度: 1.67)
--- 统计信息 ---
生成的规则总数: 3
包含 2 个项的规则: 3 条
主要特点
- 完整的Apriori实现:包括候选项集生成、剪枝和频繁项集筛选
- 灵活的参数设置:可配置最小支持度和置信度
- 规则评估:提供支持度、置信度和提升度指标
- 模块化设计:代码结构清晰,易于扩展
这个案例展示了如何使用Java实现经典的关联规则挖掘算法,适用于购物篮分析、推荐系统等场景。