モデルを構築するためのデータを準備する
ML.NET を使用して、追加の処理またはモデルの構築のためにデータを準備する方法について説明します。
多くの場合、データは汚れていて、まばらです。 ML.NET 機械学習アルゴリズムでは、入力または特徴が 1 つの数値ベクトルに含まれると想定されます。 同様に、特にカテゴリ データの場合は、予測する値 (ラベル) をエンコードする必要があります。 そのため、データ準備の目的の 1 つは、ML.NET アルゴリズムで想定される形式でデータを取得することです。
データをトレーニング セット & テスト セットに分割する
次のセクションでは、オーバーフィットとアンダーフィットと呼ばれるモデルをトレーニングするときの一般的な問題について説明します。 保留セットを使用してデータを分割し、モデルを検証すると、これらの問題を特定して軽減するのに役立ちます。
オーバーフィット & アンダーフィット
オーバーフィットとアンダーフィットは、モデルのトレーニング時に発生する最も一般的な 2 つの問題です。 アンダーフィットとは、選択したトレーナーがトレーニング データセットに適合するのに十分な能力を持たないことを意味し、通常はトレーニング中に高い損失が発生し、テスト データセットのスコア/メトリックが低くなります。 これを解決するには、より強力なモデルを選択するか、より多くの特徴エンジニアリングを実行する必要があります。 オーバーフィットは逆であり、モデルがトレーニング データを学習しすぎる場合に発生します。 通常、これはトレーニング中に低損失メトリックになりますが、テスト データセットでは高損失になります。
これらの概念の良い例えは、試験の勉強です。 事前に質問と回答を知っていたとします。 勉強した後、あなたはテストを受け、完璧なスコアを取得します。 素晴らしいニュース! ただし、質問が並べ替えられ、少し異なる文言で再び試験を受けると、スコアが低くなります。 つまり、答えを暗記し、実際にテスト対象の概念を学習しなかったことを示唆しています。 これはオーバーフィットの例です。 アンダーフィッティングとは、与えられた教材が試験の評価内容を正確に反映していない状況を指します。それは過学習(オーバーフィッティング)とは逆の現象です。 その結果、正しく回答するのに十分な知識がないため、答えを推測することに頼ります。
データの分割
次の入力データを取得し、data
と呼ばれる IDataView
に読み込みます。
var homeDataList = new HomeData[]
{
new()
{
NumberOfBedrooms = 1f,
Price = 100_000f
},
new()
{
NumberOfBedrooms = 2f,
Price = 300_000f
},
new()
{
NumberOfBedrooms = 6f,
Price = 600_000f
},
new()
{
NumberOfBedrooms = 3f,
Price = 300_000f
},
new()
{
NumberOfBedrooms = 2f,
Price = 200_000f
}
};
データをトレーニング/テスト セットに分割するには、TrainTestSplit(IDataView, Double, String, Nullable<Int32>) メソッドを使用します。
// Apply filter
TrainTestData dataSplit = mlContext.Data.TrainTestSplit(data, testFraction: 0.2);
testFraction
パラメーターは、テストのためにデータセットの 0.2 または 20% を受け取るために使用されます。 残りの 80% はトレーニングに使用されます。
結果は、TrainSet と TestSet を介してアクセスできる 2 つの IDataView を持つ DataOperationsCatalog.TrainTestData です。
データのフィルター処理
場合によっては、データセット内のすべてのデータが分析に関連しているわけではありません。 無関係なデータを削除する方法は、フィルター処理です。 DataOperationsCatalog
には、すべてのデータを含む IDataView
を受け取り、関心のあるデータ ポイントのみを含む IDataView を返す一連のフィルター操作が含まれています。 フィルター操作は TransformsCatalog
のような IEstimator
または ITransformer
ではないため、EstimatorChain
または TransformerChain
データ準備パイプラインの一部として含めることはできません。
次の入力データを取得し、data
と呼ばれる IDataView
に読み込みます。
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms=1f,
Price=100000f
},
new ()
{
NumberOfBedrooms=2f,
Price=300000f
},
new ()
{
NumberOfBedrooms=6f,
Price=600000f
}
};
列の値に基づいてデータをフィルター処理するには、FilterRowsByColumn
メソッドを使用します。
// Apply filter
IDataView filteredData = mlContext.Data.FilterRowsByColumn(data, "Price", lowerBound: 200000, upperBound: 1000000);
上記のサンプルでは、200000 から 1000000 の間の価格でデータセット内の行を取得します。 このフィルターを適用した結果、データ内の最後の 2 行のみが返され、最初の行は除外されます。これは、価格が 100000 であり、指定された範囲の間ではないためです。
欠損値を置き換える
欠損値は、データセットで一般的に発生します。 欠損値を処理する方法の 1 つは、データ内の平均値などの意味のある値がある場合は、指定された型の既定値に置き換えます。
次の入力データを取得し、data
と呼ばれる IDataView
に読み込みます。
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms=1f,
Price=100000f
},
new ()
{
NumberOfBedrooms=2f,
Price=300000f
},
new ()
{
NumberOfBedrooms=6f,
Price=float.NaN
}
};
リストの最後の要素に Price
の欠損値があることに注意してください。 Price
列の欠損値を置き換えるには、ReplaceMissingValues
メソッドを使用してその欠損値を入力します。
重要
ReplaceMissingValue
は数値データでのみ機能します。
// Define replacement estimator
var replacementEstimator = mlContext.Transforms.ReplaceMissingValues("Price", replacementMode: MissingValueReplacingEstimator.ReplacementMode.Mean);
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer replacementTransformer = replacementEstimator.Fit(data);
// Transform data
IDataView transformedData = replacementTransformer.Transform(data);
ML.NET は、さまざまな 置換モードをサポートしています。 上記のサンプルでは、Mean
置換モードを使用します。このモードでは、欠損値にその列の平均値が入力されます。 置換の結果は、データ内の最後の要素の Price
プロパティに 200,000 が入力されます。これは平均 100,000 と 300,000 であるためです。
ノーマライザーを使用する
正規化 は、特徴を同じ範囲 (通常は 0 から 1) にスケーリングするために使用されるデータ前処理手法であり、機械学習アルゴリズムによってより正確に処理できます。 たとえば、年齢と収入の範囲は、一般的に年齢が 0 から 100 の範囲にあり、収入は一般的にゼロから数千の範囲で大きく異なります。 正規化変換の詳細な一覧と説明については、「変換」ページ を参照してください。
最小最大正規化
次の入力データを取得し、data
と呼ばれる IDataView
に読み込みます。
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms = 2f,
Price = 200000f
},
new ()
{
NumberOfBedrooms = 1f,
Price = 100000f
}
};
正規化は、単一の数値とベクトルを持つ列に適用できます。 NormalizeMinMax
メソッドを使用して最小最大正規化を使用して、Price
列のデータを正規化します。
// Define min-max estimator
var minMaxEstimator = mlContext.Transforms.NormalizeMinMax("Price");
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer minMaxTransformer = minMaxEstimator.Fit(data);
// Transform data
IDataView transformedData = minMaxTransformer.Transform(data);
[200000,100000]
元の価格値は、0 から 1 の範囲の出力値を生成する MinMax
正規化式を使用して、[ 1, 0.5 ]
に変換されます。
ビニング
ビン分割 は、連続値を離散的な入力表現に変換します。 たとえば、特徴の 1 つが年齢であるとします。 実際の年齢の値を使用する代わりに、ビニングによってその値の範囲が作成されます。 0 から 18 を 1 つのビン、19 から 35 をもう 1 つのビン、のように指定できます。
次の入力データを取得し、data
と呼ばれる IDataView
に読み込みます。
HomeData[] homeDataList = new HomeData[]
{
new ()
{
NumberOfBedrooms=1f,
Price=100000f
},
new ()
{
NumberOfBedrooms=2f,
Price=300000f
},
new ()
{
NumberOfBedrooms=6f,
Price=600000f
}
};
NormalizeBinning
メソッドを使用して、データを bin に正規化します。 maximumBinCount
パラメーターを使用すると、データを分類するために必要なビンの数を指定できます。 この例では、データは 2 つのビンに格納されます。
// Define binning estimator
var binningEstimator = mlContext.Transforms.NormalizeBinning("Price", maximumBinCount: 2);
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
var binningTransformer = binningEstimator.Fit(data);
// Transform Data
IDataView transformedData = binningTransformer.Transform(data);
ビン分割の結果、[0,200000,Infinity]
のビン境界が作成されます。 したがって、最初の観測値は 0 から 200000 の間であり、他の観測値は 200000 を超えるが無限大より小さいため、結果のビンは [0,1,1]
されます。
カテゴリ データを操作する
最も一般的な種類のデータの 1 つはカテゴリ データです。 カテゴリ データには、有限のカテゴリがあります。 たとえば、米国の州や、一連の画像に含まれる動物の種類のリストなどです。 カテゴリ データが特徴かラベルかに関係なく、機械学習モデルの生成に使用できるように、それらのデータを数値にマップする必要があります。 解決する問題に応じて、ML.NET のカテゴリ データを操作する方法はいくつかあります。
キー値のマッピング
ML.NET では、キーはカテゴリを表す整数値です。 キー値マッピングは、トレーニングのために文字列ラベルを一意の整数値にマップし、モデルを使用して予測を行うときに文字列値に戻すために最もよく使用されます。
キー値マッピングを実行するのに使用される変換は、MapValueToKey と MapKeyToValueです。
MapValueToKey
モデルにマッピングのディクショナリが追加されるため、MapKeyToValue
は予測を行うときに逆変換を実行できます。
1 つのホット エンコード
1 つのホット エンコードは、有限の値のセットを受け取り、バイナリ表現が文字列内の一意の位置に 1 つの 1
値を持つ整数にマップします。 カテゴリ データの暗黙的な順序付けがない場合は、ホット エンコードを 1 つ選択することをお勧めします。 次の表に、郵便番号を生の値として使用する例を示します。
生の値 | 1 つのホット エンコード値 |
---|---|
98052 | 00...01 |
98100 | 00...10 |
... | ... |
98109 | 10...00 |
カテゴリーデータをワンホットエンコーディングされた数値に変換するための変換は OneHotEncoding
です。
ハッシュ
ハッシュは、カテゴリ データを数値に変換するもう 1 つの方法です。 ハッシュ関数は、任意のサイズ (テキストの文字列など) のデータを、固定範囲の数値にマップします。 ハッシュは、特徴をベクター化する高速かつスペース効率の高い方法です。 機械学習でのハッシュの注目すべき例の 1 つは、既知の単語の辞書を維持する代わりに、電子メール内のすべての単語がハッシュされ、大きな特徴ベクトルに追加される電子メール スパム フィルターです。 この方法でハッシュを使用すると、辞書に含まれていない単語を使用することで、悪意のあるスパム フィルタリングの回避の問題を回避できます。
ML.NET では、ハッシュ 変換を提供して、テキスト、日付、数値データに対してハッシュを実行します。 値キーマッピングと同様に、ハッシュ変換の出力はキー型です。
テキスト データを操作する
カテゴリ データと同様に、テキスト データを機械学習モデルの構築に使用する前に、数値特徴に変換する必要があります。 テキスト変換の詳細な一覧と説明については、「変換」ページ を参照してください。
IDataView
に読み込まれた以下のデータに似たデータを使用します。
ReviewData[] reviews = new ReviewData[]
{
new ReviewData
{
Description="This is a good product",
Rating=4.7f
},
new ReviewData
{
Description="This is a bad product",
Rating=2.3f
}
};
ML.NET は、テキストの文字列値を受け取り、一連の個々の変換を適用してテキストから特徴のセットを作成する FeaturizeText
変換を提供します。
// Define text transform estimator
var textEstimator = mlContext.Transforms.Text.FeaturizeText("Description");
// Fit data to estimator
// Fitting generates a transformer that applies the operations of defined by estimator
ITransformer textTransformer = textEstimator.Fit(data);
// Transform data
IDataView transformedData = textTransformer.Transform(data);
結果の変換により、Description
列のテキスト値が、次の出力のような数値ベクトルに変換されます。
[ 0.2041241, 0.2041241, 0.2041241, 0.4082483, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0.2041241, 0, 0, 0, 0, 0.4472136, 0.4472136, 0.4472136, 0.4472136, 0.4472136, 0 ]
FeaturizeText
を構成する変換を個別に適用して、フィーチャ生成をより細かく制御することもできます。
// Define text transform estimator
var textEstimator = mlContext.Transforms.Text.NormalizeText("Description")
.Append(mlContext.Transforms.Text.TokenizeIntoWords("Description"))
.Append(mlContext.Transforms.Text.RemoveDefaultStopWords("Description"))
.Append(mlContext.Transforms.Conversion.MapValueToKey("Description"))
.Append(mlContext.Transforms.Text.ProduceNgrams("Description"))
.Append(mlContext.Transforms.NormalizeLpNorm("Description"));
textEstimator
には、FeaturizeText
メソッドによって実行される操作のサブセットが含まれています。 より複雑なパイプラインの利点は、データに適用される変換の制御と可視性です。
最初のエントリを例として使用して、textEstimator
によって定義された変換手順によって生成される結果の詳細な説明を次に示します。
元のテキスト:これは良い製品 です
変化させる | 説明 | 結果 |
---|---|---|
1. NormalizeText | 既定では、すべての文字を小文字に変換します | これは良い製品です |
2. TokenizeWords | 文字列を個々の単語に分割します | これは良い製品です。 |
3. デフォルトのストップワードを削除 (RemoveDefaultStopWords) | is や a のようなストップワードを削除します。 | ["良い製品"] |
4. MapValueToKey | 入力データに基づいて値をキー (カテゴリ) にマップします | [1,2] |
5. ProduceNGrams | 連続する単語のシーケンスにテキストを変換します。 | [1,1,1,0,0] |
6. NormalizeLpNorm | 入力を lp-ノルムで尺度化する | [ 0.577350529, 0.577350529, 0.577350529, 0, 0 ] |
.NET