一般的な時系列のオンライン異常値検出のためのシンプルなアルゴリズム


88

私は大量の時系列で作業しています。これらの時系列は基本的に10分ごとに発生するネットワーク測定値であり、一部は定期的(帯域幅)であり、一部はそうでない(つまりルーティングトラフィックの量)です。

オンラインの「異常値検出」を行うための簡単なアルゴリズムが欲しいです。基本的に、各時系列の履歴データ全体をメモリ(またはディスク)に保持し、ライブシナリオ(新しいサンプルがキャプチャされるたびに)で異常値を検出します。これらの結果を達成する最良の方法は何ですか?

現在、ノイズを除去するために移動平均を使用していますが、次に何をしますか?データセット全体に対する標準偏差、狂気などの単純なものはうまく機能しません(時系列が定常的であるとは思いません)。

double outlier_detection(double * vector、double value);

ここで、vectorは履歴データを含むdoubleの配列であり、戻り値は新しいサンプル "value"の異常スコアです。


1
明確にするために、SOの元の質問を次に示します。stackoverflow.com
マットパーカー

1
別のSEサイトに同じ質問を投稿した場合、質問の一部としてリンクを投稿するようにポスターを奨励する必要があると思います。

はい、あなたは完全に正しいです。次回は、メッセージがクロスポストされることについて言及します。
ジャンルカ

また、ページの右側にある他の関連リンクも確認することをお勧めします。これは一般的な質問であり、これまでにさまざまな質問が寄せられています。満足できない場合は、状況の詳細に関する質問を更新するのが最善です。
アンディW

@Andyさん、良いキャッチです!この質問を他の質問とマージしましょう。
whuber

回答:


75

これは、時系列の外れ値を見つける(オプションでそれらをプロットに表示する)簡単なR関数です。季節的および非季節的時系列を処理します。基本的な考え方は、トレンドと季節成分の堅牢な推定値を見つけて、それらを減算することです。次に、残差で外れ値を見つけます。残差の外れ値の検定は、標準の箱ひげ図の検定と同じです。上限と下限の四分位の上下1.5IQRより大きい点は、外れ値と見なされます。これらのしきい値を上回る/下回るIQRの数は、外れ値の「スコア」として返されます。そのため、スコアは任意の正の数値にすることができ、外れ値以外の場合はゼロになります。

Rでこれを実装していないことはわかっていますが、R関数を開始するのに適した場所であることがよくあります。次に、これを必要な言語に翻訳します。

tsoutliers <- function(x,plot=FALSE)
{
    x <- as.ts(x)
    if(frequency(x)>1)
        resid <- stl(x,s.window="periodic",robust=TRUE)$time.series[,3]
    else
    {
        tt <- 1:length(x)
        resid <- residuals(loess(x ~ tt))
    }
    resid.q <- quantile(resid,prob=c(0.25,0.75))
    iqr <- diff(resid.q)
    limits <- resid.q + 1.5*iqr*c(-1,1)
    score <- abs(pmin((resid-limits[1])/iqr,0) + pmax((resid - limits[2])/iqr,0))
    if(plot)
    {
        plot(x)
        x2 <- ts(rep(NA,length(x)))
        x2[score>0] <- x[score>0]
        tsp(x2) <- tsp(x)
        points(x2,pch=19,col="red")
        return(invisible(score))
    }
    else
        return(score)
}

私からの+1、素晴らしい。では、1.5 Xの四分位範囲は、時間依存シリーズの外れ値のコンセンサス定義ですか?スケールに依存しない参照があればいいでしょう。
ダグ

外れ値のテストは残差に基づいているため、時間依存性が小さいことが望まれます。私はコンセンサスについては知りませんが、箱ひげ図はしばしば異常値の検出に使用され、かなりうまく機能しているようです。誰かが関数を少し面倒にしたかったなら、より良い方法があります。
ロブハインドマン

本当にありがとうございます、本当に感謝しています。私は今仕事でかなり忙しいですが、できるだけ早くあなたのようなアプローチをテストするつもりです。考えられたのは、あなたの関数では、私が見るものから、時系列の頻度を手動で指定する必要があり(構築するとき)、季節性成分は頻度が1より大きい場合にのみ考慮されますこれを自動的に処理するには?
ジャンルカ

1
はい、周波数は既知で指定されていると想定しています。周波数を自動的に推定する方法がありますが、それは機能をかなり複雑にします。頻度を推定する必要がある場合は、頻度について別の質問をしてみてください。おそらく答えを提供します。しかし、コメントで利用できる以上のスペースが必要です。
ロブハインドマン

2
@Marcin、自分で刺すことをお勧めします。ソリューションをgist.github.comに貼り付け、完了したらSO質問を投稿して、他の人に作業をチェックしてもらえますか?
ケンウィリアムズ

27

優れたソリューションには、次のようないくつかの要素が含まれます。

  • 非定常性を除去するために、抵抗力のある、動く窓を滑らかに使用してください。

  • 平滑に関する残差がほぼ対称的に分布するように、元のデータを再表現します。データの性質を考えると、それらの平方根または対数は対称残差を与える可能性があります。

  • 管理図法、または少なくとも管理図思考を残差に適用します。

最後の1つに関する限り、管理図の考え方では、2 SDやIQRの4分の1の1.5倍などの「従来の」しきい値は、誤った制御不能信号をトリガーしすぎるため、うまく機能しません。通常、管理図の作業には3 SDを使用します。四分位を超えるIQRの2.5倍(または3倍)が適切な出発点です。

Rob Hyndmanのソリューションの性質を大まかに概説しましたが、2つの主要なポイントを追加しました。データを再表現する必要性と、外れ値を通知する際により保守的であるという知恵です。ただし、Loessがエンドポイントでうまく機能しないため、Loessがオンライン検出器に適しているかどうかはわかりません。代わりに、移動メジアンフィルターのような単純なものを使用することもできます(Tukeyの耐性スムージングなど)。外れ値が急増しない場合は、狭いウィンドウを使用できます(5つのデータポイント、おそらく、5つのグループ内の3つ以上の外れ値のバーストでのみ故障します)。

分析を実行してデータの適切な再表現を決定したら、再表現を変更する必要はほとんどありません。したがって、オンライン検出器は、以前のデータをまったく使用しないため、実際には最新の値(最新のウィンドウ)のみを参照する必要があります。非常に長い時系列がある場合は、自己相関と季節性(毎日または毎週の変動の繰り返しなど)をさらに分析して、手順を改善できます。


3
これは、実用的な分析に対する並外れた答えです。四分位数を超えて3 IQRを試すのに必要だとは思わなかったでしょう。
ジョンロバートソン

3
@ John、1.5 IQRは、箱ひげ図の最長ウィスカに対するTukeyの元の推奨であり、3 IQRは、ポイントを「遠い外れ値」(人気のある60年代のフレーズのリフ)としてマークするための彼の推奨です。これは多くの箱ひげ図アルゴリズムに組み込まれています。推奨事項は、Hoaglin、Mosteller、およびTukey、Robust and Exploratory Data Analysisで
whuber

これは、分析しようとした時系列データを確認します。ウィンドウ平均およびウィンドウ標準偏差。((x-avg)/ sd)> 3は、外れ値としてフラグを立てたいポイントのようです。少なくとも異常値として警告しますが、10 sdを超える値は極端なエラー異常値としてフラグを立てます。私が遭遇する問題は、理想的なウィンドウの長さです。4〜8個のデータポイントの間で遊んでいます。
ジョシュピーク

1
@Neo最善の策は、データのサブセットを実験し、残りのテストで結論を確認することです。より正式な相互検証も実施できます(ただし、すべての値の相互依存性のため、時系列データには特別な注意が必要です)。
whuber

17

(この回答は、未解決のイベントの検出に関する重複した(現在は閉じられている)質問に回答しました。


外れ値の検出は、データの性質と、データについて何を想定するかによって異なります。 汎用メソッドは、堅牢な統計に依存しています。このアプローチの精神は、外れ値の影響を受けない方法でデータの大部分を特徴付けて、その特性に収まらない個々の値を指すことです。

これは時系列であるため、異常値を継続的に(再)検出する必要があるという複雑さが加わります。これがシリーズの展開時に行われる場合、検出には古いデータのみを使用でき、将来のデータは使用できません!さらに、多くの繰り返しテストに対する保護として、偽陽性率が非常に低い方法を使用する必要があります。

これらの考慮事項は、データに対して単純で堅牢な移動ウィンドウの外れ値テストを実行することをお勧めします。多くの可能性がありますが、単純で、簡単に理解され、簡単に実装できるものは、実行中のMADに基づいています:中央値からの絶対偏差の中央値。これは、標準偏差に類似した、データ内の変動の非常に堅牢な尺度です。外れたピークは、いくつかのMADまたは中央値より大きくなります。

Rx=(1,2,,n)n=1150y

# Parameters to tune to the circumstances:
window <- 30
threshold <- 5

# An upper threshold ("ut") calculation based on the MAD:
library(zoo) # rollapply()
ut <- function(x) {m = median(x); median(x) + threshold * median(abs(x - m))}
z <- rollapply(zoo(y), window, ut, align="right")
z <- c(rep(z[1], window-1), z) # Use z[1] throughout the initial period
outliers <- y > z

# Graph the data, show the ut() cutoffs, and mark the outliers:
plot(x, y, type="l", lwd=2, col="#E00000", ylim=c(0, 20000))
lines(x, z, col="Gray")
points(x[outliers], y[outliers], pch=19)

質問に示されている赤い曲線のようなデータセットに適用すると、次の結果が生成されます。

プロット

データは赤で、中央値+ 5 * MADしきい値の30日間のウィンドウは灰色で、外れ値は単に灰色の曲線より上のデータ値で、黒で表示されます。

(しきい値は、最初のウィンドウの最後からしか計算できません。この最初のウィンドウ内のすべてのデータには、最初のしきい値が使用されます。そのため、灰色の曲線はx = 0とx = 30の間で平坦です。)

パラメータを変更すると、(a)の値がwindow大きくthresholdなるとグレーカーブが滑らかになり、(b)大きくするとグレーカーブが大きくなります。これを知って、データの最初のセグメントを取得し、外側のピークを残りのデータから最適に分離するパラメーターの値をすばやく特定できます。これらのパラメータ値を適用して、残りのデータを確認します。時間が経つにつれてメソッドが悪化していることがプロットに示されている場合、それはデータの性質が変化しており、パラメーターの再調整が必要な可能性があることを意味します。

このメソッドがデータに関してほとんど想定していないことに注意してくださいそれらは正規分布である必要はありません。周期性を示す必要はありません。彼らは非負である必要さえありません。すべてのそれは想定していたデータは、時間をかけて、合理的に同様の方法で動作することをして、範囲外のピークは、データの残りの部分よりも目に見えて高くなっているということです。


誰かが実験する(または他のソリューションをここで提供されているソリューションと比較する)場合は、質問に示されているようなデータを生成するために使用したコードを以下に示します。

n.length <- 1150
cycle.a <- 11
cycle.b <- 365/12
amp.a <- 800
amp.b <- 8000

set.seed(17)
x <- 1:n.length
baseline <- (1/2) * amp.a * (1 + sin(x * 2*pi / cycle.a)) * rgamma(n.length, 40, scale=1/40)
peaks <- rbinom(n.length, 1,  exp(2*(-1 + sin(((1 + x/2)^(1/5) / (1 + n.length/2)^(1/5))*x * 2*pi / cycle.b))*cycle.b))
y <- peaks * rgamma(n.length, 20, scale=amp.b/20) + baseline

これは本当に興味深いソリューションであり、Rを使用せずに(Webアプリケーションで単純なJavaScriptを使用するだけで)実装できることに感謝しています。ありがとう!
hgoebl

15

特定のアプローチで仮定が心配な場合、1つのアプローチは異なる信号で多数の学習者をトレーニングし、アンサンブルメソッドを使用して学習者からの「投票」を集計して外れ値分類を行うことです。

ところで、これは問題へのいくつかのアプローチを参照しているので、これは読むかスキミングする価値があるかもしれません。


5

この方法論を使用して異常値を検出するのに時間がかかるため、洗練された時系列モデルは機能しません。したがって、次の回避策があります。

  1. 最初に、時刻、平日、週末、年の月などを考慮した履歴データの手動分析に基づいて、1年間のベースライン「通常」トラフィックパターンを確立します。

  2. 外れ値を検出するために、このベースラインをいくつかの単純なメカニズム(たとえば、Carlosによって提案された移動平均)とともに使用します。

また、いくつかのアイデアについては、統計的プロセス制御に関する文献を確認することもできます。


1
ええ、これはまさに私がやっていることです:今まで手動で信号を期間に分割しました。そのため、それぞれの期間について、信号が静止しているはずの信頼区間を定義できるため、標準的な方法を使用できます標準偏差として、...本当の問題は、分析する必要のあるすべての信号の予想されるパターンを決定できないことです。それが、よりインテリジェントなものを探している理由です。
ジャンルカ

1つのアイデアを次に示します。ステップ1:履歴データに基づいて、1つの時間ベースで一般的な時系列モデルを実装および推定します。これはオフラインで実行できます。ステップ2:結果のモデルを使用して、外れ値を検出します。ステップ3:一定の頻度(おそらく毎月?)で、時系列モデルを再調整し(オフラインで実行可能)、外れ値のステップ2の検出が現在のトラフィックパターンとあまりずれないようにします。それはあなたのコンテキストで機能しますか?

はい、これはうまくいくかもしれません。私は同様のアプローチを考えていました(ベースラインを毎週再計算します。分析する数百の単変量時系列がある場合、CPUに負荷がかかる可能性があります)。ところで、本当に難しい質問は、「ノイズ、傾向推定、季節性を考慮して、完全に一般的な信号をモデル化するための最高のブラックボックススタイルのアルゴリズムは何ですか?」です。知る限り、文献のすべてのアプローチには本当に難しい「パラメーター調整」フェーズが必要であり、私が見つけた唯一の自動方法はHyndmanのARIMAモデル(robjhyndman.com/software/forecast)です。何か不足していますか?
ジャンルカ

これらのパラメーターを調査するのが面倒ではないことを覚えておいてください。ポイントは、これらの値を信号の予想パターンに従って設定する必要があるということであり、私のシナリオでは推測することはできません。
ジャンルカ

ARIMAモデルは、時系列データを近似するために使用できる古典的な時系列モデルです。ARIMAモデルの適用を検討することをお勧めします。あなたはロブがオンラインになるのを待つことができ、おそらく彼はいくつかのアイデアでチャイムします。

5

通常の日がフラットに近くなるように、データを季節ごとに調整します。今日の午後5時のサンプルを使用して、午後30時に過去30日間の平均を減算または除算できます。次に、外れ値の過去N個の標準偏差(事前調整済みデータを使用して測定)を調べます。これは、毎週と毎日の「季節」に対して別々に行うことができます。


繰り返しますが、信号にそのような季節性があると想定される場合、これは非常にうまく機能しますが、完全に異なる時系列(つまり、時間に対する平均TCP往復時間)を使用する場合、この方法は機能しません(より良いため)履歴データを含むスライディングウィンドウを使用して、単純なグローバル平均と標準偏差でそれを処理します)。
ジャンルカ

1
一般的な時系列モデル(遅延などの点で短所をもたらす)を実装する意思がない限り、あらゆる種類の時系列で動作するのに十分に単純な一般的な実装を見つけることができると悲観的です。

別のコメント:良い答えは「信号の周期性を推定し、それに応じて使用するアルゴリズムを決定する」かもしれないと知っていますが、この他の問題に対する本当の良い解決策は見つかりませんでした(私は自己相関関数を使用してDFT、時間分析を使用して、私の時系列は、多くのノイズが含まれており、そのような方法は、時間のいくつかのクレイジー結果のMOSTを与えるスペクトル分析とビット)
Gianlucaさん

あなたの最後のコメントへのコメント:それが私がより一般的なアプローチを探している理由です、しかし、私は分析されたシグナルについての仮定をすることができないので一種の「ブラックボックス」が必要です。 「学習アルゴリズムに最適なパラメーターセット」。
ジャンルカ

@gianlucaあなたが推測したように、基礎となるARIMA構造は異常を隠すことができます。時刻、曜日、休日の影響など、考えられる原因変数の不正確な定式化も、異常を隠す可能性があります。答えは、異常を効果的に検出するために十分な注意を払う必要があることはかなり明白です。ベーコンを引用すると、「自然の方法を知っている人は彼女の逸脱に簡単に気付くでしょう。一方、彼女の逸脱を知っている人は彼女の方法をより正確に説明します。」
IrishStat

3

Rob Hyndmanが概説したアプローチの代替案は、Holt-Winters Forecastingを使用することです。Holt-Wintersから導出された信頼帯を使用して、外れ値を検出できます。ここでは、「ネットワーク監視のための時系列での異常行動検出」のためにホルト・ウィンタースを使用する方法について説明した紙です。RRDToolの実装はここにあります


2

スペクトル分析は、定常時系列の周期性を検出します。スペクトル密度推定に基づく周波数領域アプローチは、最初のステップとしてお勧めするアプローチです。

特定の期間において、不規則性がその期間に典型的なものよりもはるかに高いピークを意味する場合、そのような不規則性を持つシリーズは定常的ではなく、スペクトル解析は適切ではありません。しかし、不規則性のある期間を特定したと仮定すると、通常のピークの高さをほぼ決定でき、その平均を超えるレベルでしきい値を設定して不規則なケースを指定できます。


2
このソリューションが「局所的な不規則性」をどのように検出するか説明していただけますか?実用的な例を提示することは非常に役立ちます。(正直に言って、このような演習を行うと、あなたの提案は外れ値の検出には効果的でないことがわかると思いますが、間違っている可能性があります...)
whuber

1
@whuberスペクトル分析は、すべてのピークがどこにあるかのみを識別します。次のステップは、スペクトル分析から決定された周波数とデータから推定された振幅を使用して、サインとコサインの項を使用して、yimeシリーズモデルを近似することです。不規則性が非常に高い振幅のピークを意味する場合、振幅のしきい値が適切だと思います。局所的な不規則性により、ある期間において振幅が他の不規則性よりも大幅に大きくなることがある場合、系列は定常的ではなく、スペクトル分析は適切ではありません。
マイケルチャーニック

1
定常性の欠如に関する結論には従いません。たとえば、通常の正弦波とマークされたポアソン点プロセスの合計は定常的ですが、求める周期性はまったくありません。それでもピリオドグラムにはいくつかの強いピークがありますが、ポアソンプロセスコンポーネントによって導入された不規則なデータピークに関連するものは何もありません。
whuber

1
定常時系列には一定の平均があります。周期的な成分のピークが時間とともに変化する可能性がある場合、平均が時間とともに変化するため、平均値に変化が生じる可能性があり、したがって、周期は非定常になります。
マイケルチャーニック

2

時系列データであるため、単純な指数フィルターhttp://en.wikipedia.org/wiki/Exponential_smoothingはデータを平滑化します。古いデータポイントを蓄積する必要がないため、非常に優れたフィルターです。すべての新しく比較平滑そのとデータ値を平滑化されていない値。偏差が特定の事前定義されたしきい値を超えると(データの外れ値と思われるものに応じて)、外れ値を簡単に検出できます。

CIでは、リアルタイムの16ビットサンプルについて次のことを行います(これはここのどこかにあります<説明-https://dsp.stackexchange.com/questions/378/what-is-the-best-first-order -iir-approximation-to-a-moving-average-filter >)

#define BITS2 2     //< This is roughly = log2( 1 / alpha ), depending on how smooth you want your data to be

short Simple_Exp_Filter(int new_sample) 
{static int filtered_sample = 0;
long local_sample = sample << 16; /*We assume it is a 16 bit sample */
filtered_sample += (local_sample - filtered_sample) >> BITS2;   
return (short) ((filtered_sample+0x8000) >> 16); //< Round by adding .5 and truncating.   
}


int main()
{
newly_arrived = function_receive_new_sample();
filtered_sample = Simple_Exp_Filter(newly_arrived);
if (abs(newly_arrived - filtered_sample)/newly_arrived > THRESHOLD)
    {
    //AN OUTLIER HAS BEEN FOUND
    }
 return 0;   
}

1

最後のN個の測定値の標準偏差を使用できます(適切なNを選択する必要があります)。良い異常スコアは、移動平均からの測定値の標準偏差の数です。


ご回答いただきありがとうございますが、信号の季節性が高い場合(つまり、多くのネットワーク測定値が、毎日と毎週のパターン、例えば夜間と昼間、週末と営業日などによって特徴付けられる場合)はどうでしょうか。その場合、標準偏差に基づくアプローチは機能しません。
ジャンルカ

たとえば、10分ごとに新しいサンプルを取得し、会社のネットワーク帯域幅使用量の異常値検出を行っている場合、基本的に午後6時にこの測定値は低下します(これは完全に正常なパターンです)。スライディングウィンドウで計算された標準偏差は失敗します(確かにアラートをトリガーするため)。同時に、メジャーが午後4時に低下した場合(通常のベースラインから逸脱)、これは実際の外れ値です。
ジャンルカ

1

私がしているのは、時間と曜日で測定値をグループ化し、その標準偏差を比較することです。休日や夏/冬の季節性などについては依然として正しいとは言えませんが、ほとんどの場合正しいです。

欠点は、stddevが意味を持ち始めるのに十分なデータを得るために、実際に1年程度のデータを収集する必要があることです。


それは私が(ベースラインの1〜2週間後に、多分「汚い」などのオンライン検出、)本当に反応アプローチをしたいと思いますので、私は、(ベースラインとしてのサンプルの多くを持つ)を回避しようとしていたまさにです、ありがとう
Gianlucaさん

0

以下のスキームをお勧めします。これは1日程度で実装できるはずです。

トレーニング

  • メモリに保持できる数のサンプルを収集します
  • 各属性の標準偏差を使用して明白な外れ値を削除します
  • 相関行列と各属性の平均も計算して保存します
  • すべてのサンプルのマハラノビス距離を計算して保存します

「外れ値」の計算:

「外れ値」を知りたい単一のサンプルの場合:

  • トレーニングから平均、共分散行列、マハラノビス距離 sを取得します
  • サンプルのマハラノビス距離「d」を計算します
  • 「d」が含まれるパーセンタイルを返します(トレーニングからのマハラノビス距離を使用)

それが外れ値スコアになります。100%は極端な外れ値です。


PS。マハラノビス距離の計算では、共分散行列ではなく相関行列を使用します。サンプルの測定値の単位と数が異なる場合、これはより堅牢です。


0

外れ値をすばやく計算する必要がある場合、Rob HyndmanとMahito Sugiyamaのアイデア(https://github.com/BorgwardtLab/sampling-outlier-detection、library(spoutlier)、function qsp)を使用して計算できます次のような外れ値:

library(spoutlier)
rapidtsoutliers <- function(x,plot=FALSE,seed=123)
{
    set.seed(seed)
    x <- as.numeric(x)
    tt <- 1:length(x)
    qspscore <- qsp(x)
    limit <- quantile(qspscore,prob=c(0.95))
    score <- pmax((qspscore - limit),0)
    if(plot)
    {
        plot(x,type="l")
        x2 <- ts(rep(NA,length(x)))
        x2[score>0] <- x[score>0]
        tsp(x2) <- tsp(x)
        points(x2,pch=19,col="red")
        return(invisible(score))
    }
    else
        return(score)
}

0

異常検出には、期待値を記述する方程式の構築が必要です。介入検出は、非因果設定と因果設定の両方で利用できます。価格などの予測子シリーズがある場合、少し複雑になる可能性があります。ここでの他の応答は、価格などのユーザー指定の予測変数シリーズに起因する割り当て可能な原因を考慮していないようで、欠陥がある可能性があります。販売数量は、おそらく以前の価格とおそらく過去の販売数量に応じて価格に依存する可能性があります。異常検出の基礎(パルス、季節的パルス、レベルシフト、現地時間の傾向)は https://pdfs.semanticscholar.org/09c4/ba8dd3cc88289caf18d71e8985bdd11ad21c.pdfにあります。


リンクが機能していません。修正してください。ありがとう
Pankaj Joshi

完了..................
IrishStat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.