このチュートリアルでは、ML.NET を使用して 回帰モデル を構築し、価格 (具体的にはニューヨーク市のタクシー料金) を予測する方法について説明します。
このチュートリアルでは、以下の内容を学習します。
- データを準備して理解する
- データを読み込んで変換する
- 学習アルゴリズムを選択する
- モデルをトレーニングする
- モデルを評価する
- 予測にモデルを使用する
[前提条件]
- .NET デスクトップ開発ワークロードがインストールされている Visual Studio 2022 以降。
コンソール アプリケーションの作成
"TaxiFarePrediction" という名前の C# コンソール アプリケーション を作成します。
使用するフレームワークとして .NET 8 を選択します。 [作成] ボタンをクリックします。
Data という名前のディレクトリをプロジェクトに作成して、データ セットとモデル ファイルを格納します。
Microsoft.ML と Microsoft.ML.FastTree NuGet パッケージをインストールします。
注
このサンプルでは、特に明記されていない限り、記載されている最新の安定バージョンの NuGet パッケージを使用します。
ソリューション エクスプローラーで、プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。 パッケージ ソースとして [nuget.org] を選択 し、[参照 ] タブを選択し、 Microsoft.ML を検索して、一覧からパッケージを選択して、[インストール] を選択 します。 [変更のプレビュー] ダイアログで [OK] ボタンを選択し、表示されているパッケージのライセンス条項に同意する場合は、[ライセンスの同意] ダイアログで [同意する] ボタンを選択します。 Microsoft.ML.FastTree NuGet パッケージでも同じ操作を行います。
データを準備して理解する
taxi-fare-train.csv と taxi-fare-test.csv データ セットをダウンロードし、前の手順で作成したデータ フォルダーに保存します。 これらのデータセットを使用して機械学習モデルをトレーニングし、モデルの精度を評価します。 これらのデータ セットは、NYC TLC タクシー乗車データ セットから作成されたものです。
ソリューション エクスプローラーで、各 *.csv ファイルを右クリックし、[プロパティ] を選択します。 [ 詳細設定] で、[ 出力ディレクトリにコピー ] の値を [新しい場合はコピー] に変更します。
taxi-fare-train.csv データ セットを開き、最初の行の列ヘッダーを調べます。 各列を見てみましょう。 データを理解し、 特徴 である列と ラベルを決定します。
labelは、予測する列です。 識別されたFeaturesLabelを予測するためにモデルに与える入力です。
指定されたデータ セットには、次の列が含まれています。
- vendor_id: タクシー ベンダーの ID が機能です。
- rate_code: タクシー乗車の料金の種類が特徴です。
- passenger_count: 乗車中の乗客数が特徴です。
- trip_time_in_secs: 旅行にかかった時間。 旅行が完了する前に、旅行の料金を予測する必要があります。 その時点では、旅行にかかる時間がわかりません。 したがって、乗車時間は特徴ではないため、この列をモデルから除外します。
- trip_distance: 乗車の距離は特徴です。
- payment_type: 支払い方法 (現金またはクレジット カード) が機能です。
- fare_amount: 支払われたタクシー料金の合計はラベルです。
データ クラスを作成する
入力データと予測のクラスを作成します。
ソリューション エクスプローラーでプロジェクトを右クリックし、[追加]、[>を選択します。
[ 新しい項目の追加 ] ダイアログ ボックスで、[ クラス ] を選択し、[ 名前 ] フィールドを TaxiTrip.csに変更します。 その後、 [追加] を選択します。
新しいファイルに次の
usingディレクティブを追加します。using Microsoft.ML.Data;
既存のクラス定義を削除し、2 つのクラス TaxiTrip と TaxiTripFarePredictionを含む次のコードを TaxiTrip.cs ファイルに追加します。
public class TaxiTrip
{
[LoadColumn(0)]
public string? VendorId;
[LoadColumn(1)]
public string? RateCode;
[LoadColumn(2)]
public float PassengerCount;
[LoadColumn(3)]
public float TripTime;
[LoadColumn(4)]
public float TripDistance;
[LoadColumn(5)]
public string? PaymentType;
[LoadColumn(6)]
public float FareAmount;
}
public class TaxiTripFarePrediction
{
[ColumnName("Score")]
public float FareAmount;
}
TaxiTrip は入力データ クラスであり、各データ セット列の定義を持ちます。
LoadColumnAttribute属性を使用して、データ セット内のソース列のインデックスを指定します。
TaxiTripFarePrediction クラスは、予測された結果を表します。
FareAmount
Score属性が適用された単一の float フィールド (ColumnNameAttribute) があります。 回帰タスクの場合、[ スコア ] 列には予測ラベル値が含まれます。
注
入力データ クラスと予測データ クラスの浮動小数点値を表すには、 float 型を使用します。
データパスとモデルパスを定義する
Program.cs ファイルの先頭に、次の追加のusing ディレクティブを追加します。
using Microsoft.ML;
using TaxiFarePrediction;
データ セットを含むファイルへのパスとモデルを保存するファイルを保持するには、次の 3 つのフィールドを作成する必要があります。
-
_trainDataPathには、モデルのトレーニングに使用されるデータ セットを含むファイルへのパスが含まれています。 -
_testDataPathには、モデルの評価に使用されるデータ セットを含むファイルへのパスが含まれています。 -
_modelPathには、トレーニング済みのモデルが格納されているファイルへのパスが含まれています。
usings セクションのすぐ下に次のコードを追加して、これらのパスと _textLoader 変数を指定します。
string _trainDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "taxi-fare-train.csv");
string _testDataPath = Path.Combine(Environment.CurrentDirectory, "Data", "taxi-fare-test.csv");
string _modelPath = Path.Combine(Environment.CurrentDirectory, "Data", "Model.zip");
すべての ML.NET 操作は MLContext クラスで開始されます。
mlContext初期化すると、モデル作成ワークフロー オブジェクト間で共有できる新しい ML.NET 環境が作成されます。 概念的には、Entity Framework の DBContext に似ています。
変数の初期化
Console.WriteLine("Hello World!")行を次のコードに置き換えて、mlContext変数を宣言して初期化します。
MLContext mlContext = new MLContext(seed: 0);
Train メソッドを呼び出す次のコード行として、次のコードを追加します。
var model = Train(mlContext, _trainDataPath);
Train() メソッドは、次のタスクを実行します。
- データを読み込みます。
- データを抽出して変換します。
- モデルをトレーニングします。
- モデルを返します。
Trainメソッドは、モデルをトレーニングします。 次のコードを使用して、そのメソッドを下に作成します。
ITransformer Train(MLContext mlContext, string dataPath)
{
}
データの読み込みと変換
ML.NET は、数値またはテキストの表形式データを記述する柔軟で効率的な方法として IDataView インターフェイス を使用します。
IDataView では、テキスト ファイルまたはリアルタイム (SQL データベースやログ ファイルなど) を読み込むことができます。
Train() メソッドの最初の行として、次のコードを追加します。
IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(dataPath, hasHeader: true, separatorChar: ',');
タクシー乗車料金を予測する場合、 FareAmount 列は予測する Label (モデルの出力) です。
CopyColumnsEstimator変換クラスを使用してFareAmountをコピーし、次のコードを追加します。
var pipeline = mlContext.Transforms.CopyColumns(outputColumnName: "Label", inputColumnName:"FareAmount")
モデルをトレーニングするアルゴリズムには 数値 特徴が必要であるため、カテゴリ データ (VendorId、 RateCode、 PaymentType) の値を数値 (VendorIdEncoded、 RateCodeEncoded、 PaymentTypeEncoded) に変換する必要があります。 そのためには、各列の異なる値に異なる数値キー値を割り当てる OneHotEncodingTransformer 変換クラスを使用し、次のコードを追加します。
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "VendorIdEncoded", inputColumnName:"VendorId"))
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "RateCodeEncoded", inputColumnName: "RateCode"))
.Append(mlContext.Transforms.Categorical.OneHotEncoding(outputColumnName: "PaymentTypeEncoded", inputColumnName: "PaymentType"))
データ準備の最後の手順では、変換クラスを使用して、すべてのフィーチャ列を mlContext.Transforms.Concatenate 列に結合します。 既定では、学習アルゴリズムは [特徴] 列の特徴のみを処理します。 次のコードを追加します。
.Append(mlContext.Transforms.Concatenate("Features", "VendorIdEncoded", "RateCodeEncoded", "PassengerCount", "TripDistance", "PaymentTypeEncoded"))
学習アルゴリズムを選択する
この問題は、ニューヨーク市のタクシー乗車料金を予測することです。 一見すると、単に移動距離に依存しているように見えるかもしれません。 ただし、ニューヨークのタクシー会社は、追加の乗客や現金ではなくクレジットカードでの支払いなど、その他の要因に応じて料金が異なります。 データセット内の他の要因に基づいて、実際の値である価格値を予測する必要があります。 これを行うには、 回帰 機械学習タスクを選択します。
データ変換定義に FastTreeRegressionTrainer 機械学習タスクを追加するには、次のコード行を Train()に追加します。
.Append(mlContext.Regression.Trainers.FastTree());
モデルをトレーニングする
モデルをトレーニング dataview に適合させ、 Train() メソッドに次のコード行を追加して、トレーニング済みモデルを返します。
var model = pipeline.Fit(dataView);
Fit() メソッドは、データセットを変換してトレーニングを適用することで、モデルをトレーニングします。
Train() メソッドで次のコード行を使用して、トレーニング済みのモデルを返します。
return model;
モデルを評価する
次に、テスト データを使用してモデルのパフォーマンスを評価し、品質保証と検証を行います。
Evaluate()の直後に、次のコードを使用して、Train() メソッドを作成します。
void Evaluate(MLContext mlContext, ITransformer model)
{
}
Evaluate メソッドは、次のタスクを実行します。
- テスト データセットを読み込みます。
- 回帰エバリュエーターを作成します。
- モデルを評価し、メトリックを作成します。
- メトリックを表示します。
次のコードを使用して、 Train メソッド呼び出しのすぐ下に新しいメソッドの呼び出しを追加します。
Evaluate(mlContext, model);
LoadFromTextFile() メソッドを使用してテスト データセットを読み込みます。 このデータセットを品質チェックとして使用してモデルを評価するには、 Evaluate メソッドに次のコードを追加します。
IDataView dataView = mlContext.Data.LoadFromTextFile<TaxiTrip>(_testDataPath, hasHeader: true, separatorChar: ',');
次に、次のコードをTestに追加して、Evaluate() データを変換します。
var predictions = model.Transform(dataView);
Transform() メソッドは、テスト データセットの入力行の予測を行います。
RegressionContext.Evaluateメソッドは、指定したデータセットを使用してPredictionModelの品質メトリックを計算します。 回帰エバリュエーターによって計算された全体的なメトリックを含む RegressionMetrics オブジェクトを返します。
これらを表示してモデルの品質を判断するには、まずメトリックを取得する必要があります。
Evaluate メソッドの次の行として、次のコードを追加します。
var metrics = mlContext.Regression.Evaluate(predictions, "Label", "Score");
予測を設定すると、 Evaluate() メソッドによってモデルが評価されます。このメソッドは、予測値とテスト データセット内の実際の Labels を比較し、モデルのパフォーマンスに関するメトリックを返します。
次のコードを追加してモデルを評価し、評価メトリックを生成します。
Console.WriteLine();
Console.WriteLine($"*************************************************");
Console.WriteLine($"* Model quality metrics evaluation ");
Console.WriteLine($"*------------------------------------------------");
RSquared は、回帰モデルのもう 1 つの評価メトリックです。 RSquared は 0 ~ 1 の値を受け取ります。 値が 1 に近いほど、モデルの方が優れています。
Evaluate メソッドに次のコードを追加して、RSquared 値を表示します。
Console.WriteLine($"* RSquared Score: {metrics.RSquared:0.##}");
RMS は、回帰モデルの評価メトリックの 1 つです。 低いほど、モデルの方が優れています。 RMS 値を表示するには、 Evaluate メソッドに次のコードを追加します。
Console.WriteLine($"* Root Mean Squared Error: {metrics.RootMeanSquaredError:0.##}");
予測にモデルを使用する
次のコードを使用して、TestSinglePrediction メソッドの直後に Evaluate メソッドを作成します。
void TestSinglePrediction(MLContext mlContext, ITransformer model)
{
}
TestSinglePrediction メソッドは、次のタスクを実行します。
- テスト データの 1 つのコメントを作成します。
- テスト データに基づいて料金の金額を予測します。
- レポート用のテスト データと予測を組み合わせます。
- 予測された結果を表示します。
次のコードを使用して、 Evaluate メソッド呼び出しのすぐ下に新しいメソッドの呼び出しを追加します。
TestSinglePrediction(mlContext, model);
次のコードをPredictionEngineに追加して、TestSinglePrediction()を使用して料金を予測します。
var predictionFunction = mlContext.Model.CreatePredictionEngine<TaxiTrip, TaxiTripFarePrediction>(model);
PredictionEngine は便利な API であり、データの単一インスタンスに対して予測を実行できます。
PredictionEngine はスレッド セーフではありません。 シングルスレッド環境またはプロトタイプ環境で使用することは許容されます。 運用環境でのパフォーマンスとスレッド セーフを向上させるには、PredictionEnginePool サービスを使用します。このサービスにより、アプリケーション全体で使用するObjectPool オブジェクトのPredictionEngineが作成されます。
ASP.NET Core Web API でPredictionEnginePoolを使用する方法については、このガイドを参照してください。
注
PredictionEnginePool サービス拡張機能は現在プレビュー段階です。
このチュートリアルでは、このクラス内で 1 回のテスト旅行を使用します。 後で他のシナリオを追加して、モデルを試すことができます。
TestSinglePrediction()のインスタンスを作成して、トレーニング済みのモデルのコスト予測を TaxiTrip メソッドでテストするトリップを追加します。
var taxiTripSample = new TaxiTrip()
{
VendorId = "VTS",
RateCode = "1",
PassengerCount = 1,
TripTime = 1140,
TripDistance = 3.75f,
PaymentType = "CRD",
FareAmount = 0 // To predict. Actual/Observed = 15.5
};
次に、タクシー乗車データの 1 つのインスタンスに基づいて料金を予測し、PredictionEngine メソッドの次のコード行として次の行を追加してTestSinglePrediction()に渡します。
var prediction = predictionFunction.Predict(taxiTripSample);
Predict() 関数は、データの 1 つのインスタンスに対して予測を行います。
指定した乗車の予測料金を表示するには、 TestSinglePrediction メソッドに次のコードを追加します。
Console.WriteLine($"**********************************************************************");
Console.WriteLine($"Predicted fare: {prediction.FareAmount:0.####}, actual fare: 15.5");
Console.WriteLine($"**********************************************************************");
プログラムを実行して、テスト ケースの予測タクシー料金を確認します。
おめでとうございます! これで、タクシー乗車料金を予測し、その精度を評価し、それを使用して予測を行う機械学習モデルが正常に構築されました。 このチュートリアルのソース コードは 、dotnet/samples GitHub リポジトリにあります。
次のステップ
このチュートリアルでは、次の方法を学習しました。
- データを準備して理解する
- 学習パイプラインを作成する
- データを読み込んで変換する
- 学習アルゴリズムを選択する
- モデルをトレーニングする
- モデルを評価する
- 予測にモデルを使用する
詳細については、次のチュートリアルに進んでください。
.NET