一、要解決的問題
問題:常常一些單位或組織召開會議時需要錄入會議記錄,我們需要通過機器學習對使用者輸入的文字內容進行自動評判,合格或不合格。(同樣的問題還類似垃圾簡訊檢測、工作日誌質量分析等。)
處理思路:我們人工對現有會議記錄進行評判,標記合格或不合格,通過對這些記錄的學習形成模型,學習演算法仍採用二元分類的快速決策樹演算法,和上一篇文章不同,這次輸入的特徵值不再是浮點數,而是中文文字。這裡就要涉及到文字特徵提取。
為什麼要進行文字特徵提取呢?因為文字是人類的語言,符號文字序列不能直接傳遞給演算法。而計算機程式演算法只接受具有固定長度的數字矩陣特徵向量(float或float陣列),無法理解可變長度的文字文件。
常用的文字特徵提取方法有如下幾種:
以上只是需要了解大致的含義,我們不需要去實現一個文字特徵提取的演算法,只需要使用平臺自帶的方法就可以了。
系統自帶的文字特徵處理的方法,輸入是一個字串,要求將一個語句中的詞語用空格分開,英語的句子中詞彙是天生通過空格分割的,但中文句子不是,所以我們需要首先進行分詞操作,具體流程如下:
二、程式碼
程式碼整體流程和上一篇文章描述的基本一致,為簡便起見,我們省略了模型儲存和讀取的過程。
先看一下資料集:
程式碼如下:
namespace BinaryClassification_TextFeaturize { class Program { static readonly string DataPath = Path.Combine(Environment.CurrentDirectory, "Data", "meeting_data_full.csv"); static void Main(string[] args) { MLContext mlContext = new MLContext(); var fulldata = mlContext.Data.LoadFromTextFile<MeetingInfo>(DataPath, separatorChar: ',', hasHeader: false); var trainTestData = mlContext.Data.TrainTestSplit(fulldata, testFraction: 0.15); var trainData = trainTestData.TrainSet; var testData = trainTestData.TestSet; var trainingPipeline = mlContext.Transforms.CustomMapping<JiebaLambdaInput, JiebaLambdaOutput>(mapAction: JiebaLambda.MyAction, contractName: "JiebaLambda") .Append(mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: "JiebaText")) .Append(mlContext.BinaryClassification.Trainers.FastTree(labelColumnName: "Label", featureColumnName: "Features")); ITransformer trainedModel = trainingPipeline.Fit(trainData); //評估 var predictions = trainedModel.Transform(testData); var metrics = mlContext.BinaryClassification.Evaluate(data: predictions, labelColumnName: "Label"); Console.WriteLine($"Evalution Accuracy: {metrics.Accuracy:P2}"); //建立預測引擎 var predEngine = mlContext.Model.CreatePredictionEngine<MeetingInfo, PredictionResult>(trainedModel); //預測1 MeetingInfo sampleStatement1 = new MeetingInfo { Text = "支委會。" }; var predictionresult1 = predEngine.Predict(sampleStatement1); Console.WriteLine($"{sampleStatement1.Text}:{predictionresult1.PredictedLabel}"); //預測2 MeetingInfo sampleStatement2 = new MeetingInfo { Text = "開展新時代中國特色社會主義思想三十講黨員答題活動。" }; var predictionresult2 = predEngine.Predict(sampleStatement2); Console.WriteLine($"{sampleStatement2.Text}:{predictionresult2.PredictedLabel}"); Console.WriteLine("Press any to exit!"); Console.ReadKey(); } } public class MeetingInfo { [LoadColumn(0)] public bool Label { get; set; } [LoadColumn(1)] public string Text { get; set; } } public class PredictionResult : MeetingInfo { public string JiebaText { get; set; } public float[] Features { get; set; } public bool PredictedLabel; public float Score; public float Probability; } }
三、程式碼分析
和上一篇文章中相似的內容我就不再重複解釋了,重點介紹一下學習管道的建立。
var trainingPipeline = mlContext.Transforms.CustomMapping<JiebaLambdaInput, JiebaLambdaOutput>(mapAction: JiebaLambda.MyAction, contractName: "JiebaLambda") .Append(mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: "JiebaText")) .Append(mlContext.BinaryClassification.Trainers.FastTree(labelColumnName: "Label", featureColumnName: "Features"));
首先,在進行文字特徵轉換之前,我們需要對文字進行分詞操作,您可以對樣本資料進行預處理,形成分詞的結果再進行學習,我們沒有采用這個方法,而是自定義了一個分詞處理的資料處理管道,通過這個管道進行分詞,其定義如下:
namespace BinaryClassification_TextFeaturize { public class JiebaLambdaInput { public string Text { get; set; } } public class JiebaLambdaOutput { public string JiebaText { get; set; } } public class JiebaLambda { public static void MyAction(JiebaLambdaInput input, JiebaLambdaOutput output) { JiebaNet.Segmenter.JiebaSegmenter jiebaSegmenter = new JiebaNet.Segmenter.JiebaSegmenter(); output.JiebaText = string.Join(" ", jiebaSegmenter.Cut(input.Text)); } } }
最後我們新建了兩個物件進行實際預測:
//預測1 MeetingInfo sampleStatement1 = new MeetingInfo { Text = "支委會。" }; var predictionresult1 = predEngine.Predict(sampleStatement1); Console.WriteLine($"{sampleStatement1.Text}:{predictionresult1.PredictedLabel}"); //預測2 MeetingInfo sampleStatement2 = new MeetingInfo { Text = "開展新時代中國特色社會主義思想三十講黨員答題活動。" }; var predictionresult2 = predEngine.Predict(sampleStatement2); Console.WriteLine($"{sampleStatement2.Text}:{predictionresult2.PredictedLabel}");
預測結果如下:
四、除錯
上一篇文章提到,當我們執行Transform方法時,會對所有記錄進行轉換,轉換後的資料集是什麼樣子呢,我們可以寫一個除錯程式看一下。
var predictions = trainedModel.Transform(testData); DebugData(mlContext, predictions); private static void DebugData(MLContext mlContext, IDataView predictions) { var trainDataShow = new List<PredictionResult>(mlContext.Data.CreateEnumerable<PredictionResult>(predictions, false, true)); foreach (var dataline in trainDataShow) { dataline.PrintToConsole(); } } public class PredictionResult { public string JiebaText { get; set; } public float[] Features { get; set; } public bool PredictedLabel; public float Score; public float Probability; public void PrintToConsole() { Console.WriteLine($"JiebaText={JiebaText}"); Console.WriteLine($"PredictedLabel:{PredictedLabel},Score:{Score},Probability:{Probability}"); Console.WriteLine($"TextFeatures Length:{Features.Length}"); if (Features != null) { foreach (var f in Features) { Console.Write($"{f},"); } Console.WriteLine(); } Console.WriteLine(); } }
通過對除錯結果的分析,可以看到整個資料處理管道的工作流程。
五、資源獲取
原始碼下載地址:https://github.com/seabluescn/Study_ML.NET
工程名稱:BinaryClassification_TextFeaturize