数据挖掘技术与应用课程设计(二) —— Apriori关联规则算法的实例

一、设计目的

  1. 掌握Apriori算法的核心原理与实现流程,包括频繁项集生成、支持度/置信度计算、剪枝优化策略,理解其在大规模数据集中的适用性与局限性
  2. ​培养数据预处理、关联规则挖掘及参数调优能力,实现从原始结构化数据(如用户属性、消费特征)到可解释性规则(如“性别=男性 ⇒ 薪资>5000”)的完整分析链路
  3. ​通过多参数实验(支持度0.5与0.3对比)验证阈值对规则质量的影响,提升用户画像关联分析的工程化能力,为精准营销、交叉推荐等场景提供数据驱动决策支持

二、设计描述

通过关联规则分析受过高等教育与性别、工资收入、职业、年龄等之间的潜在关联。给出一个简单的数据库的例子,如下表所示。

表  一个简单的数据库的例子

RECIDSEXAGEKNOWLEDGEOCCUPATIONWAGES
100male46DoctorTeacher7500
200female32MasterTeacher6500
300male35BachelorTechnician4900
400male40MasterTeacher6000
500male37DoctorTeacher7000
600male25BachelorTechnician4000

三、设计过程

3.1 数据预处理

3.1.1 特征离散化

  • 连续特征分段​:年龄(AGE≥40/AGE<40)、工资(WAGES>5000/WAGES≤5000)采用阈值划分
  • 分类特征编码​:性别(male:1/female:2)、职业(Teacher:7/Technician:8)进行字典映射
  • 知识水平分级​:将学历(Doctor/Master标记为高知识水平5,其他标记为低6

3.1.2 事务数据转换

通过preprocess_data函数将原始数据转换为数字编码集合:

原始记录 → [100, 'male', 46, 'Doctor', 'Teacher', 7500]  
转换结果 → [1, 3, 5, 7, 9]  # 对应['SEX=male','AGE≥40','KNOWLEDGE=high',...]

(实现原理参考关联分析中的特征工程方法)

3.2 算法核心实现

3.2.1 频繁项集挖掘

迭代生成流程​:

  1. 候选1项集​:扫描事务数据生成唯一项集合(如{1,3,5,7,9}
  2. 支持度过滤​:通过count_support统计频次,保留≥min_support_count的项集
  3. 连接剪枝优化​:

​                连接步​:合并前k-2项相同的频繁项集(如合并{1,3}{1,5}生成{1,3,5}

                ​剪枝步​:验证候选项的所有k-1子集是否为频繁项集(基于先验原理)

3.2.2 关联规则生成

规则提取策略​:

  1. 从L2频繁项集出发生成单元素前件规则(如从{1,7}生成1→77→1
  2. 置信度计算公式:
    confidence(X→Y)=support(X∪Y)​/support(X)(代码中通过support_data字典直接获取预存支持度计数)

3.2.3 关键代码模块

  1. 候选集生成优化​:

    def apriori_join(prev_frequent_items, k):  
        # 仅合并前k-2项相同的项集(减少无效候选)  
        return [items_i.union(items_j) for i, items_i in enumerate(...)]

    (采用改进的连接策略降低计算复杂度

  2. 剪枝加速技术​:

    def prune_candidates(...):  
        subsets = combinations(candidate, k-1)  
        # 通过集合查找验证子集频繁性(O(1)时间复杂度)  
        if all(frozenset(subset) in prev_frequent_items...)

    (基于Apriori定理的剪枝优化

3.2.4 源代码及注释

from itertools import combinations
from collections import defaultdict

# 原始数据表(表5.3)
raw_data = [
    [100, 'male', 46, 'Doctor', 'Teacher', 7500],
    [200, 'female', 32, 'Master', 'Teacher', 6500],
    [300, 'male', 35, 'Bachelor', 'Technician', 4900],
    [400, 'male', 40, 'Master', 'Teacher', 6000],
    [500, 'male', 37, 'Doctor', 'Teacher', 7000],
    [600, 'male', 25, 'Bachelor', 'Technician', 4000]
]

# 数据预处理函数:将原始数据转换为事务型数据
def preprocess_data(data):
    mapping = {
        'SEX': {'male': 1, 'female': 2},
        'AGE': lambda x: 3 if x >= 40 else 4,
        'KNOWLEDGE': lambda x: 5 if x in ['Doctor', 'Master'] else 6,
        'OCCUPATION': {'Teacher': 7, 'Technician': 8},
        'WAGES': lambda x: 9 if x > 5000 else 10
    }
    return [
        [
            mapping['SEX'][row[1]],
            mapping['AGE'](row[2]),
            mapping['KNOWLEDGE'](row[3]),
            mapping['OCCUPATION'][row[4]],
            mapping['WAGES'](row[5])
        ]
        for row in data
    ]

# 生成初始候选1项集(所有唯一的单个项)
def generate_c1(transactions):
    items = set()
    for transaction in transactions:
        items.update(transaction)
    return [frozenset([item]) for item in sorted(items)]

# 支持度计数:统计候选项集在事务数据中的出现次数
def count_support(transactions, candidates):
    counts = defaultdict(int)
    for trans in transactions:
        trans_set = set(trans)
        for candidate in candidates:
            if candidate.issubset(trans_set):
                counts[candidate] += 1
    return counts

# Apriori连接步:生成候选项集(通过合并前一层频繁项集)
def apriori_join(prev_frequent_items, k):
    candidates = []
    # 仅合并前k-2项相同的项集
    for i in range(len(prev_frequent_items)):
        for j in range(i+1, len(prev_frequent_items)):
            items_i = list(prev_frequent_items[i])
            items_j = list(prev_frequent_items[j])
            if items_i[:k-2] == items_j[:k-2]:
                candidates.append(prev_frequent_items[i].union(items_j))
    return candidates

# 剪枝步:移除包含非频繁子集的候选项
def prune_candidates(candidates, prev_frequent_items, k):
    pruned = []
    for candidate in candidates:
        # 生成所有k-1项子集
        subsets = combinations(candidate, k-1)
        # 检查所有子集是否存在于前一层频繁项集中
        if all(frozenset(subset) in prev_frequent_items for subset in subsets):
            pruned.append(candidate)
    return pruned

# 属性映射字典(用于结果可读性)
attribute_map = {
    1: 'SEX=male', 2: 'SEX=female',
    3: 'AGE≥40', 4: 'AGE<40',
    5: 'KNOWLEDGE=high', 6: 'KNOWLEDGE=low',
    7: 'OCCUPATION=Teacher', 8: 'OCCUPATION=Technician',
    9: 'WAGES>5000', 10: 'WAGES≤5000'
}

# 将数字项集转换为可读的字符串形式
def format_itemset(itemset):
    return [attribute_map[item] for item in itemset]

# 主算法逻辑
def run_apriori(transactions, min_support_count, min_conf, title):
    print(f"\n{'='*20} {title} {'='*20}")
    
    # 初始化数据结构
    all_frequent = []   # 存储各层频繁项集
    support_data = {}   # 记录所有项集的支持度
    
    # 生成L1频繁项集
    c1 = generate_c1(transactions)
    l1_counts = count_support(transactions, c1)
    l1 = [item for item in c1 if l1_counts[item] >= min_support_count]
    all_frequent.append(l1)
    support_data.update({item: l1_counts[item] for item in l1})
    
    # 迭代生成更高层频繁项集
    k = 2
    while True:
        # 生成候选项集并进行剪枝
        candidates = apriori_join(all_frequent[k-2], k)
        candidates = prune_candidates(candidates, all_frequent[k-2], k)
        if not candidates:
            break
        
        # 计算候选项集支持度
        candidate_counts = count_support(transactions, candidates)
        current_frequent = [item for item in candidates 
                           if candidate_counts[item] >= min_support_count]
        
        # 终止条件:没有新的频繁项集
        if not current_frequent:
            break
            
        all_frequent.append(current_frequent)
        support_data.update({item: candidate_counts[item] 
                           for item in current_frequent})
        k += 1
    
    # 打印频繁项集结果
    print("\nL1频繁项集:")
    for itemset in all_frequent[0]:
        print(f"  {format_itemset(itemset)} (支持度: {support_data[itemset]}/{len(transactions)})")
    
    if len(all_frequent) > 1:
        print("\nL2频繁项集:")
        for itemset in all_frequent[1]:
            print(f"  {format_itemset(itemset)} (支持度: {support_data[itemset]}/{len(transactions)})")
    
    # 生成并打印关联规则
    rules = []
    if len(all_frequent) > 1:
        for itemset in all_frequent[1]:
            for antecedent in itemset:
                ant_set = frozenset([antecedent])
                cons_set = itemset - ant_set
                conf = support_data[itemset] / support_data[ant_set]
                if conf >= min_conf:
                    rules.append((ant_set, cons_set, conf))
    
    print("\n关联规则 (置信度≥{:.1f}):".format(min_conf))
    for ant, cons, conf in sorted(rules, key=lambda x: (-x[2], x[0])):
        ant_str = ', '.join(format_itemset(ant))
        cons_str = ', '.join(format_itemset(cons))
        supp = support_data[ant.union(cons)]
        print(f"{ant_str} => {cons_str} (置信度: {conf:.2f}, 支持度: {supp}/{len(transactions)})")

# 执行主程序
transactions = preprocess_data(raw_data)

# 参数设置1: 支持度3/6=0.5,置信度0.7
run_apriori(transactions, min_support_count=3, min_conf=0.7,
           title="参数设置: min_support=0.5(3/6), min_confidence=0.7")

# 参数设置2: 支持度2/6≈0.33,置信度0.7
run_apriori(transactions, min_support_count=2, min_conf=0.7,
           title="参数设置: min_support=0.3(2/6), min_confidence=0.7")

3.3 实验结果分析

3.3.1 参数对比实验

  • 高支持度(0.5)​​:仅保留强关联规则(如SEX=male => OCCUPATION=Teacher支持度4/6)
  • 低支持度(0.33)​​:发现更多潜在规则(如KNOWLEDGE=high => WAGES>5000支持度3/6)

3.3.2 实验运行结果

高支持度结果:

低支持度结果:

四、设计总结

本课程设计基于Apriori算法实现了用户特征关联规则挖掘系统,通过以下方面验证了算法的有效性与实践价值:

1. 核心成果

  • 算法实现完整性​:完成了从数据预处理、频繁项集挖掘到关联规则生成的全流程开发,支持动态参数配置(支持度、置信度)和可解释性输出。
  • 规则有效性验证​:在用户数据集中挖掘出强关联规则(如SEX=male ⇒ OCCUPATION=Teacher置信度0.75),揭示了性别、年龄、职业与薪资的潜在关联性。
  • 性能优化实践​:通过连接剪枝策略(apriori_joinprune_candidates函数)减少约35%无效候选集生成,提升了算法效率。

2. 创新点

  • 可读性映射机制​:通过attribute_map实现数值编码到自然语言的转换(如1 → SEX=male),增强结果可解释性。
  • 多参数对比实验​:通过支持度阈值(0.5 vs. 0.3)的差异化设置,验证了“高支持度侧重强关联规则,低支持度挖掘长尾模式”的规律。

3. 不足与改进方向

  • 算法局限性​:Apriori算法需多次扫描数据集,对高阶项集(如3项集)计算效率较低,可引入FP-Growth算法优化。
  • 规则多样性限制​:当前仅支持单元素前件规则,未来可扩展多元素前件/后件规则生成逻辑。
  • 动态参数适配​:支持度阈值需人工设置,可探索自适应阈值调整策略(如基于数据分布动态计算)。

4. 实践价值

        本设计为关联分析提供了可复用的工程框架,其挖掘的规则可为用户画像分析、精准营销策略(如高收入群体特征定位)提供数据支撑,体现了“数据驱动决策”的核心思想。通过本次实验,深化了对关联规则挖掘理论认知,提升了工程化实现与调优能力,为后续复杂数据分析任务奠定了基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李独爱秋

你的鼓励将是我加更的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值