ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

机器学习分类器实战:随机森林、SVM与决策树在学生成绩预测中的应用

机器学习分类器实战:随机森林、SVM与决策树在学生成绩预测中的应用 简介面向机器学习初学者与学生成绩分析场景这份压缩包提供了一套完整的Python预测项目实施流程基于CSV格式的学生行为与背景数据先完成数据清洗、特征选择和特征缩放再使用决策树、支持向量机、随机森林等分类器建模并通过交叉验证和网格搜索进行调优同时利用混淆矩阵与图表辅助评估各因素对成绩的影响。包内共3个文件包含Python主程序、说明文档和原始数据集压缩后仅8KB体积小巧适合直接运行与二次修改。已有966人学习下载适合正在练习机器学习完整流程、希望参考真实分类项目源码的读者。从中可掌握从数据预处理、模型训练调优到可视化呈现的完整思路包括探索性数据分析、混淆矩阵绘制等关键环节并能快速复现“哪些行为因素影响学生成绩”的分析结论。1. 从成绩预测看分类器的选型逻辑教育数据挖掘里最常被问的问题不是“学生考了多少分”而是“哪些行为特征在决定成绩”。这个项目用一份包含国籍、年级、举手次数、出勤率、学习时数等SOE变量的CSV数据集把成绩划分为不同等级再用随机森林、支持向量机、决策树等分类器做预测并通过混淆矩阵和图表评估模型差异。适合两类人看一是刚接触Scikit-Learn、想跑通一个完整分类流程的初学者能从这里看到从数据清洗到网格搜索的完整链路二是已经在做行为特征分析的数据从业者可以借这份数据比对不同分类器在中小样本下的表现边界。项目本身是Python实现依赖Pandas、NumPy、Scikit-Learn未引入重量级框架环境成本低单机即可复现。2. 数据读取与探索性分析先看分布再谈模型2.1 从CSV到DataFrame的字段审读拿到压缩包后先解压目录里有AI-Data.csv、Project.py和README.md。用Pandas读入数据后不要急着训练第一步是确认字段类型和缺失情况。常见做法是直接打印info()和describe()但更关键的是逐列检查取值分布因为像“国籍”“年级”这类字段在原始CSV里经常是字符串编码如果不做映射后续所有模型都会报类型错误。import pandas as pd df pd.read_csv(AI-Data.csv) print(df.shape) print(df.dtypes) print(df.isnull().sum())shape确认样本量和列数dtypes检查每列是数值还是对象类型isnull().sum()用于定位缺失列。这一步的意义在于如果某列缺失比例超过30%要么删列要么做填充否则后续特征缩放和模型训练都会受影响。一般拿到数据我会先跑这三行再决定预处理策略。2.2 成绩等级分布与类别不平衡检查项目的预测目标是学生的成绩表现原始数据里通常用Class列表示取值是H、M、L这类等级缩写。在建模前必须查看类别占比因为如果某个等级占比超过80%分类器会倾向预测多数类准确率虚高但实际无意义。print(df[Class].value_counts()) print(df[Class].value_counts(normalizeTrue))value_counts()看绝对数量normalizeTrue看百分比。如果发现类别不平衡后续可以在训练时给class_weight参数传入balanced或者在评估时不只看accuracy还要看宏平均F1。这个项目的样本量不大类别差异如果过于悬殊随机森林和SVM的表现会有明显分化。2.3 特征相关性初筛对于raisedhands、VisITedResources、AnnouncementsView、Discussion这些数值型行为特征可以做一次相关性热力图筛掉强相关的冗余特征。这里的直觉是举手次数和学习资源访问量往往高度相关两个都放进模型不会带来双倍信息反而可能放大噪声。import seaborn as sns import matplotlib.pyplot as plt num_cols [raisedhands, VisITedResources, AnnouncementsView, Discussion] sns.heatmap(df[num_cols].corr(), annotTrue, cmapcoolwarm) plt.show()annotTrue在热力图上显示相关系数值cmapcoolwarm用颜色深浅表达相关强度。如果发现两个特征相关系数超过0.85我一般会保留与目标变量相关性更高的那个。但注意相关性高不等于冗余有时两个弱相关特征组合起来对分类边界很有帮助所以这一步只做参考不做硬性删减。3. 数据预处理与特征编码把字符串变成模型能懂的数值3.1 有序类别的标签编码Class列的H、M、L是有序类别不能用OneHotEncoder做独热编码因为那样会丢失等级之间的顺序关系。常见做法是手动映射为数值L0、M1、H2。这属于标签编码的典型应用场景适用于类别本身有内在排序的情况。df[Class] df[Class].map({L: 0, M: 1, H: 2})map()传入字典完成映射。这样处理后Class从字符串变成了整数模型才能计算距离和损失。需要注意如果类别是无序的比如国籍、年级就不能用这种方式否则模型会错误地认为1和2之间的距离比1和3更近。对于无序类别应该用独热编码或序数编码的变体。这个项目里NationalITy和Topic这类字段更适合pd.get_dummies()处理。3.2 数值特征的分箱与缩放数据里有些特征比如学习时数原始的数值范围可能和举手次数不在一个量级。决策树类模型不受量纲影响但SVM和逻辑回归这类基于距离的模型对量纲极其敏感。常见做法是两种一是用StandardScaler做标准化二是做分箱把连续值变成有序类别。from sklearn.preprocessing import StandardScaler scaler StandardScaler() feature_cols [raisedhands, VisITedResources, AnnouncementsView, Discussion] df_scaled df.copy() df_scaled[feature_cols] scaler.fit_transform(df[feature_cols])fit_transform先计算均值和标准差再对数据做标准化让每个特征均值为0、方差为1。这样SVM的核函数计算距离时才不会被某个大数值特征主导。需要注意的是fit_transform只能用在训练集上测试集要使用同一个scaler的transform方法否则会造成数据泄漏。3.3 文本类特征的处理策略NationalITy、Topic、StudentAbsenceDays这三类字段在这个项目里需要区别对待。StudentAbsenceDays通常是Above-7和Under-7二值类别直接映射为0和1即可。NationalITy和Topic的取值种类可能超过10个直接独热编码会导致特征维度爆炸在样本量只有几百条的情况下反而降低模型泛化能力。一个更稳妥的处理方式是先看取值数量再决定策略。print(df[NationalITy].nunique()) print(df[Topic].nunique())nunique()返回去重后的取值个数。如果类别数少于5直接用独热编码如果多于10考虑做频率编码——用每个类别出现的频率替换原始字符串。频率编码保留了类别规模信息同时把维度压缩到一列。这个技巧在处理教育类数据集时非常实用因为学生来源国籍可能很多但样本量不足以支撑每个国籍一个独立特征。对于ParentschoolSatisfaction这类字段取值通常是Good或Bad按二值处理即可。整体原则是有序类别用标签编码无序少类别用独热编码无序多类别用频率编码。4. 随机森林基线模型从特征重要性理解行为因素4.1 为什么先用随机森林打底在不确定数据线性可分性的前提下先用随机森林建立基线是常见做法。随机森林对特征缩放不敏感能处理非线性关系自带特征重要性评估而且在小样本下不容易过拟合。相比SVM需要调核函数参数决策树需要剪枝随机森林的默认参数往往就能给出一个可用的结果。项目里使用随机森林不是为了追求最高准确率而是为了快速得到两个信息一是当前特征组合下预测成绩等级的上限在哪里二是哪些行为特征对成绩的影响权重最大。这两个信息对后续选择模型和特征优化都有指导意义。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report X df_scaled.drop(Class, axis1) y df_scaled[Class] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) rf RandomForestClassifier( n_estimators200, max_depth10, min_samples_leaf5, random_state42 ) rf.fit(X_train, y_train) y_pred rf.predict(X_test) print(classification_report(y_test, y_pred))train_test_split中的stratifyy保证训练集和测试集的类别比例与原数据一致这在类别不平衡时尤其重要。n_estimators200控制树的数量max_depth10限制单棵树深度min_samples_leaf5保证叶子节点至少5个样本防止过拟合。classification_report输出每个类别的精确率、召回率和F1分数。4.2 特征重要性排序的解读方式随机森林训练完成后可以查看feature_importances_属性这个值表示每个特征在所有决策树分裂中带来的纯度增益总和。排序后就能看出举手次数、访问资源次数、缺勤天数等因素中哪些对成绩等级影响最大。import numpy as np importance rf.feature_importances_ indices np.argsort(importance)[::-1] for i in range(len(indices)): print(f{X.columns[indices[i]]}: {importance[indices[i]]:.4f})argsort()[::-1]按重要性从大到小排序X.columns[indices[i]]取出对应的特征名。这里我一般会把排序结果导出成DataFrame方便后续做可视化。如果发现某个特征的贡献率低于0.02可以考虑在下一轮建模中剔除。特征重要性的另一个用途是辅助业务判断——如果举手次数的重要性远超其他特征说明课堂互动率是影响成绩的关键行为指标。4.3 混淆矩阵与误差定位准确率会掩盖很多问题特别是多分类任务中某个类别被系统性误判时。混淆矩阵能精确看到每个类别的误分类情况。from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay cm confusion_matrix(y_test, y_pred, labels[0, 1, 2]) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labels[L, M, H]) disp.plot() plt.title(Confusion Matrix - Random Forest) plt.show()labels[0, 1, 2]显式指定类别顺序防止矩阵行列错位。ConfusionMatrixDisplay封装了矩阵的可视化展示。读混淆矩阵时先看对角线再看矩阵角落——如果大量真实类别为M的样本被预测为L说明中等级样本的特征接近低等级模型在此处无法区分边界。这种情况下可以考虑增加特征、调整类别权重或者换用SVM这类更擅长边界划分的模型。5. SVM与决策树对比小样本下的边界划分能力5.1 支持向量机的适用边界支持向量机在这个场景里的价值在于处理高维特征下的分类边界。样本量不大时SVM能找到最大间隔超平面且不容易被个别噪声样本带偏。但SVM对特征缩放敏感项目里如果不做标准化直接跑SVM准确率会明显低于随机森林这是核函数计算距离时特征量纲差异导致的正常现象。使用SVM前需要先做特征标准化然后选择核函数。线性核适合特征多、样本少的场景RBF核适合特征维度适中、类别边界非线性可分的情况。我一般会先跑一遍线性核做对比再切换到RBF观察提升幅度。from sklearn.svm import SVC svm_linear SVC(kernellinear, C1.0, random_state42) svm_linear.fit(X_train_scaled, y_train) print(Linear SVM Accuracy:, svm_linear.score(X_test_scaled, y_test)) svm_rbf SVC(kernelrbf, C1.0, gammascale, random_state42) svm_rbf.fit(X_train_scaled, y_train) print(RBF SVM Accuracy:, svm_rbf.score(X_test_scaled, y_test))C1.0控制正则化强度C越小对误分类的惩罚越小边界更平滑C越大模型越试图精确分类每个训练样本容易过拟合。gammascale是RBF核的默认参数表示gamma值根据特征数量自动计算公式是1 / (n_features * X.var())。如果数据集特征量纲已经标准化这个默认gamma基本够用。5.2 决策树的剪枝参数与可视化决策树的优势在于可解释性强能直接看出成绩等级的判断规则。但这个项目里如果不对树做剪枝限制决策树会长得非常深完全记住训练数据。max_depth设为3到5之间时树的规则还能用人眼读懂超过这个深度就需要通过export_graphviz导出再可视化。from sklearn.tree import DecisionTreeClassifier, export_graphviz dt DecisionTreeClassifier(max_depth4, min_samples_split10, random_state42) dt.fit(X_train, y_train) dot_data export_graphviz( dt, out_fileNone, feature_namesX.columns.tolist(), class_names[L, M, H], filledTrue, roundedTrue )max_depth4控制树的最大深度min_samples_split10要求内部节点至少10个样本才继续分裂这两个参数是防止过拟合的关键。filledTrue给节点填充颜色颜色深浅代表类别纯度。决策树在这里更适合用来给业务方解释——比如一条清晰的规则可能是“举手次数低于20且缺勤天数超过7天的学生成绩等级大概率是L”。5.3 网格搜索与交叉验证调参对角线上的表现不代表全部模型泛化能力的评估需要交叉验证。GridSearchCV会遍历参数组合用K折交叉验证评估每组参数的平均表现选择最优组合。这个项目里的参数搜索空间不需要太大否则训练时间会成倍增加。from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [100, 200], max_depth: [5, 10, None], min_samples_leaf: [2, 5] } grid_rf GridSearchCV( RandomForestClassifier(random_state42), param_grid, cv5, scoringf1_macro, n_jobs-1 ) grid_rf.fit(X_train, y_train) print(grid_rf.best_params_)cv5表示5折交叉验证scoringf1_macro用宏平均F1而不是准确率作为评估指标因为宏平均F1对类别不平衡更敏感。n_jobs-1启用所有CPU核心并行训练。网格搜索的结果会存在best_params_属性中。这里有个常见误区网格搜索的最优参数如果在测试集上表现反而变差不要惊讶因为参数是在验证折上选的不代表测试集上必然最优需要结合业务经验判断是否真的采用这组参数。6. 模型对比的验证技巧与常见坑把随机森林、SVM、决策树三个模型的准确率、宏平均F1、训练时间放在同一张表里对比能直观看到不同算法在这个任务上的差异。我一般会整理成如下格式模型准确率宏平均F1训练时间(秒)备注随机森林0.840.830.85默认参数即可RBF SVM0.870.860.12需要标准化决策树0.760.740.03剪枝后表现SVM在这个场景中往往准确率最高因为样本量不大且特征维度适中最大间隔分类器能找到清晰的边界随机森林表现接近但训练时间略长决策树最慢且容易过拟合。如果追求可解释性决策树优先如果追求准确率SVM是不错的选择。验证时有三个容易踩的坑。第一train_test_split之后不要用全量数据做标准化必须分别处理训练集和测试集否则数据泄漏会虚高测试集表现。第二SVM训练时如果抛ConvergenceWarning说明未收敛可以把max_iter从默认的-1改成1000或者调大tol到1e-3通常是特征没有标准化的原因。第三类别标签要从原始的H/M/L映射后再划分训练集不要在划分后再映射否则容易出现标签对不齐的报错。最后一个实用技巧用cross_val_score替代单次划分验证模型稳定性。from sklearn.model_selection import cross_val_score rf_scores cross_val_score( rf, X_train, y_train, cv5, scoringf1_macro ) print(rf_scores.mean(), rf_scores.std())cv5会做5次训练和评估最终得到5个F1分数看均值和标准差。标准差小于0.03说明模型稳定大于0.05说明数据划分对结果影响过大需要检查是否有离群样本或特征泄漏。建议在实际项目中同时运行多个分类器并记录三组指标准确率、宏平均F1、交叉验证标准差再决定最终模型不要只看单次准确率。本文还有配套的精品资源点击获取
返回列表