1、准备样本html
接上一篇文章提到的问题:根据一我的的身高、体重来判断一我的的身材是否很好。但我手上没有样本数据,只能伪造一批数据了,伪造的数据比较标准,用来学习仍是蛮合适的。git
下面是我用来伪造数据的代码:github
string Filename = "./figure_full.csv"; StreamWriter sw = new StreamWriter(Filename, false); sw.WriteLine("Height,Weight,Result"); Random random = new Random(); float height, weight; Result result; for (int i = 0; i < 2000; i++) { height = random.Next(150, 195); weight = random.Next(70, 200); if (height > 170 && weight < 120) result = Result.Good; else result = Result.Bad; sw.WriteLine($"{height},{weight},{(int)result}"); } enum Result { Bad=0, Good=1 }
制形成功后的数据以下:算法
用记事本打开:数组
2、源码框架
数据准备好了,咱们就用准备好的数据进行学习了,先贴出所有代码,而后再逐一解释:dom
namespace BinaryClassification_Figure { class Program { static readonly string DataPath = Path.Combine(Environment.CurrentDirectory, "Data", "figure_full.csv"); static readonly string ModelPath = Path.Combine(Environment.CurrentDirectory, "Data", "FastTree_Model.zip"); static void Main(string[] args) { TrainAndSave(); LoadAndPrediction(); Console.WriteLine("Press any to exit!"); Console.ReadKey(); } static void TrainAndSave() { MLContext mlContext = new MLContext(); //准备数据 var fulldata = mlContext.Data.LoadFromTextFile<FigureData>(path: DataPath, hasHeader: true, separatorChar: ','); var trainTestData = mlContext.Data.TrainTestSplit(fulldata,testFraction:0.2); var trainData = trainTestData.TrainSet; var testData = trainTestData.TestSet; //训练 IEstimator<ITransformer> dataProcessPipeline = mlContext.Transforms.Concatenate("Features", new[] { "Height", "Weight" }) .Append(mlContext.Transforms.NormalizeMeanVariance(inputColumnName: "Features", outputColumnName: "FeaturesNormalizedByMeanVar")); IEstimator<ITransformer> trainer = mlContext.BinaryClassification.Trainers.FastTree(labelColumnName: "Result", featureColumnName: "FeaturesNormalizedByMeanVar"); IEstimator<ITransformer> trainingPipeline = dataProcessPipeline.Append(trainer); ITransformer model = trainingPipeline.Fit(trainData); //评估 var predictions = model.Transform(testData); var metrics = mlContext.BinaryClassification.Evaluate(data: predictions, labelColumnName: "Result", scoreColumnName: "Score"); PrintBinaryClassificationMetrics(trainer.ToString(), metrics); //保存模型 mlContext.Model.Save(model, trainData.Schema, ModelPath); Console.WriteLine($"Model file saved to :{ModelPath}"); } static void LoadAndPrediction() { var mlContext = new MLContext(); ITransformer model = mlContext.Model.Load(ModelPath, out var inputSchema); var predictionEngine = mlContext.Model.CreatePredictionEngine<FigureData, FigureDatePredicted>(model); FigureData test = new FigureData(); test.Weight = 115; test.Height = 171; var prediction = predictionEngine.Predict(test); Console.WriteLine($"Predict Result :{prediction.PredictedLabel}"); } } public class FigureData { [LoadColumn(0)] public float Height { get; set; } [LoadColumn(1)] public float Weight { get; set; } [LoadColumn(2)] public bool Result { get; set; } } public class FigureDatePredicted : FigureData { public bool PredictedLabel; } }
3、对代码的解释机器学习
一、读取样本数据ide
string DataPath = Path.Combine(Environment.CurrentDirectory, "Data", "figure_full.csv"); MLContext mlContext = new MLContext(); //准备数据 var fulldata = mlContext.Data.LoadFromTextFile<FigureData>(path: DataPath, hasHeader: true, separatorChar: ','); var trainTestData = mlContext.Data.TrainTestSplit(fulldata,testFraction:0.2); var trainData = trainTestData.TrainSet; var testData = trainTestData.TestSet;
LoadFromTextFile<FigureData>(path: DataPath, hasHeader: true, separatorChar: ',')用来读取数据到DataView函数
FigureData类是和样本数据对应的实体类,LoadColumn特性指示该属性对应该条数据中的第几个数据。
public class FigureData { [LoadColumn(0)] public float Height { get; set; } [LoadColumn(1)] public float Weight { get; set; } [LoadColumn(2)] public bool Result { get; set; } }
path:文件路径
hasHeader:文本文件是否包含标题
separatorChar:用来分割数据的字符,咱们用的是逗号,经常使用的还有跳格符‘\t’
TrainTestSplit(fulldata,testFraction:0.2)用来随机分割数据,分红学习数据和评估用的数据,一般状况,若是数据较多,测试数据取20%左右比较合适,若是数据量较少,测试数据取10%左右比较合适。
若是不经过分割,准备两个数据文件,一个用来训练、一个用来评估,效果是同样的。
二、训练
//训练 IEstimator<ITransformer> dataProcessPipeline = mlContext.Transforms.Concatenate("Features", new[] { "Height", "Weight" }) .Append(mlContext.Transforms.NormalizeMeanVariance(inputColumnName: "Features", outputColumnName: "FeaturesNormalizedByMeanVar")); IEstimator<ITransformer> trainer = mlContext.BinaryClassification.Trainers.FastTree(labelColumnName: "Result", featureColumnName: "FeaturesNormalizedByMeanVar"); IEstimator<ITransformer> trainingPipeline = dataProcessPipeline.Append(trainer); ITransformer model = trainingPipeline.Fit(trainData);
IDataView这个数据集就相似一个表格,它的列(Column)是能够动态增长的,一开始咱们经过LoadFromTextFile得到的数据集包括:Height、Weight、Result这几个列,在进行训练以前,咱们还要对这个数据集进行处理,造成符合咱们要求的数据集。
Concatenate这个方法是把多个列,组合成一个列,由于二元分类的机器学习算法只接收一个特征列,因此要把多个特征列(Height、Weight)组合成一个特征列Features(组合的结果应该是个float数组)。
NormalizeMeanVariance是对列进行归一化处理,这里输入列为:Features,输出列为:FeaturesNormalizedByMeanVar,归一化的含义见本文最后一节介绍。
数据集就绪之后,就要选择学习算法,针对二元分类,咱们选择了快速决策树算法FastTree,咱们须要告诉这个算法特征值放在哪一个列里面(FeaturesNormalizedByMeanVar),标签值放在哪一个列里面(Result)。
连接数据处理管道和算法造成学习管道,将数据集中的数据逐一经过学习管道进行学习,造成机器学习模型。
有了这个模型咱们就能够经过它进行实际应用了。但咱们通常不会如今就使用这个模型,咱们须要先评估一下这个模型,而后把模型保存下来。之后应用时再经过文件读取出模型,而后进行应用,这样就不用等待学习的时间了,一般学习的时间都比较长。
三、评估
//评估 var predictions = model.Transform(testData); var metrics = mlContext.BinaryClassification.Evaluate(data: predictions, labelColumnName: "Result"); PrintBinaryClassificationMetrics(trainer.ToString(), metrics);
评估的过程就是对测试数据集进行批量转换(Transform),转换过的数据集会多出一个“PredictedLabel”的列,这个就是模型评估的结果,逐条将这个结果和实际结果(Result)进行比较,就最终造成了效果评估数据。
咱们能够打印这个评估结果,查看其成功率,通常成功率大于97%就是比较好的模型了。因为咱们伪造的数据比较整齐,因此咱们此次评估的成功率为100%。
注意:评估过程不会提高现有的模型能力,只是对现有模型的一种检测。
四、保存模型
//保存模型 string ModelPath = Path.Combine(Environment.CurrentDirectory, "Data", "FastTree_Model.zip"); mlContext.Model.Save(model, trainData.Schema, ModelPath); Console.WriteLine($"Model file saved to :{ModelPath}");
这个没啥好解释的。
五、读取模型并建立预测引擎
//读取模型 var mlContext = new MLContext(); ITransformer model = mlContext.Model.Load(ModelPath, out var inputSchema); //建立预测引擎 var predictionEngine = mlContext.Model.CreatePredictionEngine<FigureData, FigureDatePredicted>(model);
建立预测引擎的功能和Transform是相似的,不过Transform是处理批量记录,这里只处理一条数据,并且这里的输入输出是实体对象,定义以下:
public class FigureData { [LoadColumn(0)] public float Height { get; set; } [LoadColumn(1)] public float Weight { get; set; } [LoadColumn(2)] public bool Result { get; set; } } public class FigureDatePredicted : FigureData { public bool PredictedLabel; }
因为预测结果里放在“PredictedLabel”字段中,因此FigureDatePredicted类必需要包含PredictedLabel属性,目前FigureDatePredicted 类是从FigureData类继承的,因为咱们只用到PredictedLabel属性,因此不继承也没有关系,若是继承的话,后面要调试的话会方便一点。
六、应用
FigureData test = new FigureData { Weight = 115, Height = 171 }; var prediction = predictionEngine.Predict(test); Console.WriteLine($"Predict Result :{prediction.PredictedLabel}");
这部分代码就比较简单,test是咱们要预测的对象,预测后打印出预测结果。
4、附:数据归一化
机器学习的算法中通常会有不少的乘法运算,当运算的数字过大时,很容易在屡次运算后溢出,为了防止这种状况,就要对数据进行归一化处理。归一化的目标就是把参与运算的特征数变为(0,1)或(-1,1)之间的浮点数,常见的处理方式有:min-max标准化、Log函数转换、对数函数转换等。
咱们此次采用的是平均方差归一化方法。
5、资源
源码下载地址:https://github.com/seabluescn/Study_ML.NET
工程名称:BinaryClassification_Figure