共用方式為


教學課程:使用 ML.NET 偵測時間序列中的異常

了解如何建置時間序列資料的異常偵測應用程式。 此教學課程會示範如何在 Visual Studio 2019 中使用 C# 建立 .NET Core 主控台應用程式。

在本教學課程中,您會了解如何:

  • 載入資料
  • 偵測時間序列的期間
  • 偵測定期時間序列的異常狀況

您可以在 dotnet/samples 存放庫中找到本教學課程的原始程式碼。

必要條件

建立主控台應用程式

  1. 建立名為 "PhoneCallsAnomalyDetection" 的 C# 主控台應用程式。 按 [下一步] 按鈕。

  2. 選擇 .NET 6 作為要使用的架構。 按一下 [ 建立 ] 按鈕。

  3. 在專案中建立一個名為 Data 的目錄以儲存資料集檔案。

  4. 安裝 Microsoft.ML NuGet 封裝1.5.2 版:

    1. 在 [方案總管] 中,於您的專案上按一下滑鼠右鍵,然後選取 [管理 NuGet 套件]。
    2. 選擇「nuget.org」做為套件來源。
    3. 選取 [瀏覽] 索引標籤。
    4. 搜尋 Microsoft.ML
    5. 從封裝清單中選取 [Microsoft.ML],然後從 [版本] 下拉式清單中選擇 [1.5.2] 版。
    6. 選取 [安裝] 按鈕。
    7. 在 [預覽變更] 對話方塊上,選取 [確定] 按鈕,然後在 [授權接受] 對話方塊上,如果您同意所列套件的授權條款,請選取 [我接受]

    針對 Microsoft.ML.TimeSeries1.5.2 版重複這些步驟。

  5. 在您的 Program.cs 檔案最上方新增下列 using 陳述式:

    using Microsoft.ML;
    using Microsoft.ML.TimeSeries;
    using PhoneCallsAnomalyDetection;
    

下載您的資料

  1. 下載資料集,並儲存至您先前建立的 Data 資料夾:

    以滑鼠右鍵按一下 phone-calls.csv,然後選取 [另存連結 (或目標)...]

    請務必將 *.csv 檔案儲存至 Data 資料夾,或儲存在其他位置之後,將 *.csv 檔案移至 Data 資料夾。

  2. 在 [方案總管] 中,以滑鼠右鍵按一下 *.csv 檔案,並選取 [內容]。 在 [進階] 底下,將 [複製到輸出目錄] 的值變更為 [有更新時才複製]。

下表是 *.csv 檔案的資料預覽:

timestamp value
2018/9/3 36.69670857
2018/9/4 35.74160571
..... .....
2018/10/3 34.49893429
... ....

此檔案代表時間序列。 檔案中的每個資料列都是資料點。 每個資料點都有兩個屬性,也就是 timestampvalue,代表每天的通話數目。 通話數目會轉換成去敏感度。

建立類別及定義路徑

接下來,定義您的輸入和預測類別資料結構。

將新類別新增至專案:

  1. 在 [方案總管] 中,以滑鼠右鍵按一下專案,然後選取 [新增] > [新項目]。

  2. 在 [新增項目] 對話方塊中,選取 [類別],然後將 [名稱] 欄位變更為 PhoneCallsData.cs。 接著,選取 [新增] 按鈕。

    隨即在程式碼編輯器中開啟 PhoneCallsData.cs 檔案。

  3. 將下列 using 陳述式新增至 PhoneCallsData.cs 的上方:

    using Microsoft.ML.Data;
    
  4. 移除現有的類別定義,然後將下列程式碼 (具有 PhoneCallsDataPhoneCallsPrediction 這兩個類別) 新增至 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 屬性會指定應該載入資料集內的哪些資料行 (依資料行索引)。 其有兩個屬性 (timestampvalue),會對應至資料檔案中的相同屬性。

    PhoneCallsPrediction 指定預測資料類別。 針對 SR-CNN 偵測器,預測取決於指定的偵測模式。 在此範例中,我們會選取 AnomalyAndMargin 模式。 輸出包含七個資料行。 在大部分情況下,IsAnomaly, ExpectedValueUpperBoundaryLowerBoundary 都有足夠的資訊。 他們會告訴您某個點是否為異常、點的預期值,以及點的下/上限區域。

  5. 將下列程式碼新增至緊接在使用陳述式下方的一行,以指定資料檔案的路徑:

    string _dataPath = Path.Combine(Environment.CurrentDirectory, "Data", "phone-calls.csv");
    

將變數初始化

  1. Console.WriteLine("Hello World!") 行替換成下列程式碼,宣告並初始化 mlContext 變數:

    MLContext mlContext = new MLContext();
    

    MLContext 類別是所有 ML.NET 作業的起點,且初始化 mlContext 會建立新的 ML.NET 環境,其可在模型建立工作流程物件之間共用。 就概念而言,類似於 Entity Framework 中的 DBContext

載入資料

ML.NET 中的資料會以 IDataView 介面表示。 IDataView 是彈性且有效率的表格式資料描述方式 (數值和文字)。 資料可以從文字檔或其他來源 (例如 SQL 資料庫或記錄檔) 載入至 IDataView 物件。

  1. 在建立 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 殘差 (SR) 和卷積類神經網路為基礎, (CNN) 來偵測時間序列的異常。 如需此演算法的詳細資訊,請參閱 Microsoft 的時間序列異常偵測服務

在本教學課程中,您將會看到可以使用兩個函式來完成這些程序。

偵測期間

在第一個步驟中,我們會叫用 DetectSeasonality 函式來判斷序列列的期間。

建立 DetectPeriod 方法

  1. 使用下列程式碼,在 Program.cs 檔案底部建立 DetectPeriod 方法:

    int DetectPeriod(MLContext mlContext, IDataView phoneCalls)
    {
    
    }
    
  2. 使用 DetectSeasonality 函式來偵測期間。 使用下列程式碼將它新增至 DetectPeriod 方法:

    int period = mlContext.AnomalyDetection.DetectSeasonality(phoneCalls, nameof(PhoneCallsData.value));
    
  3. 將下列內容新增為 DetectPeriod 方法中的下一行程式碼來顯示期間值:

    Console.WriteLine("Period of the series is: {0}.", period);
    
  4. 傳回期間值。

    // <SnippetSetupSrCnnParameters>
    
  5. LoadFromTextFile() 方法的呼叫下方新增 DetectPeriod 方法的下列呼叫:

    int period = DetectPeriod(mlContext, dataView);
    

期間偵測結果

執行應用程式。 您的結果應該與以下類似。

Period of the series is: 7.

偵測異常

在此步驟中,您會使用 DetectEntireAnomalyBySrCnn 方法來尋找異常。

建立 DetectAnomaly 方法

  1. 請使用下列程式碼,在 DetectPeriod 方法正下方建立 DetectAnomaly 方法:

    void DetectAnomaly(MLContext mlContext, IDataView phoneCalls, int period)
    {
    
    }
    
  2. 使用下列程式碼在 DetectAnomaly 方法中設定 SrCnnEntireAnomalyDetectorOptions

    var options = new SrCnnEntireAnomalyDetectorOptions()
    {
        Threshold = 0.3,
        Sensitivity = 64.0,
        DetectMode = SrCnnDetectMode.AnomalyAndMargin,
        Period = period,
    };
    
  3. DetectAnomaly 方法中新增下列程式碼,以利用 SR-CNN 演算法偵測異常:

    var outputDataView = mlContext.AnomalyDetection.DetectEntireAnomalyBySrCnn(phoneCalls, nameof(PhoneCallsPrediction.Prediction), nameof(PhoneCallsData.value), options);
    
  4. 將輸出資料檢視轉換成強型別 IEnumerable,以更輕鬆使用 CreateEnumerable 方法和下列程式碼顯示:

    var predictions = mlContext.Data.CreateEnumerable<PhoneCallsPrediction>(
        outputDataView, reuseRowObject: false);
    
  5. 下列列程式碼作為 DetectAnomaly 方法中的下一行,建立顯示標頭:

    Console.WriteLine("Index,Data,Anomaly,AnomalyScore,Mag,ExpectedValue,BoundaryUnit,UpperBoundary,LowerBoundary");
    

    您會在變更點偵測結果中顯示下列資訊:

    • Index 是每個點的索引。
    • Anomaly 是每個點是否偵測為異常的指標。
    • ExpectedValue 是每個點的估計值。
    • LowerBoundary 是每個點的最小值,不能是異常值。
    • UpperBoundary 是每個點的最高值,不能是異常值。
  6. 使用下列程式碼逐一查看 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("");
    
  7. DetectPeriod() 方法呼叫的下方新增 DetectAnomaly 方法的下列呼叫:

    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 存放庫中找到本教學課程的原始程式碼。

在本教學課程中,您已了解如何:

  • 載入資料
  • 偵測時間序列資料的期間
  • 偵測時間序列資料中的異常

下一步

請查看機器學習範例 GitHub 存放庫,以探索耗電量異常偵測範例。