瞭解如何建置時間序列數據的異常偵測應用程式。 本教學課程會在 Visual Studio 2019 中使用 C# 建立 .NET 控制台應用程式。
在本教學課程中,您將瞭解如何:
- 載入數據
- 偵測時間序列的周期
- 偵測時間序列中的定期異常
您可以在 dotnet/samples 存放庫找到本教學課程的原始程式碼。
先決條件
安裝 Visual Studio 2022 或更新版本 並配置 .NET Desktop Development 工作負載。
建立主控台應用程式
建立名為 「PhoneCallsAnomalyDetection」 的 C# 控制台應用程式。 選取 下一步。
選擇 .NET 8 作為目標框架。 選取 ,創建。
在專案中建立名為 Data 的目錄,以儲存數據集檔案。
安裝 Microsoft.ML NuGet 套件 版本 1.5.2:
- 在 [方案總管] 中,以滑鼠右鍵按下您的專案,然後選取 [管理 NuGet 套件]。
- 選擇 [nuget.org] 作為套件來源。
- 選取 [流覽] 索引標籤。
- 搜尋 Microsoft.ML。
- 從套件清單中選取 [Microsoft.ML],然後從 [版本] 下拉式清單中選擇版本 1.5.2。
- 按下 [安裝] 按鈕。
- 選取 [確定] 按鈕於 [預覽變更] 對話方塊上,然後如果您同意列出的套件的許可條款,請在 [授權接受] 對話方塊上選取 [我接受] 按鈕。
針對 Microsoft.ML.TimeSeries1.5.2版重複這些步驟。
在
using檔案頂端新增下列 指令:using Microsoft.ML; using Microsoft.ML.TimeSeries; using PhoneCallsAnomalyDetection;
下載您的數據
下載數據集,並將其儲存至您先前建立的 Data 資料夾:
在 phone-calls.csv 上按下滑鼠右鍵,然後選取 [儲存連結](或目標) 作為...。
請確定您將 *.csv 檔案儲存至 Data 資料夾,或在其他地方儲存之後,將 *.csv 檔案移至 Data 資料夾。
在 [方案總管] 中,以滑鼠右鍵按一下 *.csv 檔案,選取 [屬性]。 在 [進階] 下,將 [複製到輸出目錄] 的值變更為 [如果較新則複製]。
下表是 *.csv 檔案中的數據預覽:
| 時間戳記 | 價值 |
|---|---|
| 2018/9/3 | 36.69670857 |
| 2018/9/4 | 35.74160571 |
| ..... | ..... |
| 2018/10/3 | 34.49893429 |
| ... | .... |
此檔案代表時間序列。 檔案中的每個數據列都是數據點。 每個數據點都有兩個屬性,即 timestamp 和 value,以代表每天的來電數目。 通話數目會轉換成去敏感處理。
建立類別並定義路徑
接下來,定義您的輸入和預測類別數據結構。
將新類別新增至您的專案:
在 方案總管中,以滑鼠右鍵按下專案,然後選取 新增 > 新增項目。
在 [[新增專案] 對話框中,選取 [類別],並將 [名稱] 字段變更為 [PhoneCallsData.cs]。 然後,選取 新增。
PhoneCallsData.cs 檔案會在程式碼編輯器中開啟。
將下列
using指示詞新增至 PhoneCallsData.cs頂端:using Microsoft.ML.Data;移除現有的類別定義,將下列包含兩個類別
PhoneCallsData和PhoneCallsPrediction的程式碼新增到 PhoneCallsData.cs 檔案:public class PhoneCallsData { [LoadColumn(0)] public string? timestamp; [LoadColumn(1)] public double value; } public class PhoneCallsPrediction { // Vector to hold anomaly detection results, including isAnomaly, anomalyScore, // magnitude, expectedValue, boundaryUnits, upperBoundary and lowerBoundary. [VectorType(7)] public double[]? Prediction { get; set; } }PhoneCallsData指定輸入資料類別。 LoadColumn 屬性會說明應該載入資料集中的欄位(依欄位索引)。 它有兩個屬性timestamp,value對應至數據檔中的相同屬性。PhoneCallsPrediction指定預測數據類別。 針對 SR-CNN 偵測器,預測取決於指定的 偵測 模式。 在此範例中,您會選取AnomalyAndMargin模式。 輸出包含七個數據行。 在大部分情況下,IsAnomaly、ExpectedValue、UpperBoundary和LowerBoundary都信息豐富。 它們會告訴您某個點是否為異常、點的預期值,以及該點的下層和上限區域。將下列程式代碼新增至
using指示詞下方的行,以指定資料檔案的路徑:string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "phone-calls.csv");
初始化變數
以下列程式代碼取代
Console.WriteLine("Hello World!")行,以宣告和初始化mlContext變數:MLContext mlContext = new MLContext();MLContext 類別 是所有 ML.NET 作業的起點,初始化
mlContext會建立可跨模型建立工作流程對象共用的新 ML.NET 環境。 概念上,DBContext類似於 Entity Framework 中。
載入數據
ML.NET 中的資料會以 IDataView 介面來表示。
IDataView 是描述表格式數據(數值和文字)的彈性、有效率的方式。 數據可以從文本檔或其他來源(例如 SQL 資料庫或記錄檔)載入至 IDataView 物件。
在建立
mlContext變數之後,新增下列代碼:IDataView dataView = mlContext.Data.LoadFromTextFile<PhoneCallsData>(path: _dataPath, hasHeader: true, separatorChar: ',');LoadFromTextFile() 會定義檔案中的數據架構和讀取。 它會接受資料路徑變數,並傳回
IDataView。
時間序列異常偵測
時間序列異常偵測是偵測時間序列數據的異常值的過程,指的是在給定的輸入時間序列中,那些行為與預期不符或被認為「奇怪」的點。 這些異常通常會指出問題網域中一些感興趣的事件:用戶帳戶的網路攻擊、電源中斷、伺服器上的 RPS 暴增、記憶體流失等。
若要尋找時間序列的異常,您應該先判斷數列的期間。 然後,時間序列可以分解成數個元件作為 Y = T + S + R,其中 Y 是原始數位,T 是趨勢元件,S 是季節性元件,而 R 是數列的剩餘元件。 此步驟稱為 分解。 最後,會在剩餘元件上執行偵測,以尋找異常狀況。 在 ML.NET 中,SR-CNN 演算法是以光譜殘差(SR)和卷積神經網路(CNN)為基礎的進階和新穎演算法,可偵測時間序列上的異常。 如需此演算法的詳細資訊,請參閱 Microsoft
在本教學課程中,您會看到這些程式可以使用兩個函式來完成。
偵測期間
在第一個步驟中,您會叫用 DetectSeasonality 函式來判斷數列的期間。
建立 DetectPeriod 方法
使用下列程式代碼,在
DetectPeriod檔案底部建立 方法:int DetectPeriod(MLContext mlContext, IDataView phoneCalls) { }使用 DetectSeasonality 函式來偵測期間。 請使用下列程式碼將其新增至
DetectPeriod方法:int period = mlContext.AnomalyDetection.DetectSeasonality(phoneCalls, nameof(PhoneCallsData.value));在
DetectPeriod方法中新增以下程式碼為下一行程式碼,以顯示週期值:Console.WriteLine($"Period of the series is: {period}.");傳回週期值。
// <SnippetSetupSrCnnParameters>在呼叫
DetectPeriod方法下方,將下列呼叫新增至LoadFromTextFile()方法:int period = DetectPeriod(mlContext, dataView);
週期偵測結果
執行應用程式。 您的結果應該如下所示。
Period of the series is: 7.
偵測異常
在此步驟中,您會使用 DetectEntireAnomalyBySrCnn 方法來尋找異常狀況。
建立 DetectAnomaly 方法
使用下列程式代碼,在
DetectAnomaly方法正下方建立DetectPeriod方法:void DetectAnomaly(MLContext mlContext, IDataView phoneCalls, int period) { }使用下列程式代碼在 SrCnnEntireAnomalyDetectorOptions 方法中設定
DetectAnomaly:var options = new SrCnnEntireAnomalyDetectorOptions() { Threshold = 0.3, Sensitivity = 64.0, DetectMode = SrCnnDetectMode.AnomalyAndMargin, Period = period, };藉由在
DetectAnomaly方法中新增下列程式代碼行,以 SR-CNN 演算法偵測異常:var outputDataView = mlContext.AnomalyDetection.DetectEntireAnomalyBySrCnn(phoneCalls, nameof(PhoneCallsPrediction.Prediction), nameof(PhoneCallsData.value), options);將結果數據視圖轉換成強型別
IEnumerable,使用CreateEnumerable方法和以下程式碼以更容易顯示。var predictions = mlContext.Data.CreateEnumerable<PhoneCallsPrediction>( outputDataView, reuseRowObject: false);使用下列程式代碼建立顯示標頭,作為
DetectAnomaly方法中的下一行:Console.WriteLine("Index,Data,Anomaly,AnomalyScore,Mag,ExpectedValue,BoundaryUnit,UpperBoundary,LowerBoundary");您會在變更點偵測結果中顯示下列資訊:
-
Index是每個點的索引。 -
Anomaly是是否偵測到每個點異常的指標。 -
ExpectedValue是每個點的估計值。 -
LowerBoundary是每個點可以不被視為異常的最低值。 -
UpperBoundary是每個點的最高值,不可以是異常。
-
遍歷
predictionsIEnumerable並使用下列程式代碼顯示結果:var index = 0; foreach (var p in predictions) { if (p.Prediction is not null) { string output; if (p.Prediction[0] == 1) output = "{0},{1},{2},{3},{4}, <-- alert is on! detected anomaly"; else output = "{0},{1},{2},{3},{4}"; Console.WriteLine(output, index, p.Prediction[0], p.Prediction[3], p.Prediction[5], p.Prediction[6]); } ++index; } Console.WriteLine("");將下列呼叫新增至
DetectAnomaly方法呼叫下方的DetectPeriod()方法:DetectAnomaly(mlContext, dataView, period);
異常偵測結果
執行應用程式。 您的結果應該如下所示。 在處理期間,會顯示訊息。 您可能會看到警告或處理中的訊息。 為了清楚起見,某些訊息已從下列結果中移除。
Detect period of the series
Period of the series is: 7.
Detect anomaly points in the series
Index Data Anomaly AnomalyScore Mag ExpectedValue BoundaryUnit UpperBoundary LowerBoundary
0,0,36.841787256739266,41.14206982401966,32.541504689458876
1,0,35.67303618137362,39.97331874865401,31.372753614093227
2,0,34.710132999891826,39.029491313022824,30.390774686760828
3,0,33.44765248883495,37.786086547816545,29.10921842985335
4,0,28.937110922276364,33.25646923540736,24.61775260914537
5,0,5.143895892785781,9.444178460066171,0.843613325505391
6,0,5.163325228419392,9.463607795699783,0.8630426611390014
7,0,36.76414836240396,41.06443092968435,32.46386579512357
8,0,35.77908590657007,40.07936847385046,31.478803339289676
9,0,34.547259536635245,38.847542103915636,30.246976969354854
10,0,33.55193524820608,37.871293561337076,29.23257693507508
11,0,29.091800129624648,33.392082696905035,24.79151756234426
12,0,5.154836630338823,9.455119197619213,0.8545540630584334
13,0,5.234332502492464,9.534615069772855,0.934049935212073
14,0,36.54992549471526,40.85020806199565,32.24964292743487
15,0,35.79526470980883,40.095547277089224,31.494982142528443
16,0,34.34099013096804,38.64127269824843,30.040707563687647
17,0,33.61201516582131,37.9122977331017,29.31173259854092
18,0,29.223563320561812,33.5238458878422,24.923280753281425
19,0,5.170512168851533,9.470794736131923,0.8702296015711433
20,0,5.2614938889462834,9.561776456226674,0.9612113216658926
21,0,36.37103858487317,40.67132115215356,32.07075601759278
22,0,35.813544599026855,40.113827166307246,31.513262031746464
23,0,34.05600492733225,38.356287494612644,29.755722360051863
24,0,33.65828319077884,37.95856575805923,29.358000623498448
25,0,29.381125690882463,33.681408258162854,25.080843123602072
26,0,5.261543539820418,9.561826107100808,0.9612609725400283
27,0,5.4873712582971805,9.787653825577571,1.1870886910167897
28,1,36.504694001629254,40.804976568909645,32.20441143434886 <-- alert is on, detected anomaly
...
祝賀! 您現在已成功建置機器學習模型,以在週期性數列上偵測週期和異常。
您可以在 dotnet/samples 存放庫找到本教學課程的原始程式碼。
在本教學課程中,您已瞭解如何:
- 載入數據
- 偵測時間序列數據的週期
- 偵測時間序列數據的異常
後續步驟
請查看 Machine Learning 範例 GitHub 存放庫,以探索耗電量異常偵測範例。