チュートリアル: ML.NET の二項分類を使用して Web サイトのコメントのセンチメントを分析する

このチュートリアルでは、Web サイトのコメントからセンチメントを分類して適切なアクションを実行する .NET Core コンソール アプリケーションの作成方法について説明します。 この二項センチメント分類子には、Visual Studio 2022 で C# を使用します。

このチュートリアルでは、次の作業を行う方法について説明します。

  • コンソール アプリケーションを作成する
  • データの準備
  • データを読み込む
  • モデルを構築してトレーニングする
  • モデルを評価する
  • モデルを使用して予測する
  • 結果を見る

このチュートリアルのソース コードは dotnet/samples リポジトリで確認できます。

必須コンポーネント

コンソール アプリケーションを作成する

  1. "SentimentAnalysis" という名前の C# コンソール アプリケーションを作成します。 [次へ] をクリックします。

  2. 使用するフレームワークとして [.NET 6] を選択します。 [作成] ボタンをクリックします。

  3. データ セット ファイルを保存するために、プロジェクトに Data という名前のディレクトリを作成します。

  4. Microsoft.ML NuGet パッケージをインストールします。

    注意

    このサンプルでは、特に明記されていない限り、記載されている最新の安定バージョンの NuGet パッケージを使用します。

    ソリューション エクスプローラーで、プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。 パッケージ ソースとして "nuget.org" を選択してから、 [参照] タブを選択します。Microsoft.ML を検索し、目的のパッケージを選択して、 [インストール] ボタンを選択します。 選択したパッケージのライセンス条項に同意してインストールを続行します。

データを準備する

Note

このチュートリアルのデータセットは、「From Group to Individual Labels using Deep Features」 (Kotzias 他) KDD 2015) のものであり、UCI 機械学習リポジトリ (Dua, D. and Karra Taniskidou, E.(2017)) でホストされています。 UCI 機械学習リポジトリ [http://archive.ics.uci.edu/ml ]。 カリフォルニア州アーバイン: カリフォルニア大学情報コンピュータサイエンス学部。

  1. UCI Sentiment Labeled Sentences データセットの ZIP ファイルをダウンロードし、展開します。

  2. yelp_labelled.txt ファイルを、作成した Data ディレクトリにコピーします。

  3. ソリューション エクスプローラーで、yelp_labeled.txt ファイルを右クリックし、 [プロパティ] を選択します。 [詳細設定] で、 [出力ディレクトリにコピー] の値を [新しい場合はコピーする] に変更します。

クラスを作成してパスを定義する

  1. 次に示す追加の using ステートメントを Program.cs ファイルの先頭に追加します。

    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 ファイルが開きます。 SentimentData.cs の先頭に次の using ステートメントを 追加します。

    using Microsoft.ML.Data;
    
  5. 既存のクラス定義を削除し、SentimentDataSentimentPrediction の 2 つのクラスを含む次のコードを 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 (SentimentText) と、センチメント用の 1 (肯定的) または 0 (否定的) のいずれかの bool (Sentiment) 値があります。 どちらのフィールドにも LoadColumn 属性が添付され、各フィールドのデータ ファイルの順序が記述されています。 さらに、Sentiment プロパティには、それを Label フィールドとして指定する ColumnName 属性があります。 次のファイル例にはヘッダー行がなく、次のような内容です。

SentimentText Sentiment (ラベル)
Waitress was a little slow in service. 0
Crust is not good. 0
Wow...Loved this place. 1
Service was very prompt. 1

SentimentPrediction はモデルのトレーニング後に使用される予測クラスです。 SentimentData から継承されるため、入力 SentimentText を出力予測と共に表示することができます。 Prediction ブール値は、新しい入力 SentimentText が指定されたときにモデルで予測される値です。

出力クラス SentimentPrediction にはモデルによって計算されたその他の 2 つのプロパティが含まれています。1 つはモデルによって計算された生のスコアの Score、もう 1 つは肯定的センチメントを持つテキストの尤度に調整されたスコアの 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. LoadData() メソッドの最後に、splitDataView が返されます。

    return splitDataView;
    

モデルを構築してトレーニングする

  1. LoadDataメソッドへの呼び出しの下に、BuildAndTrainModel メソッドへの次の呼び出しを追加します。

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

    BuildAndTrainModel() メソッドは次のタスクを実行します。

    • データを抽出して変換します。
    • モデルをトレーニングする。
    • テスト データに基づいてセンチメントを予測する。
    • モデルを返します。
  2. 次のコードを使用して、LoadData() メソッドの下に BuildAndTrainModel() メソッドを作成します。

    ITransformer BuildAndTrainModel(MLContext mlContext, IDataView splitTrainSet)
    {
    
    }
    

データを抽出して変換する

  1. 次のコード行として FeaturizeText を呼び出します。

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

    前のコードの FeaturizeText() メソッドでは、テキスト列 (SentimentText) を機械学習アルゴリズムから使用される数値キー型の Features 列に変換し、それを新しいデータセット列として追加します。

    SentimentText Sentiment フィーチャー
    Waitress was a little slow in service. 0 [0.76, 0.65, 0.44, …]
    Crust is not good. 0 [0.98, 0.43, 0.54, …]
    Wow...Loved this place. 1 [0.35, 0.73, 0.46, …]
    Service was very prompt. 1 [0.39, 0, 0.75, …]

学習アルゴリズムを追加する

このアプリでは、データの項目または行を分類する分類アルゴリズムを使用しています。 このアプリでは、Web サイトのコメントが肯定的または否定的に分類されるので、二項分類タスクが使用されます。

データ変換定義に機械学習タスクを追加するには、BuildAndTrainModel() の次のコード行に以下を追加します。

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

SdcaLogisticRegressionBinaryTrainer が分類トレーニング アルゴリズムです。 これは estimator に追加されます。また、特徴付けされた SentimentText (Features) と Label 入力パラメーターを受け取って履歴データから学習します。

モデルをトレーニングする

BuildAndTrainModel() メソッドの次のコード行として以下を追加して、モデルを splitTrainSet データに適合させ、トレーニング済みモデルを返します。

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

Fit() メソッドでは、データセットを変換して、トレーニングを適用することにより、モデルがトレーニングされます。

評価に使用する、トレーニング済みのモデルを返す

BuildAndTrainModel() メソッドの終了時にモデルを返します。

return model;

モデルを評価する

モデルのトレーニングが終わったら、テスト データを使用してモデルのパフォーマンスを検証します。

  1. BuildAndTrainModel() の直後に、次のコードを使用して Evaluate() メソッドを作成します。

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

    Evaluate() メソッドは次のタスクを実行します。

    • テスト データ セットを読み込む。
    • BinaryClassification エバリュエーターを作成します。
    • モデルを評価し、メトリックを作成する。
    • メトリックを表示する。
  2. 次のコードを使用して、BuildAndTrainModel メソッド呼び出しの下に新しいメソッドへの呼び出しを追加します。

    Evaluate(mlContext, model, splitDataView.TestSet);
    
  3. 次のコードを Evaluate() に追加して、splitTestSet データを変換します。

    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. Evaluate() メソッドの直後に、次のコードを使用して UseModelWithSingleItem() メソッドを作成します。

    void UseModelWithSingleItem(MLContext mlContext, ITransformer model)
    {
    
    }
    

    UseModelWithSingleItem() メソッドは次のタスクを実行します。

    • テスト データの 1 つのコメントを作成する。
    • テスト データに基づいてセンチメントを予測する。
    • テスト データと予測をレポート用に結合する。
    • 予測された結果を表示する。
  2. 次のコードを使用して、Evaluate() メソッド呼び出しのすぐ下に新しいメソッドへの呼び出しを追加します。

    UseModelWithSingleItem(mlContext, model);
    
  3. 次のコードを追加して、UseModelWithSingleItem() メソッドの 1 行目として作成します。

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

    PredictionEngine は、データの 1 つのインスタンスに対して予測を実行できる便利な API です。 PredictionEngine はスレッド セーフではありません。 シングル スレッド環境またはプロトタイプ環境で使用できます。 運用環境でパフォーマンスとスレッド セーフを向上させるには、PredictionEnginePool サービスを使用します。これにより、アプリケーション全体で使用するできる PredictionEngine オブジェクトの ObjectPool が作成されます。 ASP.NET Core Web API で PredictionEnginePool を使用する方法については、こちらのガイドを参照してください。

    注意

    PredictionEnginePool サービスの拡張機能は、現在プレビュー段階です。

  4. コメントを追加して、UseModelWithSingleItem() メソッドでトレーニングされたモデルの予測をテストします。これには SentimentData のインスタンスを作成します。

    SentimentData sampleStatement = new SentimentData
    {
        SentimentText = "This was a very bad steak"
    };
    
  5. UseModelWithSingleItem() メソッドの次のコード行として以下を追加して、テスト コメント データを PredictionEngine に渡します。

    var resultPrediction = predictionFunction.Predict(sampleStatement);
    

    Predict() 関数では、データの 1 つの行に対して予測を行います。

  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. UseModelWithSingleItem() メソッドの直後に、次のコードを使用して UseModelWithBatchItems() メソッドを作成します。

    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 ===============");

SentimentPredictionSentimentData から継承されているため、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 ===============");

結果

結果は以下のようになるはずです。 処理中にメッセージが表示されます。 警告または処理メッセージが表示されることがありますが、 わかりやすくするために、それらは次の結果から削除してあります。

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 リポジトリで確認できます。

次の手順

このチュートリアルでは、次の作業を行う方法を学びました。

  • コンソール アプリケーションを作成する
  • データの準備
  • データを読み込む
  • モデルを構築してトレーニングする
  • モデルを評価する
  • モデルを使用して予測する
  • 結果を見る

さらに詳しく学習するには、次のチュートリアルに進んでください。