0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

時系列データの異常値検知を5ステップで考えてみる

0
Posted at

時系列データの異常値検知を5ステップで考えてみる

〜ロバスト統計から予測残差・AI拡張まで〜

はじめに

時系列データの異常値検出は、センサー監視、防災、水文データ、設備保全、IoT、ログ監視など、さまざまな分野で重要になります。

従来は、

  • 平均値から大きく外れた値
  • 標準偏差で見た外れ値
  • 上限値・下限値を超えた値

を検出する考え方が中心でした。

しかし、現在の時系列異常検知では、単純な外れ値だけでなく、

時系列異常検知

  • 文脈を考えるとおかしい値(contextual anomaly)
  • 連続区間として異常なパターン
  • 複数センサー間の関係性の崩れ
  • 予測値から大きく外れる挙動
  • 平均や分散が変化する変化点

を検出する考え方が重要になっています。

本記事では、時系列データの異常値検出を、実装しやすい順に 5ステップ で整理して、3段階で実装を行っていきたいと考えています。

異常値検知の実装ロードマップ
5step_image.png


対象とする異常の種類

時系列データの異常は、大きく次の3種類に分けられます。

種類 内容
点異常 ある時刻だけ極端に大きい・小さい センサー値の瞬間スパイク
文脈異常 時刻・季節・前後関係を考えるとおかしい 夜間では正常だが昼間では低すぎる値
集合異常 連続した区間としておかしい 数時間続く水位上昇、長時間の通信量低下

単純な外れ値検出だけでは、文脈異常や集合異常は見逃す可能性があります。

そのため、実務では データ品質チェック、ロバスト統計、周期性、予測残差、多変量関係 を段階的に組み合わせることが重要になります。


全体ロードマップ

本記事では、以下の5ステップで進めます。

Step 内容 位置づけ
Step 1 データ品質チェック 必須の前処理
Step 2 ロバスト統計による簡易異常検知 第1段階プロトタイプ
Step 3 周期性・季節性を考慮した異常検知 実務向け改善
Step 4 予測残差ベースの異常検知 本格的な時系列異常検知
Step 5 多変量・変化点・AI拡張 発展版

最初から深層学習や時系列基盤モデルを使うのではなく、説明しやすく、運用しやすい方法から段階的に進めるのが現実的です。


Step 1:データ品質チェック

目的

異常検知モデルを使う前に、まずデータそのものの品質を確認します。

時系列データでは、モデルに入れる前の段階で、すでに以下のような問題が含まれていることがあります。

  • 欠測
  • 重複
  • 時刻抜け
  • 時刻のずれ
  • 負値
  • 物理上限・下限を超える値
  • センサー停止
  • 単位ミス
  • 同じ値が長時間続く状態

これらは、AIモデルで検出する以前に、ルールベースで確認すべきものです。

雨量データの場合:

雨量 < 0        → 異常
雨量 > 300 mm/h → 異常候補
10分間隔データなのに30分空いている → 欠測
同一時刻が複数ある → 重複

水位データの場合:

水位が物理上限を超える
水位が長時間まったく変化しない
前時刻との差が急激すぎる

このステップで行うこと

  • 時刻の連続性チェック
  • 欠測チェック
  • 重複チェック
  • 物理上限・下限チェック
  • 明らかなセンサー異常チェック
  • データ品質フラグの付与

出力イメージ

timestamp, value, quality_flag
2026-01-01 00:00, 12.3, OK
2026-01-01 00:10, -1.0, NEGATIVE_VALUE
2026-01-01 00:20, NaN, MISSING

この品質フラグは、後続の異常検知モデルでも利用できます。


Step 2:ロバスト統計による簡易異常検知

目的

次に、まず動く異常検知を作ります。

ここでは、平均値や標準偏差ではなく、外れ値に強い 中央値MAD を使います。

MAD は Median Absolute Deviation の略で、中央値からの絶対偏差の中央値です。

基本式

score(t) = |x(t) - median_window(t)| / MAD_window(t)

異常判定の例:

score(t) > threshold なら異常

使う方法

  • 移動中央値
  • 移動MAD
  • Hampel filter
  • 前時刻との差分
  • 変化率
  • IQR

検出できる異常

  • 瞬間的なスパイク
  • 急激な落ち込み
  • センサー値の飛び
  • 短時間の異常値
  • 明らかなノイズ

なぜロバスト統計を使うのか

平均値と標準偏差は、外れ値そのものに影響されやすいです。

例えば、1つだけ極端に大きい値が入ると、平均値も標準偏差も大きく変化してしまい、異常を見逃すことがあります。

一方、中央値やMADは外れ値の影響を受けにくいため、初期プロトタイプに向いています。

Python実装イメージ

import pandas as pd
import numpy as np

def detect_hampel_anomaly(series: pd.Series, window: int = 7, n_sigmas: float = 3.0) -> pd.DataFrame:
    """
    Hampel filter による簡易異常検知。

    Parameters
    ----------
    series : pd.Series
        時系列データ。
    window : int
        移動窓サイズ。
    n_sigmas : float
        異常判定しきい値。

    Returns
    -------
    pd.DataFrame
        値、移動中央値、MAD、異常スコア、異常フラグを含むDataFrame。
    """
    rolling_median = series.rolling(window=window, center=True, min_periods=1).median()
    diff = (series - rolling_median).abs()
    mad = diff.rolling(window=window, center=True, min_periods=1).median()

    # MADが0の場合のゼロ割対策
    mad_safe = mad.replace(0, np.nan)

    # 正規分布換算の係数 1.4826 を使用
    score = diff / (1.4826 * mad_safe)

    is_anomaly = score > n_sigmas

    return pd.DataFrame({
        "value": series,
        "rolling_median": rolling_median,
        "mad": mad,
        "score": score,
        "is_anomaly": is_anomaly.fillna(False)
    })

Step 3:周期性・季節性を考慮した異常検知

目的

時系列データでは、時間帯・曜日・季節によって正常値が変わることがあります。

そのため、全期間に対して同じしきい値を使うと、誤検知や見逃しが発生します。

  • 昼間は高くて正常
  • 夜間に同じ値なら異常
  • 雨期なら高い水位でも自然
  • 平常期なら同じ水位でも注意
  • 平日は高負荷、休日は低負荷

このようなデータでは、周期性や季節性を考慮する必要があります。

使う方法

  • 時刻別平均
  • 曜日別平均
  • 月別平均
  • STL分解
  • 移動平均との差分
  • 季節成分を除いた残差

STL分解の考え方

時系列を次のように分解します。

観測値 = トレンド + 季節成分 + 残差

異常検知では、このうち 残差 を使います。

residual(t) = observed(t) - trend(t) - seasonal(t)

残差が大きい場合、通常の季節変動では説明できない異常と考えます。

検出できる異常

  • 時間帯を考えると不自然な値
  • 曜日パターンから外れる値
  • 季節性では説明できない急変
  • 通常周期から外れた挙動

Step 4:予測残差ベースの異常検知

目的

ここから本格的な時系列異常検知になります。

考え方はシンプルです。

正常な値を予測する
↓
実測値との差を計算する
↓
予測から大きく外れたら異常

基本式

residual(t) = actual(t) - predicted(t)

異常スコアの例:

anomaly_score(t) = |residual(t)| / expected_error(t)

使うモデル候補

モデル 向いている場面
ARIMA / SARIMA 周期性が比較的明確な単変量時系列
STL + 回帰 季節性を分離して扱いたい場合
LightGBM / XGBoost 外部説明変数がある場合
LSTM / TCN 非線形な時間依存がある場合
Transformer 長い依存関係を扱いたい場合

最初におすすめのモデル

最初から深層学習を使うより、以下から始めるのが現実的です。

  • STL + 残差検出
  • LightGBM による予測
  • SARIMA による予測

特に、雨量・水位・流量などの防災・水文データでは、説明可能性を考えると、まずは STL + 残差 または LightGBM + 残差 が扱いやすいです。

検出できる異常

  • 通常パターンからのズレ
  • 予測外の急変
  • 継続的な異常傾向
  • 雨量に対する水位反応の異常
  • 水位・流量の予測外変動

Step 5:多変量・変化点・AI拡張

目的

最後に、複数系列の関係性や、長期的な状態変化を扱います。

単一系列では正常に見えても、複数データの関係を見ると異常が分かる場合があります。

上流雨量が増えているのに下流水位が反応しない
隣接観測所と比べて1地点だけ値が不自然
ポンプ電流と吐出量の関係が崩れている
複数センサーの相関が突然変化した

使う方法

  • PCA
  • Isolation Forest
  • LOF
  • One-Class SVM
  • AutoEncoder
  • 変化点検出
  • Transformer
  • 時系列基盤モデル

変化点検出

異常値検出と似ていますが、変化点検出は「データの性質が変わった時刻」を探します。

異常値検出:一時的におかしい点や区間を探す
変化点検出:平均・分散・傾向が変わった時刻を探す

代表的な方法:

  • CUSUM
  • Page-Hinkley
  • PELT
  • Bayesian Change Point Detection
  • ruptures

AI拡張

深層学習を使う場合は、以下のような手法があります。

  • LSTM AutoEncoder
  • VAE
  • CNN AutoEncoder
  • Transformer
  • Anomaly Transformer
  • TranAD
  • 時系列基盤モデル

ただし、AIモデルは以下の課題があります。

  • 正常データが十分に必要
  • しきい値設定が難しい
  • 説明性が弱い
  • 学習・再学習コストが高い
  • 運用後のデータドリフトに注意が必要

そのため、プロトタイプ段階では、AIは最初から主役にせず、Step 1〜Step 4 の結果を補助する位置づけで導入するのが良いです。


実装方針

実装する場合は、以下のような構成にすると拡張しやすいです。

timeseries_anomaly_detection/
├─ data/
│  ├─ raw/
│  ├─ processed/
│  └─ sample/
├─ src/
│  ├─ data_quality.py
│  ├─ robust_detector.py
│  ├─ seasonal_detector.py
│  ├─ forecast_detector.py
│  ├─ multivariate_detector.py
│  ├─ change_point_detector.py
│  └─ utils.py
├─ notebooks/
├─ outputs/
│  ├─ figures/
│  └─ reports/
├─ app/
│  └─ gui_app.py
├─ requirements.txt
└─ README.md

各モジュールの役割

ファイル 役割
data_quality.py 欠測、重複、物理範囲チェック
robust_detector.py 移動中央値、MAD、Hampel filter
seasonal_detector.py STL分解、周期性除去
forecast_detector.py 予測残差ベース検出
multivariate_detector.py PCA、Isolation Forest、LOF
change_point_detector.py 変化点検出
utils.py 共通処理、時刻処理、可視化補助
gui_app.py GUIアプリ化する場合の入口

Pythonライブラリ候補

ライブラリ 用途
pandas 時系列データ処理
numpy 数値計算
scipy 統計処理
statsmodels STL、ARIMA
scikit-learn Isolation Forest、LOF、PCA
ruptures 変化点検出
PyOD 外れ値検出アルゴリズム
aeon 時系列機械学習
Merlion 時系列予測・異常検知
PyTorch AutoEncoder、LSTM、Transformer

第1段階プロトタイプの範囲

最初の実装では、以下までを対象にするのがおすすめです。

Step 1:データ品質チェック
Step 2:ロバスト統計
Step 3:周期性・季節性対応

この範囲であれば、

  • 実装が比較的簡単
  • 説明しやすい
  • 誤検知の確認がしやすい
  • GUI化しやすい
  • 実務データに適用しやすい

というメリットがあります。


第2段階で追加する内容

第2段階では、予測残差ベースを追加します。

Step 4:予測残差ベース

この段階では、以下を実装します。

  • 予測モデルの学習
  • 実測値との差分計算
  • 残差の異常スコア化
  • 予測区間からの逸脱判定
  • 異常区間の抽出

第3段階で追加する内容

第3段階では、多変量・変化点・AI拡張を追加します。

Step 5:多変量・変化点・AI拡張

この段階では、以下を扱います。

  • 複数観測所の関係
  • 雨量と水位の関係
  • 水位と流量の関係
  • センサー群の相関崩れ
  • 平均・分散の変化点
  • AutoEncoder や Transformer の検討

運用時に重要なポイント

異常検知は、モデルを作って終わりではありません。

実務では、次の点が重要になります。

  • 異常スコアを保存する
  • 検出理由を表示する
  • しきい値を調整できるようにする
  • 誤検知を確認できるようにする
  • 正常・異常のラベルを後から追加できるようにする
  • 検出結果をログとして保存する
  • モデルやパラメータを再現できるようにする
  • 将来的に再学習できる構成にする

特に、防災・水文・センサー監視では、説明可能性が重要です。

単に「AIが異常と判断した」ではなく、

どの値が
どの時刻に
どの基準を超えて
どの程度異常だったのか

を表示できるようにする必要があります。


まとめ

時系列データの異常値検出は、最初から高度なAIモデルを使うより、段階的に進めるのが現実的です。

おすすめの進め方は次の5ステップです。

進め方

  • Step 1:データ品質チェック
  • Step 2:ロバスト統計による簡易異常検知
  • Step 3:周期性・季節性を考慮した異常検知
  • Step 4:予測残差ベースの異常検知
  • Step 5:多変量・変化点・AI拡張

特に第1段階では、

第1段階

  • データ品質チェック
  • 移動中央値 + MAD
  • Hampel filter
  • STL分解 + 残差

を中心に実装すると、説明しやすく、実務にも適用しやすいプロトタイプになります。

その後、予測残差ベース、多変量異常検知、変化点検出、深層学習、時系列基盤モデルへ拡張していくのがよいと考えます。


参考リンク


0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?