首页 / 资讯中心 / 文章详情

基于Apriori与BP神经网络的数据挖掘算法实现与毕设应用

基于Apriori与BP神经网络的数据挖掘算法实现与毕设应用 ★ FEATURED ARTICLE
简介这是一份面向高校计算机相关专业学生的毕业设计参考资料聚焦大数据背景下数据挖掘算法的实现与应用适合正在选题、撰写论文或需要算法落地案例的本科与专科毕业生。资源以PDF文档形式呈现完整覆盖毕业设计论文的规范结构包括原创性声明、中英文摘要、目录、正文、参考文献与致谢等模块并附有指导教师评阅书、评阅教师评阅书及答辩小组意见等过程性表格。内容重点讲解关联规则中的Apriori算法与神经网络中的BP算法前者用于求解高校排课问题通过迭代生成候选集并计数支持度来挖掘课程关联、优化安排后者用于政府投资项目投资估算借助误差反向传播逐层调整权重以提升预测精度并对计算结果进行了分析比较。压缩包内共1个PDF文件大小约4.8MB结构完整、便于打印与查阅。目前已有184人学习下载可为毕业设计写作、算法理解与答辩准备提供较完整的参考范本。1. 从一份“数据海量、信息缺乏”的毕设说起如果你正在搜“大数据毕业设计”“数据挖掘算法实现”大概率不是想听人复述一遍数据挖掘的定义而是想找一份能跑通、能改、能写进论文里的东西。这份本科毕业设计就是围绕这个诉求做的它把关联规则里的 Apriori 算法和神经网络里的 BP 算法拆开讲透再各自落到一个真实场景——Apriori 用来分析高校排课里课程之间的关联BP 用来做政府投资项目的投资估算。整套材料包含论文主体、外文翻译、程序代码附录正文要求不少于一万字软件工程类课题还要求附程序清单和电子文档。它适合两类人一类是计算机、软件工程、信息管理方向正在做毕设的学生需要一份结构完整、算法有落地的参考另一类是刚接触数据挖掘、想拿两个经典算法练手的从业者想看看从数据清洗到结果解释这条链路到底长什么样。下面我按“这份资源是什么、怎么用、坑在哪”的顺序把它拆成能照着复现的步骤。2. Apriori 算法从成绩表到课程关联规则2.1 为什么选 Apriori而不是聚类或分类关联规则挖掘要解决的问题是“哪些东西经常一起出现”这跟排课场景天然契合。学校积累了多年的学生成绩传统做法只停留在统计优良率、算平均分但课程之间有没有先后依赖、哪几门课的成绩会互相影响这些信息一直躺在数据库里没人用。Apriori 的核心是两阶段先迭代找出支持度不低于阈值的频繁项集再用频繁项集构造满足最小置信度的规则。找频繁项集是整个算法的性能瓶颈因为每一轮都要扫描数据库、生成候选集。选它而不是聚类或分类理由很直接——排课要的是“课程 A 和课程 B 之间的关联强度”这是一个规则发现问题不是分组问题也不是预测标签问题。聚类能告诉你哪些学生相似分类能告诉你学生会不会挂科但都回答不了“计算机网络和操作系统该不该排在同一学期”这种问题。2.2 数据清洗与离散化把连续分数变成事务项原始成绩库里混着全校各专业各年级的记录直接拿来跑 Apriori 会引入大量噪声。第一步是圈定范围只保留某一届某一专业的若干门课程。缺失值不能简单删掉否则样本量会掉得很快常见做法是用该科平均分补齐同一门课有多个成绩的按第一次成绩算。清洗完之后连续分数还得离散化因为 Apriori 处理的是离散项集。按 90、80、70、60 四个分界点切成优、良、中、及格、不及格五档分别用 1 到 5 表示课程用大写字母代替。import pandas as pd # 读取清洗后的成绩表列名为课程代码 df pd.read_csv(grades_clean.csv) # 缺失值用该科平均分补齐 df df.fillna(df.mean(numeric_onlyTrue)) # 同一门课多次成绩取第一次这里假设列名已去重 # 离散化90以上180-89270-79360-69460以下5 def discretize(score): if score 90: return 1 elif score 80: return 2 elif score 70: return 3 elif score 60: return 4 else: return 5 for col in df.columns: df[col] df[col].apply(discretize) # 转成事务格式每行是一个学生每个元素是“课程等级” transactions [] for _, row in df.iterrows(): items [f{col}{int(val)} for col, val in row.items()] transactions.append(items) print(transactions[:3])这段代码做了三件事补缺失值、把连续分数映射成等级、把每行记录转成项集列表。参数上要注意fillna用均值只适合缺失比例低的情况如果某门课缺考人数超过三成补均值会严重扭曲分布这时候更稳妥的做法是整门课剔除。离散化的分界点不是固定的如果学校是绩点制可以按绩点区间重新切。transactions的结构直接决定了后面 Apriori 的输入格式每个学生的选课和成绩组合就是一条事务。2.3 支持度、置信度和增益三个阈值怎么设支持度反映规则覆盖了多少比例的事务置信度反映前件出现时后件出现的把握程度但光看这两个指标会翻车。原文里举了一个经典反例调查 5000 名学生60% 早上打篮球75% 吃某品牌早餐40% 既打篮球又吃早餐。设最小支持度 0.4、最小置信度 0.6会得到规则“打篮球→吃早餐”支持度 0.4、置信度 0.66两个都过线。但吃早餐的学生本来就占 75%比 66% 还高说明打篮球和吃早餐实际上是负相关的。这时候必须引入增益 Lift公式是置信度除以规则后件的支持度。Lift 等于 1 表示前后件独立大于 1 正相关小于 1 负相关。上例中 Lift 等于 0.66 除以 0.75约 0.88小于 1规则没有意义。from itertools import combinations def apriori(transactions, min_support): # 统计单项支持度 item_count {} total len(transactions) for t in transactions: for item in t: item_count[item] item_count.get(item, 0) 1 # 筛选频繁 1 项集 freq {frozenset([k]): v / total for k, v in item_count.items() if v / total min_support} all_freq dict(freq) k 2 while freq: candidates set() keys list(freq.keys()) for i in range(len(keys)): for j in range(i 1, len(keys)): union keys[i] | keys[j] if len(union) k: candidates.add(union) freq {} for c in candidates: count sum(1 for t in transactions if c.issubset(set(t))) support count / total if support min_support: freq[c] support all_freq.update(freq) k 1 return all_freq def generate_rules(freq_items, transactions, min_conf): rules [] total len(transactions) for itemset, support in freq_items.items(): if len(itemset) 2: continue for i in range(1, len(itemset)): for antecedent in combinations(itemset, i): antecedent frozenset(antecedent) consequent itemset - antecedent ant_count sum(1 for t in transactions if antecedent.issubset(set(t))) if ant_count 0: continue conf support / (ant_count / total) cons_support sum(1 for t in transactions if consequent.issubset(set(t))) / total lift conf / cons_support if cons_support 0 else 0 if conf min_conf: rules.append((antecedent, consequent, support, conf, lift)) return rules freq_items apriori(transactions, min_support0.1) rules generate_rules(freq_items, transactions, min_conf0.6) for r in sorted(rules, keylambda x: -x[4])[:10]: print(r)这段实现是 Apriori 的简化版min_support设 0.1 意味着一个项集至少出现在 10% 的学生记录里才算频繁。min_conf设 0.6 是常见的起步值实际调参时先跑一遍看规则数量太多就提高支持度太少就降低置信度。输出里按 Lift 降序排优先看 Lift 明显大于 1 的规则。参数没有万能值排课场景下支持度通常设在 0.05 到 0.15 之间因为课程组合本身就比较稀疏。2.4 从频繁项集到排课建议跑出规则之后真正有价值的是那些 Lift 大于 1 且置信度高的组合。比如规则“高等数学1→计算机网络1”如果 Lift 是 1.3说明高等数学成绩好的学生计算机网络成绩好的概率比随机情况高 30%这两门课可能存在能力上的先后依赖排课时可以考虑把高等数学放在计算机网络之前。反过来如果某两门课经常同时不及格那可能是课程难度叠加应该错开学期。原文还提到 Apriori 在遥感数据挖掘中的应用思路是一样的——把遥感影像的波段或地物类型当作项找频繁共现模式。区别在于遥感数据的项集维度更高需要先做降维或分块处理否则候选集爆炸会非常严重。3. BP 神经网络投资估算的建模与训练3.1 BP 网络的结构与反向传播在做什么BP 算法解决的是另一类问题给定一组输入特征预测一个连续值。政府投资项目的投资估算就是典型场景——输入可能是项目类型、建筑面积、工期、地区系数等输出是估算投资额。BP 网络由输入层、若干隐藏层和输出层组成每层神经元之间全连接权重和偏置是待训练参数。前向传播时输入经过加权求和和激活函数逐层传递到输出反向传播时用损失函数对权重的梯度从输出层往回逐层更新。核心是链式法则误差每往回传一层就乘上该层激活函数的导数。隐藏层常用 Sigmoid 或 Tanh输出层做回归时一般用线性函数。隐藏层节点数没有固定公式常见做法是输入节点数和输出节点数之和的一半再开方或者直接试几组取验证误差最小的。3.2 数据归一化与网络初始化投资估算的输入特征量纲差异很大建筑面积可能是几万地区系数可能是 0.8 到 1.2直接喂给网络会导致梯度更新被大量纲特征主导。所以训练前必须归一化把每个特征缩放到 0 到 1 或 -1 到 1 之间。输出值同样要归一化否则损失函数一开始就很大收敛慢。import numpy as np def normalize(data): min_val data.min(axis0) max_val data.max(axis0) return (data - min_val) / (max_val - min_val 1e-8), min_val, max_val # 假设 X 是输入特征矩阵y 是投资额 X_raw np.array([[12000, 1.0, 24], [8000, 0.9, 18], [20000, 1.1, 36]], dtypefloat) y_raw np.array([[3200], [2100], [5100]], dtypefloat) X, X_min, X_max normalize(X_raw) y, y_min, y_max normalize(y_raw) # 初始化权重输入3维隐藏层5个节点输出1维 np.random.seed(42) W1 np.random.randn(3, 5) * 0.5 b1 np.zeros((1, 5)) W2 np.random.randn(5, 1) * 0.5 b2 np.zeros((1, 1)) def sigmoid(x): return 1 / (1 np.exp(-x)) def sigmoid_deriv(x): s sigmoid(x) return s * (1 - s) lr 0.1 for epoch in range(5000): # 前向 z1 X W1 b1 a1 sigmoid(z1) z2 a1 W2 b2 a2 z2 # 回归输出用线性 loss np.mean((a2 - y) ** 2) # 反向 d2 (a2 - y) / len(X) dW2 a1.T d2 db2 np.sum(d2, axis0, keepdimsTrue) d1 (d2 W2.T) * sigmoid_deriv(z1) dW1 X.T d1 db1 np.sum(d1, axis0, keepdimsTrue) # 更新 W2 - lr * dW2 b2 - lr * db2 W1 - lr * dW1 b1 - lr * db1 if epoch % 1000 0: print(fepoch {epoch}, loss {loss:.6f})这段代码把归一化、前向传播、反向传播和权重更新串起来了。lr是学习率设 0.1 是保守值太大容易震荡太小收敛慢。np.random.seed(42)保证每次初始化一致方便复现。隐藏层节点数 5 是示例值实际项目里要按验证集误差调。注意输出层没有加激活函数因为投资估算是回归问题加了 Sigmoid 会把输出限制在 0 到 1 之间反归一化后才能还原成真实金额。3.3 训练轮数、学习率和过拟合的判断训练轮数不是越多越好。损失曲线如果在训练集上持续下降但验证集上开始上升就是过拟合的信号。常见做法是划分训练集和验证集比如 8 比 2每训练若干轮就在验证集上算一次误差取验证误差最小时的权重。学习率可以设成动态的前期大一点加快收敛后期小一点精细调整。原文里 BP 网络用于投资估算输入特征的选择比网络结构本身更影响结果——如果漏掉了关键的成本驱动因素再深的网络也补不回来。所以建模前先做特征筛选把跟投资额相关性低的变量去掉比盲目加隐藏层有效得多。4. 避坑与排查跑不通、结果怪、论文写不下去4.1 频繁项集为空或规则少得可怜现象是 Apriori 跑完一条规则都没输出或者只有一两条。原因通常是支持度设太高或者离散化太粗导致所有学生的项集几乎一样。解决方法是先把支持度降到 0.02 跑一遍看频繁项集数量再逐步往上调离散化如果五档太粗可以改成按百分位切分保证每档都有足够样本。4.2 BP 损失不下降或变成 NaN现象是训练几轮后损失变成 NaN或者一直卡在初始值附近。原因一般是学习率太大导致梯度爆炸或者输入没有归一化。解决方法是先把学习率降到 0.01 甚至 0.001确认输入数据已经缩放到 0 到 1 之间再检查激活函数是否在输出层用错了——回归问题输出层不能用 Sigmoid。4.3 数据清洗时把有用记录删没了现象是清洗完发现样本量从几千掉到几十。原因是缺失值处理策略太激进比如只要有一门课缺考就整行删除。解决方法是按缺失比例决定策略缺失低于 10% 的用均值或中位数补高于 30% 的考虑整列剔除中间地带可以用 KNN 插补或回归插补。4.4 论文里算法描述和代码对不上现象是论文写的 Apriori 步骤和附录代码逻辑不一致答辩时被追问。原因是论文先写、代码后改或者参考了不同版本的伪代码。解决方法是定稿前把代码的关键函数和论文的算法步骤逐条对照确保支持度计算、候选集生成、剪枝条件这些核心环节描述一致。4.5 外文翻译和附录格式不符合学校要求现象是查重过了但格式审查被打回。原因是没注意学校对附录顺序和翻译篇幅的具体规定。解决方法是提前拿到学院的格式模板附录按任务书、开题报告、外文译文、译文原文的顺序装订外文翻译的原文和译文要对应程序代码附录加上必要的注释和运行说明。5. 把两个算法串成一条可复现的验证链路如果你想把这份毕设真正用起来我建议不要只跑一遍代码就完事而是按一条完整的验证链路走一遍。先拿 Apriori 做课程关联分析把规则按 Lift 排序挑出 Lift 大于 1.2 且置信度大于 0.7 的规则人工判断这些课程组合在培养方案里是否合理。这一步的目的是验证数据预处理和阈值设置是否合理——如果跑出来的规则全是“体育1→体育2”这种显然的关联说明离散化或支持度有问题。然后拿 BP 做投资估算用同一批历史项目数据先做特征相关性分析把跟投资额相关系数低于 0.3 的特征去掉再训练网络。训练时记录每 500 轮的验证集误差画一条误差曲线看收敛点在哪里。最后把两个算法的结果放在一起对比Apriori 输出的是离散规则BP 输出的是连续预测值前者适合解释“为什么”后者适合回答“是多少”。论文里可以把这两条线分别写成应用案例再在结语里讨论关联规则和神经网络在数据挖掘任务中的互补关系。验证的时候有几个具体技巧。Apriori 的规则数量对支持度非常敏感可以做一个支持度扫描表从 0.02 到 0.2 每隔 0.02 跑一次记录频繁项集数量和规则数量选一个规则数量在 20 到 50 条之间的支持度。BP 的隐藏层节点数可以试 3、5、8、10 四组每组跑三次取平均验证误差选误差最小且训练时间可接受的那组。这些扫描结果可以直接放进论文的实验部分比只贴一个最终结果更有说服力。提示Apriori 和 BP 的实现都不依赖特定的大数据框架单机 Python 就能跑。如果数据量确实到了单机内存放不下的程度再考虑用 Spark 的 MLlib 或分布式矩阵运算但毕设场景下通常不需要。从那以后我每次拿到一份算法类毕设资源都强制自己先跑通最小数据集再逐步加数据、调参数、记录每次改动对应的结果变化。这样即使中间翻车也能快速定位是哪一步引入的问题。希望这份拆解能帮你少走几个弯路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站