共用方式為


教學:使用 ML.NET 對網站留言進行二元分類情緒分析

這個教學會教你如何建立一個 .NET 控制台應用程式,將網站留言中的情感分類並採取適當的處理方式。 二進位情感分類器在 Visual Studio 2022 中使用 C#。

在本教學課程中,您將瞭解如何:

  • 建立主控台應用程式
  • 準備資料
  • 載入資料
  • 建置並訓練模型
  • 評估模型
  • 利用模型來做預測
  • 查看結果

你可以在 dotnet/samples 倉庫找到這個教學的原始碼。

先決條件

建立主控台應用程式

  1. 建立一個名為「SentimentAnalysis」的 C# 主控台應用程式 。 按一下 [下一步] 按鈕。

  2. 選擇 .NET 8 作為框架。 按下 [建立] 按鈕。

  3. 在專案中建立一個名為 Data 的目錄來儲存資料集檔案。

  4. 安裝 Microsoft.ML NuGet 套件

    備註

    除非另有說明,本範例使用上述 NuGet 套件的最新穩定版本。

    在解決方案總管中,右鍵點擊您的專案並選擇 「管理 NuGet 套件」。 選擇「nuget.org」作為套件來源,然後 選擇瀏覽標籤 。搜尋 Microsoft.ML,選擇你想要的套件,然後選擇 安裝。 安裝時,請同意你選擇的套件的授權條款。

準備資料

備註

本教學的資料集來自 Kotzias 等人所發表的《從群組到個別標籤:使用深度特徵》。 KDD 2015,並存放於 UCI 機器學習資料庫 - Dua, D. 和 Karra Taniskidou, E. (2017)。 UCI 機器學習資料庫 [http://archive.ics.uci.edu/ml]。 加利福尼亞州爾灣:加州大學信息與計算機科學學院。

  1. 下載 UCI Sentiment Labeled Sentences 資料集 ZIP 檔,然後解壓縮。

  2. 把檔案複製 yelp_labelled.txt 到你 建立的資料目錄

  3. 在解決方案總管中,右鍵點擊該 yelp_labelled.txt 檔案並選擇 屬性。 在 進階中,將 複製到輸出目錄 的值更改為 若較新則複製

建立類別並定義路徑

  1. 請在using檔案頂端新增以下額外指令:

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using SentimentAnalysis;
    using static Microsoft.ML.DataOperationsCatalog;
    
  2. 在指令下方 using 的行新增以下程式碼,建立一個欄位來存放最近下載的資料集檔案路徑:

    string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "yelp_labelled.txt");
    
  3. 接著,為你的輸入資料和預測建立類別。 新增一個類別到你的專案中:

    • 解決方案總管中,右鍵點擊專案,然後選擇 新增>項目

    • 新增物品 對話框中,選擇 類別 並將 名稱 欄位改為 SentimentData.cs。 然後,選取 新增

  4. SentimentData.cs 檔案會在程式碼編輯器中開啟。 在using頂部加上以下指令:

    using Microsoft.ML.Data;
    
  5. 移除現有的類別定義,並將以下程式碼(包含兩個類別 SentimentDataSentimentPrediction)加入 SentimentData.cs 檔案:

    public class SentimentData
    {
        [LoadColumn(0)]
        public string? SentimentText;
    
        [LoadColumn(1), ColumnName("Label")]
        public bool Sentiment;
    }
    
    public class SentimentPrediction : SentimentData
    {
    
        [ColumnName("PredictedLabel")]
        public bool Prediction { get; set; }
    
        public float Probability { get; set; }
    
        public float Score { get; set; }
    }
    

資料的準備方式

輸入資料集類別 SentimentData,具有 string a 用於用戶留言 (SentimentText) 以及 boolSentiment) 值,代表情感為 1(正面)或 0(負面)。 這兩個欄位都附加了 LoadColumn 屬性,描述每個欄位的資料檔案順序。 此外,該 Sentiment 屬性還有 ColumnName 屬性來指定為欄位 Label 。 以下範例檔案沒有標頭列,看起來如下:

情感文本 Sentiment(唱片公司)
女服務生服務有點慢。 0
餅皮不好吃。 0
哇......我很喜歡這個地方。 1
服務非常迅速。 1

SentimentPrediction 是模型訓練後使用的預測類別。 它繼承自 SentimentData,以便輸入 SentimentText 可以與輸出預測一同顯示。 Prediction布林值是模型在提供新輸入SentimentText時所預測的值。

輸出類別 SentimentPrediction 包含模型計算的另外兩個屬性: Score - 模型計算的原始分數,以及 Probability - 校準為文字具有正面情感的可能性的分數。

在此教學中,最重要的性質為 Prediction

載入資料

ML.NET 中的資料以 IDataView 介面表示。 IDataView 是一種靈活且高效的表格資料(數字與文字)描述方式。 資料可以從文字檔或即時(例如 SQL 資料庫或日誌檔案)載入到 IDataView 物件中。

MLContext 類別是所有 ML.NET 操作的起點。 初始化 mlContext 會建立一個新的 ML.NET 環境,可以在模型建立的工作流程物件間共享。 概念上和 Entity Framework 類似 DBContext

你先準備好應用程式,然後載入資料:

  1. 請將該 Console.WriteLine("Hello World!") 行替換為以下程式碼,以宣告並初始化 mlContext 變數:

    MLContext mlContext = new MLContext();
    
  2. 下一行程式碼加入以下內容:

    TrainTestData splitDataView = LoadData(mlContext);
    
  3. 請在Program.cs檔案的底部使用以下程式碼來建立LoadData()方法:

    TrainTestData LoadData(MLContext mlContext)
    {
    
    }
    

    LoadData() 方法執行以下任務:

    • 載入資料。
    • 將載入的資料集拆分為訓練資料集和測試資料集。
    • 回傳分割訓練與測試資料集。
  4. 將以下程式碼作為方法的第一行 LoadData()

    IDataView dataView = mlContext.Data.LoadFromTextFile<SentimentData>(_dataPath, hasHeader: false);
    

    LoadFromTextFile() 方法定義資料結構並讀取檔案。 它會接收資料路徑變數並回傳一個 IDataView

將資料集拆分進行模型訓練與測試

在準備模型時,你會用部分資料集來訓練,另一部分用來測試模型的準確度。

  1. 要將載入的資料拆分成所需的資料集,請在方法的 LoadData() 下一行加入以下程式碼:

    TrainTestData splitDataView = mlContext.Data.TrainTestSplit(dataView, testFraction: 0.2);
    

    先前的程式碼使用 TrainTestSplit() 方法將載入的資料集拆分為訓練資料集與測試資料集,並在類別中回傳 DataOperationsCatalog.TrainTestData 。 用參數 testFraction指定測試集中的資料百分比。 預設是 10%,在這種情況下你會用 20% 來評估更多資料。

  2. 在方法結束splitDataView時回傳 :LoadData()

    return splitDataView;
    

建置並訓練模型

  1. 在呼叫BuildAndTrainModel該方法的下方,將以下呼叫LoadData加入:

    ITransformer model = BuildAndTrainModel(mlContext, splitDataView.TrainSet);
    

    BuildAndTrainModel() 方法執行以下任務:

    • 擷取並轉換資料。
    • 訓練模型。
    • 根據測試數據預測情緒。
    • 回傳模型。
  2. 在方法下方BuildAndTrainModel(),使用以下程式碼建立該LoadData()方法:

    ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet)
    {
    
    }
    

擷取並轉換資料

  1. 通話 FeaturizeText 作為下一行程式碼:

    var estimator = mlContext.Transforms.Text.FeaturizeText(outputColumnName: "Features", inputColumnName: nameof(SentimentData.SentimentText))
    

    FeaturizeText()前一程式碼中的方法是將文字欄位SentimentText()轉換成機器學習演算法使用的數值鍵型Features欄位,並新增為資料集欄位:

    情感文本 情緒 Features
    女服務生服務有點慢。 0 [0.76, 0.65, 0.44, …]
    餅皮不好吃。 0 [0.98, 0.43, 0.54, …]
    哇......我很喜歡這個地方。 1 [0.35, 0.73, 0.46, …]
    服務非常迅速。 1 [0.39, 0, 0.75, …]

加入學習演算法

這款應用程式使用分類演算法,將項目或資料列分類。 應用程式會將網站留言分為正面或負面,請使用二元分類任務。

將機器學習任務附加到資料轉換定義中,並於下一段程式碼 BuildAndTrainModel()中加入:

.Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features"));

SdcaLogisticRegressionBinaryTrainer 是你的分類訓練演算法。 此內容會附加到estimator,並接受經過特徵化的SentimentTextFeatures)和Label輸入參數,以從歷史數據中學習。

訓練模型

將模型擬合於資料 splitTrainSet ,並透過在方法中加入以下程式碼 BuildAndTrainModel() 返回訓練好的模型:

Console.WriteLine("=============== Create and Train the Model ===============");
var model = estimator.Fit(splitTrainSet);
Console.WriteLine("=============== End of training ===============");
Console.WriteLine();

Fit() 方法透過轉換資料集並套用訓練來訓練你的模型。

回傳訓練用於評估的模型

方法結束 BuildAndTrainModel() 時回傳模型:

return model;

評估模型

模型訓練完成後,利用測試資料驗證模型的效能。

  1. 在 之後,請用以下程式碼建立 Evaluate() 該方法 BuildAndTrainModel()

    void Evaluate(MLContext mlContext, ITransformer model, IDataView splitTestSet)
    {
    
    }
    

    Evaluate() 方法執行以下任務:

    • 載入測試資料集。
    • 建立 BinaryClassification 評估器。
    • 評估模型並建立指標。
    • 顯示指標。
  2. 在方法呼叫下方 BuildAndTrainModel ,使用以下程式碼新增對新方法的呼叫:

    Evaluate(mlContext, model, splitDataView.TestSet);
    
  3. 透過 splitTestSet 加入以下程式碼轉換 Evaluate()資料:

    Console.WriteLine("=============== Evaluating Model accuracy with Test data===============");
    IDataView predictions = model.Transform(splitTestSet);
    

    前述程式碼使用 Transform() 方法來對測試資料集中多個輸入列進行預測。

  4. 在方法中加入以下程式碼 Evaluate() ,評估模型:

    CalibratedBinaryClassificationMetrics metrics = mlContext.BinaryClassification.Evaluate(predictions, "Label");
    

一旦你設定好預測值(predictions), Evaluate() 方法會評估模型,將預測值與測試資料集中的實際 Labels 值比較,並回傳一個 CalibratedBinaryClassificationMetrics 物件,說明模型的表現狀況。

展示模型驗證的指標

請使用以下代碼顯示指標:

Console.WriteLine();
Console.WriteLine("Model quality metrics evaluation");
Console.WriteLine("--------------------------------");
Console.WriteLine($"Accuracy: {metrics.Accuracy:P2}");
Console.WriteLine($"Auc: {metrics.AreaUnderRocCurve:P2}");
Console.WriteLine($"F1Score: {metrics.F1Score:P2}");
Console.WriteLine("=============== End of model evaluation ===============");
  • 指標 Accuracy 獲得模型的準確度,也就是測試集中正確預測的比例。

  • AreaUnderRocCurve 指標顯示模型對正負類別正確分類的信心。 你希望 AreaUnderRocCurve 能盡可能接近 1。

  • 指標F1Score會獲得模型的 F1 分數,這是衡量精確度召回率之間平衡的指標。 你希望 F1Score 能盡可能接近 1。

預測測試資料的結果

  1. 在方法之後UseModelWithSingleItem(),使用以下程式碼建立該Evaluate()方法:

    void UseModelWithSingleItem(MLContext mlContext, ITransformer model)
    {
    
    }
    

    UseModelWithSingleItem() 方法執行以下任務:

    • 建立一則測試資料的評論。
    • 根據測試數據預測情緒。
    • 結合測試數據與預測以供報告。
    • 顯示預測結果。
  2. 使用以下程式碼在方法呼叫下方 Evaluate() 新增對新方法的呼叫:

    UseModelWithSingleItem(mlContext, model);
    
  3. 在方法的第一行 UseModelWithSingleItem() 新增以下程式碼:

    PredictionEngine<SentimentData, SentimentPrediction> predictionFunction = mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(model);
    

    PredictionEngine 是一個便利 API,讓你能對單一資料實例進行預測。 PredictionEngine 不安全執行緒。 它適合使用在單執行緒或原型環境中。 為了在生產環境中提升效能與執行緒安全,建議使用該 PredictionEnginePool 服務,它能在整個應用程式中建立 ObjectPool 多個 PredictionEngine 物件。 請參閱這份關於如何在 ASP.NET Core Web API 中使用PredictionEnginePool的指南。

    備註

    PredictionEnginePool 服務擴充目前處於預覽階段。

  4. UseModelWithSingleItem() 方法中新增註解以測試訓練模型的預測,然後建立 SentimentData 的實例。

    SentimentData sampleStatement = new SentimentData
    {
        SentimentText = "This was a very bad steak"
    };
    
  5. 將測試註解資料傳遞給 PredictionEngine,方法是在 UseModelWithSingleItem() 方法中加入以下程式碼:

    var resultPrediction = predictionFunction.Predict(sampleStatement);
    

    Predict() 函數對單一資料列進行預測。

  6. 使用以下程式碼進行顯示 SentimentText 及相應的情緒預測:

    Console.WriteLine();
    Console.WriteLine("=============== Prediction Test of model with a single sample and test dataset ===============");
    
    Console.WriteLine();
    Console.WriteLine($"Sentiment: {resultPrediction.SentimentText} | Prediction: {(Convert.ToBoolean(resultPrediction.Prediction) ? "Positive" : "Negative")} | Probability: {resultPrediction.Probability} ");
    
    Console.WriteLine("=============== End of Predictions ===============");
    Console.WriteLine();
    

使用模型進行預測

部署與預測批次項目

  1. 在方法之後UseModelWithBatchItems(),使用以下程式碼建立該UseModelWithSingleItem()方法:

    void UseModelWithBatchItems(MLContext mlContext, ITransformer model)
    {
    
    }
    

    UseModelWithBatchItems() 方法執行以下任務:

    • 建立批次測試資料。
    • 根據測試數據預測情緒。
    • 結合測試數據與預測以供報告。
    • 顯示預測結果。
  2. 使用以下程式碼在方法呼叫下方 UseModelWithSingleItem() 新增對新方法的呼叫:

    UseModelWithBatchItems(mlContext, model);
    
  3. 請加入一些註解以測試訓練模型在方法 UseModelWithBatchItems() 中的預測:

    IEnumerable<SentimentData> sentiments = new[]
    {
        new SentimentData
        {
            SentimentText = "This was a horrible meal"
        },
        new SentimentData
        {
            SentimentText = "I love this spaghetti."
        }
    };
    

預測評論情緒

利用模型使用 Transform() 方法預測評論資料的情緒:

IDataView batchComments = mlContext.Data.LoadFromEnumerable(sentiments);

IDataView predictions = model.Transform(batchComments);

// Use model to predict whether comment data is Positive (1) or Negative (0).
IEnumerable<SentimentPrediction> predictedResults = mlContext.Data.CreateEnumerable<SentimentPrediction>(predictions, reuseRowObject: false);

合併並顯示預測結果

請使用以下程式碼建立預測標頭:

Console.WriteLine();

Console.WriteLine("=============== Prediction Test of loaded model with multiple samples ===============");

因為 SentimentPrediction 是從 繼承而SentimentData來,填充Transform()SentimentText了預測欄位的方法。 隨著 ML.NET 流程進行,每個元件會新增欄位,這讓結果顯示變得容易:

foreach (SentimentPrediction prediction  in predictedResults)
{
    Console.WriteLine($"Sentiment: {prediction.SentimentText} | Prediction: {(Convert.ToBoolean(prediction.Prediction) ? "Positive" : "Negative")} | Probability: {prediction.Probability} ");
}
Console.WriteLine("=============== End of predictions ===============");

Results

你的結果應該會與以下類似。 在處理過程中,訊息會被顯示出來。 你可能會看到警告或處理相關訊息。 以下結果已移除這些資料以求清晰。

Model quality metrics evaluation
--------------------------------
Accuracy: 83.96%
Auc: 90.51%
F1Score: 84.04%

=============== End of model evaluation ===============

=============== Prediction Test of model with a single sample and test dataset ===============

Sentiment: This was a very bad steak | Prediction: Negative | Probability: 0.1027377
=============== End of Predictions ===============

=============== Prediction Test of loaded model with a multiple samples ===============

Sentiment: This was a horrible meal | Prediction: Negative | Probability: 0.1369192
Sentiment: I love this spaghetti. | Prediction: Positive | Probability: 0.9960636
=============== End of predictions ===============

=============== End of process ===============
Press any key to continue . . .

祝賀! 你現在已經成功建立了一個機器學習模型,用來分類和預測訊息的情感。

建立成功的模型是一個反覆迭代的過程。 由於教學使用小型資料集以提供快速模型訓練,此模型初期品質較低。 如果你對模型品質不滿意,可以嘗試透過提供較大的訓練資料集,或選擇不同的訓練演算法,並為每個演算法提供不同的 超參數

你可以在 dotnet/samples 倉庫找到這個教學的原始碼。

後續步驟

在本教程中,您將學到如何:

  • 建立主控台應用程式
  • 準備資料
  • 載入資料
  • 建置並訓練模型
  • 評估模型
  • 利用模型來做預測
  • 查看結果

請繼續閱讀下一個教學