
简介面向数据挖掘课程设计与期末大作业场景的Python实战项目以葡萄酒质量分析为主线覆盖数据读取、清洗、特征分析、可视化及模型训练等完整流程。代码经调试可直接运行适合计算机相关专业学生快速上手也可作为分类或回归分析的练习范本。资源包共16个文件包括10个csv格式的葡萄酒质量数据集酒精含量、酸度、密度等多维特征变量及质量评分、3个py格式的源码脚本和3个txt格式的说明文档压缩包总大小约595KB内容紧凑、结构清晰。目前已有84人学习浏览。下载后即可基于真实数据集开展特征工程与模型评估系统积累从数据预处理到结果分析的数据挖掘全流程经验为课程作业或后续数据分析工作提供可复用的参考实现。1. 先说清楚这份Python葡萄酒质量分析大作业到底在解决什么问题用 Python 做葡萄酒质量分析核心就一句话用酒的十一个理化指标去预测品酒师给出的质量评分。听起来简单但它几乎覆盖了数据挖掘课的所有关键环节——数据清洗、可视化、特征工程、建模调参、结果评估所以是数据挖掘大作业里出镜率很高的选题。标题里那个“高分项目”不是玄学也不是评分老师手松而是这类项目有清晰的得分路径数据理解完整、特征有解释、模型对比严谨、代码可复现每一项都是实打实的加分点。这篇笔记就把这条路径拆开从最基础的数据格式讲到最容易翻车的细节新手照着能跑通熟手能对照检查自己的源码和报告哪里会被扣分。2. 吃透数据集与评价口径为什么精度不能直接当大作业的得分很多同学拿到这份大作业的第一反应是打开编辑器装库、跑模型这恰恰是最容易走弯路的地方。数据挖掘大作业的评分重点从来不是“你最后精度多高”而是“你清不清楚自己在预测什么、用什么口径评价预测结果”。所以第二章先把数据和评价口径讲透。2.1 从 CSV 到 DataFrame字段含义与质量分数的真实分布这份经典数据集以 CSV 形式分发红葡萄酒和白葡萄酒各一个文件行是样本列是理化指标加一个质量分。很多第一次接触的同学会直接在pd.read_csv()里翻车——文件的分隔符是分号而不是逗号直接读会把一整行塞进一个字段里。我一般会先指定sep;读进来再做一次快速体检。import pandas as pd # 注意分隔符是分号而不是默认的逗号 df pd.read_csv(winequality_red.csv, sep;) # 第一轮体检维度、列类型、缺失情况 print(df.shape) print(df.dtypes) print(df.isnull().sum().sum()) # 质量分数的分布决定后面用分类还是回归 print(df[quality].value_counts().sort_index())这段代码是后续所有分析的地基。df.shape告诉你样本量和特征数红葡萄酒通常在一千多行、十二列左右dtypes确认所有输入特征都是数值型省去大量编码工作isnull().sum().sum()检查全表缺失值这份数据基本是干净的但检查动作本身在报告里能体现数据理解的完整性。最后打印 quality 分布是关键动作如果 5 分和 6 分占了绝大多数3 分、8 分只有零星几条说明类别极不均衡后面的建模策略和评估指标都要跟着调整。这十一个输入特征分别是固定酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、密度、pH 值、硫酸盐和酒精度。其中挥发性酸度和酒精度是经验上与口感相关性最强的两个指标——高挥发酸往往意味着醋味或腐败味而酒精度直接关联酒体和甜感。把这些背景知识写进大作业报告的前置分析部分评委一眼就能看出你不是在盲目跑模型。2.2 先定任务再写代码分类、回归与排序问题三种切法同一个数据集可以切成三种完全不同的数据挖掘任务评价指标和模型选型都不一样。最直接的是回归把质量分当成连续值预测用平均绝对误差或均方根误差衡量。第二种是分类把每个质量分数当成一个类别用准确率和宏平均 F1 评估。第三种是简化版分类把质量分按阈值分成“差、中、好”三档把多分类问题降成三分类缓解类别不均衡。任务定义目标变量常用模型主要评估指标报告展示重点回归原始分数 0-10线性回归、随机森林回归MAE / RMSE预测值与真实值散点图多分类每个分数一个类逻辑回归、随机森林Accuracy / Macro-F1混淆矩阵三分类低/中/高三档逻辑回归、随机森林、决策树Macro-F1 / 各类别召回分档后的类别分布与错误分析我一般建议大作业选多分类或三分类因为回归的 MAE 小数点后两位在报告里很难写出亮点而分类任务天然带混淆矩阵、精确率召回率这些可解释的评估输出报告能写厚。选三分类还能额外展示“阈值划分依据”这个分析步骤这对高分目标很有帮助。顺带提醒如果选多分类评价指标不要只看 accuracy因为多数类会把准确率拉高建议用宏平均 F1 作为主指标这一点在打分时很加分。2.3 用统计量建立基线直接把均值当预测器所谓基线就是“不做任何智能预测”的模型用来证明你后续的模型确实学到了东西而不是瞎蒙。如果随机森林跑出来的准确率只比基线高两个百分点那说明特征和模型没匹配好需要回头检查。这类数据集上一个把所有样本都预测成多数类的基线分类器通常能拿到 40% 到 50% 的准确率你的模型必须明显超过它才说得过去。from sklearn.dummy import DummyClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # 建模前的准备特征与目标分离并切分为训练集和测试集 X df.drop(quality, axis1) y df[quality] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) # DummyClassifier 用 most_frequent 策略永远预测训练集中最多的类 baseline DummyClassifier(strategymost_frequent) baseline.fit(X_train, y_train) y_pred baseline.predict(X_test) # 输出基线模型的详细分类报告 print(classification_report(y_test, y_pred, zero_division0))这里有两个参数需要理解透彻。test_size0.2是切分比例留出两成样本做测试是常见做法数据量不大所以这个比例安全random_state42固定随机种子保证多次运行切分一致这是大作业代码里必须养成的习惯否则你报告里写的指标下一次运行就变了。stratifyy按类别比例分层抽样保证训练集和测试集的类别分布一致在类别不均衡时尤其重要不加这个参数的话极端情况下训练集可能没有某个质量分。DummyClassifier的作用是建立一个零智商的对照系。理解 baseline 的价值你就理解了大作业的第一个评分点模型对比。很多同学的报告只列自己模型的指标没有对照评委很难判断这个结果是好是坏。加上基线、逻辑回归、随机森林三组数字放一张表里说服力完全不同。3. 特征工程与可视化让评分老师一眼看懂你的挖掘过程建模前的数据分析环节是大作业报告里最容易被低估的部分。评委看源码和报告时首先关注的是你有没有“真的理解这份数据”而不是你用了多复杂的模型。特征工程做得好不仅提升模型上限更重要的是它把原始数据变成人可以读懂的叙事这一章的所有操作都服务于这个目标。3.1 相关性矩阵挑出与质量最相关的四个特征相关性矩阵是数据理解的标准动作它计算每个特征与质量分数的线性相关程度帮助我们快速锁定重点特征。可视化用热力图展示红蓝色块越深代表相关性越强报告里放一张热力图信息量抵得上三页文字描述。import matplotlib.pyplot as plt import seaborn as sns # 计算所有数值特征的相关系数矩阵 corr_matrix df.corr() # 按与 quality 的相关系数绝对值排序取前几名 corr_with_quality corr_matrix[quality].abs().sort_values(ascendingFalse) print(corr_with_quality) # 画热力图只显示与目标相关性较高的特征 top_features corr_with_quality.index[:7] plt.figure(figsize(10, 8)) sns.heatmap( df[top_features].corr(), annotTrue, fmt.2f, cmapRdBu_r, center0, ) plt.title(Top Features Correlation with Wine Quality) plt.show()df.corr()默认计算皮尔逊相关系数适合线性相关abs()取绝对值再排序是因为负相关同样重要。热力图部分我做了特征筛选只画和 quality 相关度最高的七个特征避免全图 12×12 的矩阵挤成一团看不清。annotTrue在格子里显示数值fmt.2f控制显示两位小数cmapRdBu_r用红蓝渐变色center0让白色对应相关为零这些参数是为了让图在报告里物理可读。在这份数据上与质量相关性最强的通常是酒精度、挥发性酸度、硫酸盐和密度它们的绝对值大致在零点二到零点三这个区间。注意相关性只衡量线性关系相关性低不代表没价值比如某个特征和质量分呈非线性关系相关系数会很低但放进树模型可能很有效。大作业里把“相关性分析”和“树模型特征重要性”两块都写上正好展示了两种互补的视角。3.2 离散化与哑变量把连续特征转换为可解释的输入如果你选三分类方案这一步就是核心把原始质量分映射成低、中、高三档。分档阈值网上各种做法都有常见切法是 3-5 分为低、6 分为中、7-8 分为高因为这份数据里 5、6 分是主体7 分以上才是真正意义上的好酒。import numpy as np # 定义分档规则3-5 分 - 低(0)6 分 - 中(1)7-8 分 - 高(2) bins [2, 5, 6, 9] labels [0, 1, 2] df[quality_category] pd.cut( df[quality], binsbins, labelslabels, rightTrue ) # 检查分档后的类别分布确认不是极端不均衡 print(df[quality_category].value_counts().sort_index()) # 删除原始质量分准备建模 df_model df.drop(quality, axis1)pd.cut的三个参数要解释清楚bins是区间边界[2, 5, 6, 9]代表三个区间 (2,5]、(5,6]、(6,9]labels给每个区间命名rightTrue是左开右闭即 5 分归入第一档、6 分归入第二档、7 分以上归入第三档。分档的动机有两层一是缓解原始质量分多分类的样本不均衡二是把“预测具体几分”变成“预测酒的品质等级”更贴近现实决策场景也更容易把错误分析写清楚。分档后检查分布是必须的动作。如果高档酒只有几十个样本后面的模型就要考虑类别权重或采样策略。在报告里我会建议写一段话说明为什么选这个分档边界——比如 6 分是这款数据的“中位数附近主体”7 分及以上在品酒语境中才算良好这样评委能看出你是基于数据分布做的决策而不是随手切一刀。3.3 特征组合酸性指标之间的交互项特征工程里性价比最高的一招是构造领域相关的交互特征。葡萄酒的酸度体系是一个整体固定酸度、挥发性酸度和柠檬酸不是独立作用的品酒师感知到的酸感往往是它们的综合结果。单纯把三个酸度指标送入模型模型要自己学交互关系但数据量不大时未必学得出来。我们可以先手动构造一个“总酸度”特征。# 构造交互特征主要酸性指标之和代表整体酸感 df[total_acidity] ( df[fixed acidity] df[volatile acidity] df[citric acid] ) # 构造比例特征挥发性酸度占总体酸度的比例代表“不良酸味”的占比 df[volatile_ratio] ( df[volatile acidity] / (df[total_acidity] 1e-9) ) # 验证新特征与质量分的相关性 print(df[total_acidity].corr(df[quality])) print(df[volatile_ratio].corr(df[quality]))构造时我做了两个方向的设计total_acidity是加和表达总酸感强度volatile_ratio是比例表达不愉悦酸味的占比。加一个很小的1e-9是防止分母为零的常规操作在代码里写上这个细节能体现工程素养。构造完后打印新特征与质量分的相关系数判断它们是否值得保留——如果相关系数接近于零说明这个组合对当前任务没有帮助可以丢掉。这里给一个容易犯错的提醒交互特征不是越多越好每加一个特征模型过拟合的风险就增加一分。我通常的做法是先构造三到五个候选交互特征用随机森林的特征重要性或简单的交叉验证筛选一遍只留下给模型带来稳定增益的那几个。这个“构造—评估—筛选”的闭环本身就是报告里的亮点流程。4. 建模与调参在源码里落地随机森林和逻辑回归这一章进入大作业最核心的部分模型实现。很多同学的代码能跑但经不起追问——为什么用这个模型为什么调这些参数参数范围为什么是这么大下面我用一个完整的建模流程把这几个问题一次讲清楚代码可以直接抄进你的源码里但更重要的是理解每行代码背后的选择逻辑。4.1 数据集切分与标准化先切再缩放避免数据泄露建模最先要做的是把数据集切分为训练集、测试集这一步必须放在特征缩放之前顺序错了就是典型的“数据泄露”。泄露会让测试指标异常好看但模型一旦暴露在真实场景里就现原形。from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 特征与目标分离 # quality_category 是上一章分档后的三分类目标 X df_model.drop(quality_category, axis1) y df_model[quality_category] # 先切分再进行任何基于全部数据的计算 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) # 标准化在训练集上 fit然后用同一组参数转换训练集和测试集 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)这段代码的关键在最后两行scaler.fit_transform(X_train)让标准化器只学习训练集的均值和方差之后用同一个 scaler 转换测试集。如果先对整个数据集做标准化再切分测试集的均值和方差已经参与了训练过程模型相当于提前偷看了测试答案测试指标失真。这个“先切后缩放”的顺序是大作业源码检查里的常见扣分点也是面试和答辩常问的细节。逻辑回归这类基于距离的模型需要标准化因为它的梯度下降受特征尺度影响酒精度零点几的数值范围和残糖几十的数值范围不在一个量级。随机森林这类树模型不受尺度影响标准化对结果基本没有作用但做了也无害。我建议在报告里写清楚“逻辑回归需要标准化树模型不需要但因为统一进了同一套预处理流程所以两类模型共用标准化结果。”这样写既显得你懂原理也能避免评委追问。4.2 随机森林超参数网格搜索的实际范围随机森林在中小型表格数据集上是公认的强基线它能自动处理非线性关系、抵抗个别异常值、不需要特征标准化而且自带特征重要性分数很适合大作业的展示需求。随机森林的核心超参数不多我一般用网格搜索调三个n_estimators、max_depth、min_samples_leaf。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import GridSearchCV from sklearn.metrics import classification_report # 定义随机森林的参数搜索范围 param_grid_rf { n_estimators: [100, 200, 300], # 树的数量越多越稳定但耗时越长 max_depth: [3, 5, 10], # 单棵树最大深度控制模型复杂度 min_samples_leaf: [1, 3, 5], # 叶节点最少样本数防止过拟合 } # 网格搜索 五折交叉验证以宏平均 F1 作为调参目标 rf RandomForestClassifier(random_state42, class_weightbalanced) grid_rf GridSearchCV( rf, param_grid_rf, scoringf1_macro, cv5, n_jobs-1, ) grid_rf.fit(X_train_scaled, y_train) # 输出最优参数和在测试集上的表现 print(Best params:, grid_rf.best_params_) y_pred_rf grid_rf.predict(X_test_scaled) print(classification_report(y_test, y_pred_rf))参数范围我解释一下取值逻辑。n_estimators取 100 到 300树太少容易不稳定超过 300 在千条数据上收益很小且训练时间变长max_depth取 3 到 10限制深度是树模型防过拟合的主力手段不限制的话树会深度生长直到叶节点只有一个样本min_samples_leaf取 1 到 5它限制叶节点至少有几个样本越大越保守。这九个组合在五折交叉验证下是 45 次拟合跑起来很快几秒到十几秒出结果。class_weightbalanced是处理类别不均衡的重要参数它让少数类在计算分裂收益时获得更高权重树模型会倾向于把少数类分对。scoringf1_macro指定用宏平均 F1 作为择优标准而不是默认的准确率这是大作业里很加分的细节——说明你意识到了类别不均衡下准确率会误导判断。网格搜索跑完把最优参数和测试集上的分类报告一起写进报告附一句“最优参数在验证集上 F1 最高测试集上宏观 F1 为 XX”整个流程就闭环了。4.3 逻辑回归的多分类设定求解器与类别不平衡逻辑回归作为对比模型放进大作业几乎是必须的因为数据挖掘课程里它是最经典的分类器评委默认你会拿出来和树模型比较。多分类场景下逻辑回归有两种策略一对多和多项式用超参数multi_class控制同时要选对求解器。from sklearn.linear_model import LogisticRegression # 多分类逻辑回归使用 saga 求解器开启类别平衡 lr LogisticRegression( max_iter1000, solversaga, multi_classmultinomial, class_weightbalanced, random_state42, ) lr.fit(X_train_scaled, y_train) # 输出测试集上的预测结果和分类报告 y_pred_lr lr.predict(X_test_scaled) print(classification_report(y_test, y_pred_lr))参数选择原因如下。solversaga是适合中小数据集的求解器支持 L1/L2 正则收敛稳健multi_classmultinomial使用多项式逻辑回归对所有类别同时建模而不是一对一拆成多个二分类整体决策边界更一致。max_iter1000是给足迭代次数默认 100 次在标准化后的数据上有时会报收敛警告调大后警告消失。class_weightbalanced同样处理类别不均衡让少数类的损失权重更高。逻辑回归的价值不只是作为对比基线它本身就是可解释性工具训练完成后每个特征对应一个权重系数系数绝对值大小反映该特征对分类决策的影响程度。在报告里可以把逻辑回归模型里酒精度、挥发性酸度这些特征的权重系数列一张表这就是一次完整的特征归因分析属于大作业的加分操作。把逻辑回归的这个小用法写进报告模型对比就不仅仅是指标对比而是“规律是否一致”的深度对比。5. 大作业避坑指南五个最容易扣分的细节这一章是血泪经验的合集。我带过的项目里好几个同学的代码逻辑没问题最终分数不高问题全部出在下面这类小细节上。每一条都按“现象—原因—解决”讲清楚你照着对照检查自己的代码就行。5.1 准确率很高但混淆矩阵一团糟现象模型报告里 accuracy 有 0.85看着很漂亮但把混淆矩阵画出来发现模型几乎把所有样本都预测成了多数类“中档酒”高档酒和低档酒根本没分出来几个。原因类别不均衡下准确率被多数类主导模型不需要认真学少数类就能拿到高准确率这是数值的假象。解决改用宏平均 F1 作为主评估指标并补画混淆矩阵训练时在模型里加class_weightbalanced让少数类的错误获得更高惩罚如果少数类样本实在太少可考虑对少数类做欠采样或对多数类做下采样。大作业报告里主动展示混淆矩阵和 macro-F1本身就说明你已经意识到了不均衡问题这一点非常加分。5.2 随机种子不固定两次运行结果不一致现象同一份源码第一次运行 accuracy 0.83第二次变成 0.79报告里写的指标对不上重跑结果。原因train_test_split和模型内部初始化都没有指定随机种子每次划分和每棵树的采样都不同。解决在任何可能引入随机性的地方固定种子统一用random_state42。更稳妥的做法是在脚本开头设置全局随机种子np.random.seed(42)加上random_state双保险再把“随机种子固定”写进报告的可复现性说明里。这个细节是答辩时评委最爱翻的。5.3 把测试集信息混进训练过程现象测试集表现好得出奇但换一套真实数据就崩盘。原因最常见的是标准化时对整个数据集调用了fit_transform也可能是做缺失值填充时用了全表的均值。解决严格遵循“先切分后预处理”的顺序任何基于数据计算出的统计量——均值、方差、中位数——都只在训练集上计算再应用到测试集。写代码时给预处理单独建一个函数或者用 Pipeline 把标准化和模型包在一起从结构上避免泄露。5.4 可视化中文乱码与负号显示问题现象matplotlib 图里的标题和坐标轴中文全部显示成方块坐标轴负号显示成乱码。原因操作系统没有配置 matplotlib 可用的中文字体。解决在绘图代码开头加以下几行指定支持中文的字体即可。这种细节看似无关痛痒但报告里的图是全英文还是规范中文直接影响观感分。import matplotlib.pyplot as plt # 指定中文字体解决绘图中文乱码问题 plt.rcParams[font.sans-serif] [SimHei, Arial Unicode MS] # 解决坐标轴负号显示异常 plt.rcParams[axes.unicode_minus] False5.5 提交的代码与报告里的指标对不上现象报告里写的随机森林 macro-F1 是 0.62但评委复现代码跑出来是 0.57结果对不上直接质疑报告造假。原因报告里的数字来自某一次运行那次运行的随机种子没有固定或者参数和提交的源码不一致。解决定稿前做一次“干净验证”——把报告里的每个数字对应的代码完整重跑一遍确认完全一致同时写一个自动输出所有关键指标的脚本统一从脚本输出粘贴报告而不是手动手抄数字。每次提交前我都习惯做一次全流程重跑这十分钟能避免最严重的信誉危机。6. 跑通之后把成果做成可复现的源码包再往前走一步到这里一个能稳定拿到良好成绩的框架已经有了数据理解、特征工程、模型对比、避坑细节。最后一章说两个让项目从“良好”变“优秀”的进阶操作。第一个是用交叉验证替代单次切分。单次切分的测试集指标波动大我会改用五折交叉验证输出最终指标取五折结果的均值和标准差比如“macro-F1 均值 0.61标准差 0.03”。报告里出现标准差评委一眼看出你做过重复实验而不是碰运气跑出个好数。第二个是展示随机森林的特征重要性。模型拟合后把每个特征的重要性分数拿出来排序和第三章的相关性分析并列对比哪些特征既线性相关又高重要性哪些特征相关性低但对树模型重要。比如密度在相关性表里可能排第四但在随机森林里重要性通常稳定靠前而 pH 值与质量分相关性很低在树模型里也基本排末位。这种“两种方法互相印证”的讨论是大作业真正拉开分差的地方。我个人的习惯是把所有代码按 1-数据探索、2-特征工程、3-建模、4-评估 四个脚本整理加上一份 README 写清运行环境、随机种子和复现步骤。这份干净、可复现、有对照的源码包往往比一个高精度但解释不清的模型更有说服力。代码本身不复杂真正复杂的是每一步都要讲得出为什么。希望这篇笔记能帮你把每个环节都建立在自己能解释的基础上祝你的数据挖掘大作业拿个好分数也希望你在调参过程中少踩几个我当年踩过的坑。本文还有配套的精品资源点击获取