Java关联规则案例

wen java案例 2

本文目录导读:

Java关联规则案例

  1. 项目结构
  2. 核心代码实现
  3. 运行结果示例
  4. 主要特点

我将为您提供一个完整的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 条

主要特点

  1. 完整的Apriori实现:包括候选项集生成、剪枝和频繁项集筛选
  2. 灵活的参数设置:可配置最小支持度和置信度
  3. 规则评估:提供支持度、置信度和提升度指标
  4. 模块化设计:代码结构清晰,易于扩展

这个案例展示了如何使用Java实现经典的关联规则挖掘算法,适用于购物篮分析、推荐系统等场景。

抱歉,评论功能暂时关闭!