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