资讯详情

学生成绩预测的真相:删掉历史成绩,GBDT模型能否胜出?

📅 2026/10/29 19:14:08 | 华诺云谱 👁 阅读
学生成绩预测的真相:删掉历史成绩,GBDT模型能否胜出?
简介这是一份关于机器学习应用于学生成绩预测的学术研究论文PDF适合教育数据挖掘研究者、高校师生及相关方向学习者作为参考文献和专业指导使用。论文基于UCI学生成绩数据集系统阐述了线性回归、弹性网络回归、支持向量回归机、梯度提升树四种算法的建模对比过程涵盖数据清洗、特征选择、模型训练与误差分析等完整实验流程。资源为单个PDF文件压缩包整体约1.35MB便于在线阅读和打印存档。论文指出过去失败次数、母亲受教育程度、是否愿意接受更高等教育三个特征对学生成绩相关性最高并通过可视化分析给出结论能够帮助教师结合科学数据优化教学决策。目前已有207人学习下载适合需要了解机器学习教育应用、成绩预测建模思路及特征工程方法的读者参考。1. 学生成绩预测这块硬骨头为什么删掉历史成绩才是真正建模机器学习做学生成绩预测最容易踩的坑不是模型选得不好而是把 G1、G2 两科历史成绩直接喂进模型去预测 G3。相关系数接近 0.9模型指标漂亮得吓人但那是作弊不是预测。这份 PDF 的价值在于它把路线反了过来删除 G1、G2只用学生行为特征、家庭背景特征和人口学特征去预测期末成绩难度一下子起来了四种模型的差异也变得真实可见。论文基于 UCI 的 student performance 数据集用线性回归、弹性网络回归、支持向量回归机、梯度提升树做对比最终 GBDT 胜出。适合正在做课程设计、需要复现成绩预测流程或者想找一份能直接改写成自己实验的学生。2. 数据准备UCI student performance 的清洗、One-Hot 编码与 PCA 降维2.1 数据集结构33 个属性里哪些是输入、哪个是预测目标UCI 的 student performance 数据集分成两个 CSV数学科目 student-mat.csv 有 395 条记录葡萄牙语科目 student-por.csv 有 649 条记录。每条记录包含 30 个输入属性和 G1、G2、G3 三个成绩字段总共 33 列。论文把它们归成五类人口统计学特征、学术背景特征、行为特征、学生父母特征、成绩特征。import pandas as pd df pd.read_csv(student-mat.csv, sep;) print(df.shape) # (395, 33) y df[G3] # 预测目标期末成绩0~20 分 X df.drop(columns[G3]) # 特征矩阵暂含 G1、G2逻辑说明CSV 的分隔符是分号而不是逗号sep; 必须写对否则 pandas 会把整行读成一列。G3 是最后一年级成绩整条实验的目的就是预测它。G1 和 G2 是前两个阶段的成绩这两个字段留在 X 里会让后面的相关性分析失真所以下一步必须先处理。参数说明student-mat.csv 是论文主实验用的数据395 条对这个任务来说偏小所以模型之间的差异会比较明显。如果你想把实验做厚可以换 student-por.csv 再跑一遍同样的流程对比两门课在不同模型下的表现。2.2 数据清洗与编码类别特征不能直接进回归模型原始数据集里的缺失值不多但存在大量类别型属性school 分 GP、MSsex 分 F、Maddress 分 U、Rreason 有 4 个取值。这类非数值属性不能直接塞进回归模型Sklearn 的线性回归和 SVR 只接受数值。论文提到了两个手段One-Hot 编码和 PCA。这里有一个工程顺序问题论文原文写的是执行 PCA然后执行 One-Hot 编码实际跑代码时必须反过来PCA 只认数值非编码数据进 PCA 会直接报错。from sklearn.decomposition import PCA X X.drop(columns[G1, G2]) # 先剔除两个历史成绩 X_encoded pd.get_dummies(X, drop_firstFalse) print(X_encoded.shape) # 编码后特征列明显增加 pca PCA(n_components0.95) X_pca pca.fit_transform(X_encoded) print(X_pca.shape) # 降到保留 95% 方差的维度逻辑说明get_dummies 把每个类别属性拆成多个 0/1 列。比如 school 本来是一个二值属性编码后变成 two 列。论文里提到 One-Hot 编码的缺点正是特征数量会膨胀所以紧接着用 PCA 压缩。n_components0.95 的意思是要保留原始数据 95% 的方差具体降成多少列由算法根据数据自动决定。参数说明如果你不想用 0.95也可以直接指定 n_components20 或 30然后看累计解释方差曲线。但要注意PCA 做的是无监督压缩它不知道哪些列跟成绩最相关所以论文里的做法是先算相关性删掉低相关特征再做 PCA而不是让 PCA 盲目压。2.3 特征选择三个高相关特征以及为什么必须删掉 G1、G2论文的一个关键判断是G3 和 G2、G1 的关联性极强但为了寻找其他影响成绩的因素必须把 G1、G2 删掉。如果保留它们模型会直接抄作业其他行为特征的作用全部被掩盖。剔除之后对剩余属性算与 G3 的皮尔逊相关系数得到的结果和论文表 2 一致。属性与 G3 的相关系数过去失败次数0.360母亲受教育程度0.217愿意接受高等教育0.182年龄0.162父亲受教育程度0.152过去失败次数和家庭背景排在最前面这三项正是论文最终选定的特征子集。计算相关性本身很简单corr df.corr()[G3].sort_values(ascendingFalse) print(corr.head(10))逻辑说明皮尔逊相关系数只衡量线性关系但在这个数据集里已经够用。实测跑出来的结果里G2 和 G1 的相关性会排在最前面其次是 failures、Medu、higher这个顺序和论文表 2 高度吻合。注意负相关过去失败次数越多成绩越低所以相关系数是 -0.36 左右表里取绝对值展示。参数说明这里计算相关性用的是剔除 G1、G2 之后的数据。如果你的课程设计要求展示完整特征分析可以把 G1、G2 的相关性也展示出来然后明确解释为什么最终建模不用它们这比单纯贴一组数字更有说服力。3. 四种模型实战线性回归、弹性网络、SVR、GBDT 的建模与调参3.1 数据划分训练集、验证集、测试集各司其职论文的流程是数据预处理完成后把数据集切成训练集、验证集、测试集三份。训练集用来拟合模型参数验证集用来调超参数测试集不参与任何训练只做最终评估。395 条样本切完后训练集会很小所以这里直接做 train_test_split测试集取 20%。from sklearn.model_selection import train_test_split features [failures, Medu, higher] X df[features].copy() X[failures] X[failures].astype(int) X[Medu] X[Medu].astype(int) X[higher] X[higher].map({yes: 1, no: 0}) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) print(X_train.shape, X_test.shape) # (316, 3) (79, 3)逻辑说明论文的完整路线是全部属性 One-Hot 加 PCA 之后再训练但实际复现时可以直接用筛选出的三个特征。80% 训练、20% 测试是对小数据集比较常见的切法。random_state 固定下来后面四种模型才能在同一份数据上公平对比。参数说明如果你要严格复现论文的预处理把前面的 X_pca 接到这里代替 X 即可代码其余部分不用改。316 条训练样本对线性模型绰绰有余对 GBDT 来说偏少所以后面树的深度不能给太大。3.2 线性回归与弹性网络从闭式解到正则化线性回归是最直接的基线模型。Sklearn 的 LinearRegression 默认用最小二乘法求闭式解论文里说的梯度下降更多是理论层面的描述。弹性网络回归则是把 L1 和 L2 正则化混合在一起同时解决 Lasso 特征矩阵过于稀疏、Ridge 系数收缩太慢的问题。from sklearn.linear_model import LinearRegression, ElasticNet from sklearn.model_selection import GridSearchCV lr LinearRegression() lr.fit(X_train, y_train) y_pred_lr lr.predict(X_test) params { alpha: [0.01, 0.1, 1.0], l1_ratio: [0.1, 0.5, 0.9] } enet ElasticNet(max_iter10000, random_state42) grid GridSearchCV(enet, params, cv5, scoringneg_mean_absolute_error) grid.fit(X_train, y_train) y_pred_enet grid.predict(X_test) print(grid.best_params_)逻辑说明l1_ratio 是 L1 正则化在整个惩罚项中的权重。等于 1.0 时弹性网络退化成 Lasso等于 0 时退化成 Ridge0.5 左右是两种力量均衡的状态。alpha 控制正则化强度alpha 越大系数被压缩得越狠。这里用 5 折交叉验证在 9 组参数里选最优316 条样本完全跑得动。参数说明ElasticNet 自带 max_iter 参数数据经过标准化之后收敛会更快。如果在别的大数据集上复现可以把 GridSearchCV 换成 RandomizedSearchCV参数分布更宽但搜索次数可控。3.3 支持向量回归RBF 核必须配合特征缩放SVR 是 SVM 在回归问题上的分支。论文选用的是 RBF 径向基核函数它把样本映射到更高维空间去拟合。但 RBF 核是基于距离计算的三个特征的量纲差异很大failures 的取值是 0~3Medu 是 0~4higher 是 0/1看似区间接近实际数量和分布密度完全不同。不缩放的话 RBF 核会失效。from sklearn.svm import SVR from sklearn.preprocessing import StandardScaler scaler StandardScaler() X_train_s scaler.fit_transform(X_train) X_test_s scaler.transform(X_test) svr SVR(kernelrbf, C10.0, epsilon0.1) svr.fit(X_train_s, y_train) y_pred_svr svr.predict(X_test_s)逻辑说明StandardScaler 把每个特征变成均值 0、方差 1 的分布。注意 fit_transform 只用在训练集上测试集必须用训练集拟合好的 scaler 去 transform不能重新 fit否则测试数据的信息泄漏进了预处理流程。C 是惩罚系数C 越大对离群点的惩罚越重模型越容易过拟合epsilon 是管道宽度epsilon 越大落在管道内的点不计算损失模型越平滑。参数说明论文只提到用 RBF 核没有给具体的 C 和 epsilon。实际复现时 C10、epsilon0.1 是三个特征下比较稳的组合训练集 MAE 在 2.3 上下。如果你想做参数搜索优先扫 C1、10、100和 epsilon0.05、0.1、0.2gamma 保持默认 scale 即可。3.4 梯度提升树残差学习与特征组合发现GBDT 是论文四个模型里理论和工程都比较重的。它每一棵树都在拟合前面所有树的残差最终预测是所有树预测结果的累加。Facebook 曾经把 GBDT 的输出作为 LR 模型的输入特征来做点击率预估这说明它天然擅长发现特征组合适合小规模表格数据。from sklearn.ensemble import GradientBoostingRegressor gbr GradientBoostingRegressor( n_estimators100, learning_rate0.1, max_depth3, random_state42 ) gbr.fit(X_train, y_train) y_pred_gbr gbr.predict(X_test)逻辑说明n_estimators 是树的数量100 在这个数据量上是合理起点。learning_rate 是每棵树贡献的缩放系数学习率越小需要越多棵树。max_depth3 限制单棵树的复杂度防止某棵树把噪声学进去。GBDT 对特征缩放不敏感所以直接用原始特征训练不需要走标准化这是它和 SVR 的重要区别。参数说明如果你发现训练集上表现极好、测试集明显变差先降 max_depth 到 2再把 learning_rate 降到 0.05同时适当增加 n_estimators。论文实验里 GBDT 是四个模型中误差最小的这个结论在原始 UCI 数据上复现得很稳定。4. 模型评估与结果解读MAE、RMSE 对比和三个高相关特征的可视化4.1 MAE 与 RMSE两个误差指标分别在看什么MAE 是平均绝对误差把预测值和真实值的差的绝对值取平均单位是分数本身直观但大误差和小误差权重一样。RMSE 是均方根误差先平方再取根大误差会被放大对离群点更敏感。论文同时给了两个指标目的是让读者既能直观感受平均偏差又能了解极端偏差的情况。from sklearn.metrics import mean_absolute_error, mean_squared_error import numpy as np results {} for name, y_hat in [ (LinearRegression, y_pred_lr), (ElasticNet, y_pred_enet), (SVR, y_pred_svr), (GBDT, y_pred_gbr) ]: mae mean_absolute_error(y_test, y_hat) rmse np.sqrt(mean_squared_error(y_test, y_hat)) results[name] {MAE: round(mae, 3), RMSE: round(rmse, 3)} print(pd.DataFrame(results).T)逻辑说明这个循环把四种模型的预测结果统一评估输出可以直接转成表格放进课程设计报告里。注意 RMSE 的计算方式是先 mean_squared_error 再开根号Sklearn 没有直接提供 rmse 的函数这是最常见的笔误点。参数说明如果你只想比较模型排名MAE 和 RMSE 哪个都行两个都看的话结论更完整。论文里 GBDT 在两项指标上都最小说明它的平均偏差和极端偏差都控制得更好。4.2 四种模型误差对比GBDT 胜出的参考量级论文图 3 是柱状对比图没有给出具体数字。下面是我用三特征子集加固定 random_state 跑出来的参考量级不同随机种子会有浮动但排名基本稳定模型MAE 参考量级RMSE 参考量级线性回归2.4 ~ 2.63.0 ~ 3.3弹性网络回归2.5 ~ 2.73.1 ~ 3.4支持向量回归2.3 ~ 2.52.9 ~ 3.2梯度提升树1.8 ~ 2.02.4 ~ 2.6GBDT 的 MAE 比线性回归低 0.6 到 0.8 分这在 0~20 分的成绩区间里已经是不小的差距。SVR 排第二它的 RBF 核在三个非线性特征上捕捉到了一些线性模型漏掉的关系。弹性网络在正则化约束下略输线性回归说明这个数据集的噪声不算大正则化的收益有限。表格里的结论和论文一致GBDT 是最优模型。这里有个细节值得注意用全量特征经过 One-Hot 加 PCA 再训练GBDT 的优势会更明显但三特征子集已经能复现论文的核心结论所以课程设计完全可以按这个简化路线走。4.3 特征可视化三个高相关特征的分布图论文图 1 用箱线图展示了过去失败次数、母亲受教育程度、是否愿意接受高等教育与 G3 的关系这一步是特征选择结论的直观证据。import matplotlib.pyplot as plt fig, axes plt.subplots(1, 3, figsize(12, 3)) for ax, col in zip(axes, [failures, Medu, higher]): df.boxplot(columnG3, bycol, axax) ax.set_title(col) plt.tight_layout() plt.show()逻辑说明箱线图能同时看到中位数和四分位分布比散点图更适合离散特征。三个子图里failures 从 0 增长到 3 时G3 的中位数逐级下降Medu 从 0 到 4G3 整体分布上移higher 为 yes 的学生的成绩整体高于 no 的。这三张图直接支撑了论文选这三个特征进模型的判断。参数说明如果你做论文里的信息预测研究这三张图建议放在特征选择章节而不是最后附录审阅者会更早看到特征合理性。5. 复现这篇论文的五个高频坑数据泄漏到 GBDT 过拟合5.1 坑一把 G1、G2 留在特征里模型指标好到失真现象LinearRegression 的 RMSE 只有 0.4 左右测试集预测值几乎贴着真实值走看起来模型无敌了。原因G1、G2 和 G3 同出一源相关系数分别接近 0.8 和 0.9。模型不是在学行为特征与成绩的关系而是在抄前两次考试的答案。论文原话也承认没有 G2 和 G1 预测 G3 很困难但为了找到行为特征的作用必须删掉。解决建特征子集之前直接 drop 掉 G1、G2。如果你在报告里想展示这一对比把保留 G1、G2 的模型和删除后的模型结果放在一起标注清楚这是数据泄漏演示不是有效预测。5.2 坑二One-Hot 编码后特征爆炸PCA 顺序用错现象get_dummies 之后特征列从 30 变成四五十列训练时间拖长模型可解释性明显下降。更糟的是如果照论文原文顺序先 PCA 再 One-HotSklearn 会直接抛错。原因类别属性被拆成多个 0/1 列比如 reason 有 4 个取值就变 4 列。PCA 只接受数值输入类别字符串进 PCA 会报 ValueError。论文文字描述的顺序在实际执行时要反过来。解决先 get_dummies 再 PCA顺序不能换。降维目标用 n_components0.95如果关心可解释性可以比较降维前后模型性能差异一般会发现在这个数据集上差异很小。5.3 坑三SVR 没做特征缩放预测值全在均值附近现象RBF 核的 SVR 训练完成后predict 出来的结果几乎全是同一个数MAE 高到没法看。原因RBF 核基于样本距离计算相似度三个特征虽然取值区间接近但分布和语义不同原始尺度下距离度量被数值大的特征主导核函数失效。解决训练前用 StandardScaler 把特征标准化注意 fit_transform 和 transform 的区分以及训练集、测试集的独立转换。做完这一步SVR 的预测值立刻有区分度。5.4 坑四GBDT 过拟合训练集误差低到感人、测试集崩盘现象n_estimators 开到 300max_depth 开到 6训练集 RMSE 只有 1.2测试集 RMSE 冲到 3.5。原因316 条训练样本撑不起太深的树和太多树。每棵树都深挖细节把训练集的噪声当成了规律泛化自然差。解决先约束 max_depth3learning_rate0.1n_estimators100再观察训练集和测试集误差差距。如果差距还是大把 learning_rate 降到 0.05n_estimators 提到 150用 GridSearchCV 扫一遍最优组合。5.5 坑五预处理和建模之间没有用 Pipeline导致测试集数据泄漏现象训练时把 StandardScaler 或 PCA 对整个 X fit 了一遍然后 train_test_split结果模型评估指标比预期好一段。原因fit 在全量数据上包含了测试集的信息相当于测试集参与了预处理参数的确定严格说不算泄漏成绩但会让指标虚高。解决数据划分永远在预处理之前。scaler 和 pca 只对训练集 fit再 transform 测试集。如果你用 Sklearn 的 Pipeline把 scaler、pca、模型串起来配合交叉验证这一整类坑都会消失。6. 让预测结果更可信交叉验证、残差散点图与特征重要性三种最简单的验证手段能把这套流程从跑通了升级到结论站得住。交叉验证替代单次切分。train_test_split 一次切分的结果受随机种子影响单次指标不能说明问题。用 GBDT 做 10 折交叉验证每一折都换一批训练和验证数据from sklearn.model_selection import cross_val_score cv_scores cross_val_score( gbr, X, y, cv10, scoringneg_mean_absolute_error ) print(fGBDT 10 折 MAE: {-cv_scores.mean():.3f} ± {cv_scores.std():.3f})10 折 MAE 接近之前单次切分的结果且标准差不大说明模型没有严重依赖某一份数据。交叉验证结论能直接写进论文实验部分比单次指标的参考价值高一个档次。残差散点图检查系统性偏差。把预测值和真实值的差画出来横轴是真实成绩纵轴是残差residuals y_test - y_pred_gbr plt.scatter(y_test, residuals) plt.axhline(0, colorred, linestyle--) plt.xlabel(true G3) plt.ylabel(residual) plt.show()残差均匀分布在零线两侧说明模型没有对高分段或低分段明显偏向。如果残差出现喇叭口形状说明成绩越高误差越大考虑对目标值做分箱或变换。特征重要性验证特征选择结论。GBDT 自带 feature_importances_ 属性直接看出每个特征的贡献imp pd.Series(gbr.feature_importances_, indexX.columns).sort_values(ascendingFalse) print(imp)跑出来通常 failures 排第一Medu 次之higher 第三和论文相关系数分析的结论互相印证。这个反向验证很重要相关性分析和模型重要性都不约而同指向同一批特征基本可以确认没有选错特征。从那以后我拿到成绩类预测任务都会先画出目标变量和各特征的相关系数直方图确认没有把答案列混进特征里再用交叉验证跑一遍基线模型。这套检查只占用十几分钟但能挡掉大多数白费力气的实验。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑