讓我們一起ML(Make Love Machine Learning)吧!
ML.NET是微軟推出的一個免費的開源跨平台機器學習框架,可用於生成自定義機器學習解決方案並將其集成到 .NET 應用程序。ML.NET當前最新版本為0.7,目前處於預覽狀態,本文中用到的例子來自於微軟的官方教程,但隨時可能更改,請注意版本變更造成的例子無法運行的狀況。
准備工作
你需要一個安裝了.NET Core 的VS2017 15.6或更高版本。
了解問題
在本篇中我們將對鳶尾花的數據進行聚類分析,並通過訓練出來的模型來判斷給出的數據是哪種鳶尾花。
此問題的本質即基於花卉特征將鳶尾花數據歸入不同的組。 這些特征包括:花萼的長度和寬度以及花瓣的長度和寬度。 此教程假設每朵花的類型都是未知的。 需通過這些特征了解數據集的結構,並預測數據實例與此結構的擬合程度。
淺解算法
本例中選擇K-Means算法解決問題,K-Means算法是個什么算法?不懂也沒關系,簡單給你介紹一下(我也是剛查的,想詳細了解的自己wiki百科),K-Means算法簡單來說就是給出n個數據,然后指定一個K(這個K是個大於1小於n的正整數),n個數據就被分成K堆,這個堆被稱為聚類,再給出一個樣例數據,用同樣的方法將樣例分入其中某一聚類完成聚類分析。
這K堆或者K類或者K組(K個聚類)如何分呢?假設n個數據為二維平面中的點 P1(x1,y1),P2(x2,y2),...,Pn(xn,yn) ,從n個點中隨機選出K個點,這K個點被稱作形心(有人也翻譯成質心),然后計算其他n-K個點與這K個形心的歐氏距離(即兩點之間的直線距離,歐氏即歐幾里得),一個點距離哪個形心的距離最短即被分到哪個組,然后循環更換形心再次計算,直到K個組中的點都不再變化,至此n個點即被分為K組數據(K個聚類)。K-Means算法的優點是簡單易行,只用指定一個參數K,難點是K值的選取。如果對算法有興趣可以移步這里看看如何實現算法。
示例代碼
本示例所有官方教程源代碼都在這里,我的示例與官方示例略有不同。
- 打開VS創建一個控制台應用(.NET Core)命名為IrisClustering
- 安裝Microsoft.ML Nuget包(當前最新版本為0.7)
- 在項目根路徑下創建一個Data文件夾,從這里下載鳶尾花的數據保存到剛建好的Data文件夾下命名為iris_data.txt,點擊iris_data.txt 將文件屬性中復制到輸出目錄項的值改為如果較新則復制
在項目中添加實體類IrisData.cs如下:
1 using Microsoft.ML.Runtime.Api; 2 3 namespace IrisClustering 4 { 5 public class IrisData 6 { 7 [Column("0")] 8 public float SepalLength; 9 10 [Column("1")] 11 public float SepalWidth; 12 13 [Column("2")] 14 public float PetalLength; 15 16 [Column("3")] 17 public float PetalWidth; 18 } 19 20 public class ClusterPrediction 21 { 22 [ColumnName("PredictedLabel")] 23 public uint PredictedClusterId; 24 25 [ColumnName("Score")] 26 public float[] Distances; 27 } 28 }
其中IrisData
類是輸入數據類,通過使用Column
屬性在數據集文件中指定源列的索引。
ClusterPrediction
類表示應用到IrisData
實例的聚類分析模型的輸出。通過使用ColumnName
屬性將PredictedClusterId
和 Distances
字段分別綁定至PredicatedLabel
和 Score
列。
PredictedLabel
包含所預測群集的ID。Score
包含一個數組,這個數組中的數即為與群集形心之間歐氏距離的平方。這個數組的長度等於群集數(K-Means算法中的K值)。
接下來在Program.cs中添加預測模型的訓練方法並通過Main方法訓練預測模型並預測給出的樣例屬於哪種鳶尾花
1 using System; 2 using System.IO; 3 using System.Threading.Tasks; 4 using Microsoft.ML.Legacy; 5 using Microsoft.ML.Legacy.Data; 6 using Microsoft.ML.Legacy.Trainers; 7 using Microsoft.ML.Legacy.Transforms; 8 9 namespace IrisClustering 10 { 11 public static class Program 12 { 13 //數據文件路徑 14 static readonly string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "iris_data.txt"); 15 //預測模型保存路徑 16 static readonly string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "IrisClusteringModel.zip"); 17 //預測模型訓練方法 18 private static PredictionModel<IrisData, ClusterPrediction> Train() 19 { 20 var pipeline = new LearningPipeline 21 { 22 new TextLoader(_dataPath).CreateFrom<IrisData>(separator: ','), //加載數據 23 new ColumnConcatenator( //指定數據列名 24 "Features", //特征 學習算法將通過ColumnConcatenator類將數據轉化為特征列的值 25 "SepalLength", //花萼長度 26 "SepalWidth", //花萼寬度 27 "PetalLength", //花瓣長度 28 "PetalWidth"), //花瓣寬度 29 new KMeansPlusPlusClusterer() { K = 3 } //指定K-Means算法,這里因為數據中已經給出三個分類,所以我們指定K值為3 30 }; 31 var model = pipeline.Train<IrisData, ClusterPrediction>(); 32 return model; 33 } 34 35 //在Main方法前加async關鍵字是c#7.1及以后的新功能 36 //應當右鍵單擊項目名稱(IrisClustering) 屬性->生成->高級->語言版本 中將語言改為c#7.1 37 private static async Task Main(string[] args) 38 { 39 PredictionModel<IrisData, ClusterPrediction> model = Train(); 40 await model.WriteAsync(_modelPath); 41 var prediction = model.Predict(TestIrisData.Setosa); 42 Console.WriteLine($"Cluster:{prediction.PredictedClusterId}"); 43 Console.WriteLine($"Distances:{string.Join(" ",prediction.Distances)}"); 44 Console.Read(); 45 } 46 } 47 }
被用於預測的樣例數據如下TestIrisData.cs
1 namespace IrisClustering 2 { 3 static class TestIrisData 4 { 5 internal static readonly IrisData Setosa = new IrisData 6 { 7 SepalLength = 5.1f, 8 SepalWidth = 3.5f, 9 PetalLength = 1.4f, 10 PetalWidth = 0.2f 11 }; 12 } 13 }
程序運行結果如下:
PS:我多次運行后發現結果並不一定是同一個,如果你運行的結果與我不同也可能是正確的。另外PredictedClusterId並不是Distances數組的下標。
最后讓我們看一下訓練后得到的預測模型是什么東西吧
IrisClusteringModel.zip解壓后得到DataLoaderModel和TrainingInfo兩個文件夾,其中TrainingInfo中只有一個version.txt保存了一個版本號,而DataLoaderModel中存在數個名為model.key的二進制文件,這就是我們通過ML.NET訓練出來的模型。
這樣你就使用ML.NET完成了一次聚類分析。
******************************
歡迎隨意打賞