学生成绩预测案例
本案例的数据来源为加州大学尔湾分校的机器学习公开样本数据集,数据介绍页面和下载地址为:https://archive.ics.uci.edu/ml/datasets/Student+Performance。该数据集包含了来自两所学校的学生的问卷调查结果,以及每位学生的综合成绩。数据集为CSV格式,每个字段的含义在官网上都有详细介绍,因此,在这里就不再赘述了。确定问题类型
我们的任务很简单,就是基于这套已有的学生问卷调查结果以及综合成绩,进行机器学习模型训练,然后,再根据一套给定的学生情况信息,来预测该名学生的综合成绩。不难发现,我们需要使用监督学习中的回归算法来进行模型训练,因为我们需要得到一个连续的预测值,而不是离散的二元或者多元值。在确定了我们的任务之后,就可以对得到的数据集进行一些预处理,以便机器学习的过程能够顺利进行。数据预处理与数据分析
在得到训练数据集之后,通常不能直接拿来进行机器学习,需要对数据进行一些处理。数据预处理任务大致有:- 数据格式规整化:对每一列的数据进行类型和单位统一,比如,“浓度”字段有些行使用的是ug/mL,有些行使用的是g/L,需要对单位进行统一,并将“浓度”字段的值转换为数值类型,以便进行统计
- 特殊值处理:有些样本数据的取值比较异常,超出正常范围很多,对于这样的数据,可以直接丢弃,也可以通过一些统计学算法对其进行修正
- 空值、无效值处理:有些样本数据的取值为空(或者对于数值型的数据,取值为0,并且不合理),对于这样的数据,也需要进行修正或者舍弃
- 数据一致性校验:对数据一致性进行校验
- 识别特征属性与目标属性:分析训练数据中,哪些属性会对预测目标造成影响,哪些属性不会影响预测结果


基于ML.NET的模型训练
注:本案例代码已开源。地址是:https://github.com/daxnet/mlnet-trainer。 通过上面的分析不难得出,我们的应用场景属于监督学习中的回归(Regression)预测,因此,我们可以选择使用ML.NET中所提供的回归算法,使用样本数据逐一完成模型训练,然后,使用测试数据对每个模型的预测结果进行评估,以选择合适的预测算法。为了对所有ML.NET默认支持的回归算法进行预测评估,在程序中使用如下数据结构来保存这些算法的实例,以便之后进行模型训练的时候,可以逐一对这些算法进行训练和评估:
1
2
3
4
5
6
7
8
9
10 |
var trainers = new List<ITrainerEstimator<ISingleFeaturePredictionTransformer<ModelParametersBase< float >>, ModelParametersBase< float >>>() { mlContext.Regression.Trainers.FastTree(), mlContext.Regression.Trainers.FastForest(), mlContext.Regression.Trainers.FastTreeTweedie(), mlContext.Regression.Trainers.GeneralizedAdditiveModels(), mlContext.Regression.Trainers.OnlineGradientDescent(), mlContext.Regression.Trainers.PoissonRegression(), mlContext.Regression.Trainers.StochasticDualCoordinateAscent() }; |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 |
public IEnumerable<KeyValuePair< string , RegressionMetrics>> TrainAndEvaluate(IDataView trainingDataView, IDataView testDataView) { var metrics = new Dictionary< string , RegressionMetrics>(); foreach ( var trainer in this .trainers) { var pipeline = mlContext.Transforms.CopyColumns(inputColumnName: "G3" , outputColumnName: "Label" ) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "School" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Sex" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Age" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Famsize" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Guardian" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Traveltime" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Studytime" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Failures" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Paid" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Higher" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Famrel" )) .Append(mlContext.Transforms.Categorical.OneHotEncoding( "Absences" )) .Append(mlContext.Transforms.Concatenate( "Features" , "School" , "Sex" , "Age" , "Famsize" , "Guardian" , "Traveltime" , "Studytime" , "Failures" , "Paid" , "Higher" , "Famrel" , "Absences" )) .AppendCacheCheckpoint(mlContext) .Append(trainer); var trainedModel = pipeline.Fit(trainingDataView); trainedModels.Add(trainer.GetType().Name, trainedModel); var predictionModel = trainedModel.Transform(testDataView); var regMetrics = mlContext.Regression.Evaluate(predictionModel); metrics.Add(trainer.GetType().Name, regMetrics); } return metrics; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 |
// 基于训练数据集进行训练,并基于测试数据集进行评估,然后输出评估结果 var regressionMetrics = session.TrainAndEvaluate(trainingDataView, testingDataView); foreach ( var item in regressionMetrics) { LearningSession.OutputRegressionMetrics(item.Key, item.Value); } // 找到RMS最小的算法,作为最优算法 var winnerAlgorithmName = regressionMetrics.OrderBy(x => x.Value.Rms).First().Key; Console.WriteLine($ "最优算法为:{winnerAlgorithmName}" ); Console.WriteLine(); var winnerModel = session.GetTrainedModel(winnerAlgorithmName); using ( var fileStream = new FileStream(ModelFileName, FileMode.Create, FileAccess.Write)) { mlContext.Model.Save(winnerModel, fileStream); } |