見出し画像

ML.netでCSVファイルの異常値を検出する その4

前回の話で終わろうかなと思ったのですが、書き忘れている事がありました。
それは、検出結果の表示です。

こちらのソースコードは、以下で公開されているサンプルソースを元に作成しています。
https://docs.microsoft.com/ja-jp/dotnet/machine-learning/

資料を印刷して読みたい方、PDFファイルのアドレスは以下です。
https://docs.microsoft.com/ja-jp/dotnet/opbuildpdf/machine-learning/toc.pdf?branch=live

#学習 #勉強 #AI #機械学習 #プログラミング #Visual #CSharp #BASIC #ソースコード #Windows #自動判定 #時間 #予測 #異常値


元になっているサンプルコードそのままなのですが、あの出力結果だけを見て、何が異常なのか分かりますか?
異常や変化の兆候を表示し、その結果を導き出した数値だけを出力しています。

異常を検出した事を知らせたとしても、現状では異常になっている月(?)と数値が分かりません。
これでは、プログラムが異常を知らせたとしても、情報を受け取った人間が異常な月(?)を判断できませんし、誤報の可能性があるのか簡単に調べることが出来ません。

元々の数値も表示するサンプルコードを作ってみました。
もし、何かの実用的なプログラムを作っている時ならば、必要になる可能性があるからです。

C#のクラスライブラリー側のソースコードの一部だけを書きますね。
(DetectChangepointにも変化させたところをコピペすれば、良いので省略します)


//DetectSpike() メソッドを作成します。
//・エスティメーターから変換を作成します。
//・売上データ履歴に基づいてスパイクを検出します。
//・結果を表示します。
static void DetectSpike(MLContext mlContext, int docSize, IDataView productSales)
{
//スパイク検出のために、IidSpikeEstimator を使用してモデルをトレーニングします。
var iidSpikeEstimator = mlContext.Transforms.DetectIidSpike(outputColumnName:nameof(ProductSalesPrediction.Prediction),
inputColumnName: nameof(ProductSalesData.numSales),confidence: 95, pvalueHistoryLength: docSize / 4);

//スパイク検出の変換を作成します。
ITransformer iidSpikeTransform = iidSpikeEstimator.Fit(CreateEmptyDataView(mlContext));

//productSales データを DetectSpike() メソッドの次の行に変換します。
//Transform() メソッドを使用して、データセットの複数の入力行の予測を行います。
IDataView transformedData = iidSpikeTransform.Transform(productSales);

//CreateEnumerable() メソッドを使って transformedData を厳密に型指定された IEnumerable に変換します。
var predictions = mlContext.Data.CreateEnumerable<ProductSalesPrediction>(transformedData,reuseRowObject: false);

//表示ヘッダー行を作成します。
Console.WriteLine("Month\tnumSales\tAlert\tScore\tP-Value");

//現在表示している行数を数えます
int LineCount = 0;

//元々の値をListに格納しておく
var ProductSalesDataList = new List<string>();

//元々のデータを復元してみる
//IEnumerableからIEnumerableへ変換します
IEnumerable<ProductSalesData> ProductSalesDataEnumerable = mlContext.Data.CreateEnumerable<ProductSalesData>(productSales, reuseRowObject: true);

//複数のクラスが列になっているので、一個ずつのクラスとして取り出す
foreach (ProductSalesData row in ProductSalesDataEnumerable)
{
//リストに追加していく
string CombineOneLine;
CombineOneLine = row.Month.ToString() + "\t" + row.numSales.ToString() + "\t";

ProductSalesDataList.Add(CombineOneLine);
}

//スパイクの検出結果には、次の情報が表示されます。
//Alert は、特定のデータ ポイントに対するスパイク アラートを示します。
//Score は、データセット内の特定のデータ ポイントに対する ProductSales 値です。
//P - Value "P" は確率を表します。 p 値が 0 に近いほど、データ ポイントが異常になる可能性が高くなります。

//predictions と IEnumerable を反復処理し、結果を表示します。


foreach (var p in predictions)
{

var results = ProductSalesDataList[LineCount] + $"{p.Prediction[0]}\t{p.Prediction[1]:f2}\t{p.Prediction[2]:F2}";
if (p.Prediction[0] == 1)
{
results += " <-- Spike detected";
}
Console.WriteLine(results);

LineCount++;
}
Console.WriteLine("");


}


いいなと思ったら応援しよう!