時系列異常検知 — 監視の現場で動いている数学
監視のアラートは、値の大きさではなく「その時刻に期待される値とのずれ」で鳴らすべきです。ロバストな統計量・予測残差・部分列の近傍距離・変化点検出という4つの物差しを比喩から式まで積み上げ、実務で最も事故が多い閾値の決め方と評価の罠まで扱います。
Bayesian Online Changepoint Detection
一次資料 — この記事の根拠
この解説の公開 2026-08-25
Bayesian Online Changepoint DetectionarXiv:0710.3742論文ページ·PDFTowards a Rigorous Evaluation of Time-series Anomaly DetectionarXiv:2109.05257論文ページ·PDF
Current Time Series Anomaly Detection Benchmarks are Flawed and are Creating the Illusion of ProgressarXiv:2009.13807論文ページ·PDF
深夜2時、監視画面が赤くなる
CPU使用率が90%を超えたらアラートを鳴らす。監視の第一歩はたいていこれです。そして1ヶ月も運用すると、ほぼ必ずこうなります。毎週日曜の未明に重いバッチが走って90%を超え、当番が叩き起こされる。仕方なく閾値を95%へ上げると、今度は平日の本当の障害が92%で止まっていて、誰も気づかない。
問題は数字ではなく、「異常」を値の大きさだけで定義したことです。日曜未明の90%は正常で、火曜午後の70%のほうが異常かもしれない。時系列の異常とは、値そのものではなくその時刻・その文脈から期待される値とのずれです。この記事では、そのずれを測る物差しを4つ——統計量・予測残差・部分列の距離・変化点——順に組み立てます。前提知識は平均と標準偏差だけで足ります。
「異常」には3つの顔がある
点異常は、単独の値がぽつんと外れるもの。センサの読み取りミスで一瞬だけ 9999 が出る、といったスパイクです。
文脈異常は、値自体はありふれているのにその時刻には起きないはずというもの。真夏に暖房の電力が立つ、深夜3時のアクセス数が昼のピーク並みになる。値の分布としては外れていないので、ヒストグラムを眺めても永遠に見つかりません。
部分列異常は、一つ一つの値は普通なのに並び方がおかしいもの。心電図で一拍だけリズムが崩れる、振動センサの周期が乱れる。各点を独立に見ている限り、これも検知できません。
時系列に固有なのは後ろの2つで、現場で本当に困るのもこの2つです。
物差し1: 統計的な「外れ具合」
古典から始めます。平均からの距離を、標準偏差を単位にして測るzスコアです。
は時刻 の観測値、 は平均、 は標準偏差。要するに「平均から標準偏差何個分ぶん離れているか」を数えているだけです。正規分布なら は約0.3%しか起きないので、そこに線を引く——「3シグマ」と呼ばれる慣行です。
素朴ですが、そのままでは2つの理由で壊れます。
ひとつは異常が自分自身を隠すこと。 と は異常を含んだデータから計算されています。巨大なスパイクが1点あると、それが を膨らませ、結果として自分の を小さくしてしまう。異常が大きいほど見つけにくいという意地の悪い性質で、マスキングと呼ばれます。対策は、外れ値に引きずられない統計量——中央値とMAD(中央絶対偏差)への置き換えです。
要するに「中央値からのずれの、中央値」を散らばりの尺度に使うということです。 は正規分布のとき と一致させるための定数で、深い意味はありません。中央値は半分近くが汚染されても動かないので、スパイクが何点混ざっても物差しが狂いません。
もうひとつは平均が一定でないこと。トレンドがあれば去年の平均は今日の基準になりませんし、日内周期があれば「1日の平均」は昼にも夜にも当てはまりません。対策は、全期間ではなく直近の窓だけで と を計算することです。製造業の管理図は、この発想で100年近く現場を回してきました。
import numpy as np
def robust_z(x, window=288): # 288 = 5分刻みで1日分
med = np.median(x[-window:])
mad = np.median(np.abs(x[-window:] - med))
return (x[-1] - med) / (1.4826 * mad + 1e-9)
窓幅が最初のハイパーパラメータです。短いと敏感になる一方、異常が続くとそれが新しい「正常」になる。長いと鈍く、正当な変化にも延々と鳴り続ける。この綱引きは、以降のどの手法にも形を変えて現れます。
物差し2: 予測して、残差を見る
発想を変えます。「正常なときの系列を予測できるモデル」を先に作り、予測と実測の差(残差)を異常度にするのです。
が予測値です。つまり異常検知を、予測問題とその後始末に分解したことになります。
この分解が効くのは、トレンド・季節性・カレンダー効果をまるごとモデル側へ押し込められるからです。冒頭の日曜バッチを思い出してください。予測が「日曜未明は90%」と知っていれば、実際に90%でも残差はほぼゼロでアラートは鳴りません。逆に火曜午後の70%は、予測が40%だった分だけ残差が立つ。値の大小ではなく文脈からのずれを測る、という最初の目標がここで実現します。予測モデル自体の作り方は時系列予測を1から解説にあります。
ただし、大きな落とし穴があります。予測モデルが柔軟すぎると、異常まで再現してしまうのです。表現力の高いモデルを残差がゼロになるまで訓練すれば、スパイクごと予測してしまい、検知器は何も鳴らなくなる。異常検知の予測器は、わざと鈍く作るのが正しい。
コメント
コメントにはログインが必要です