「異常」と言われても
AutoEncoder による異常検知を 公開したとき、画面には「異常」と表示される点が並びました。 それらしく見えます。
ただ、どこからが異常なのかは、モデルが決めたわけではありません。 モデルが出すのは「どれくらい普段と違うか」という連続値だけです。 そこに線を引いて「これ以上は異常」としたのは、実装した側です。
異常スコアの計算方法ではなく、そのスコアをどう判定に変えるかを扱います。 AutoEncoder でも移動平均でも、連続値を二値にする段階で同じ問題が起きます。
今回は分かりやすさのため、移動窓の標準化残差を異常スコアとします。 直近60日の平均と標準偏差を基準に、今日の変化が何σ離れているかを測る方法です。
閾値を動かすと、結果が総取り替えになる
合成データに5つの急変を仕込みました。−6.2%、−7.8% といった、 誰が見ても異常と言える下落です。これを検出できるか試します。
| 閾値 | 検出数 | 正しく検出 | 誤検出 | 見逃し |
|---|---|---|---|---|
| 1.5 σ | 58 | 5 | 53 | 0 |
| 2.0 σ | 27 | 4 | 23 | 1 |
| 2.5 σ | 14 | 4 | 10 | 1 |
| 3.0 σ | 8 | 3 | 5 | 2 |
| 3.5 σ | 5 | 3 | 2 | 2 |
| 5.0 σ | 3 | 2 | 1 | 3 |
5つとも検出できるのは σ1.5 だけ——ただし誤検出が53件つきます。 σ3.5 まで上げると誤検出は2件に減りますが、3つしか拾えません。
注目したいのは、どこにも「ちょうどよい」点が無いことです。 仕込んだ急変は −6.2% や −7.8% という、 誰が見ても異常と言える大きさでした。それでも取りこぼします。
適合率=「異常」と言ったもののうち、本当に異常だった割合。 再現率=本当の異常のうち、検出できた割合。 片方を上げると、もう片方が下がります。
| 閾値 | 適合率 | 再現率 |
|---|---|---|
| 1.5 σ | 9 % | 100 % |
| 2.5 σ | 29 % | 80 % |
| 3.5 σ | 60 % | 60 % |
| 5.0 σ | 67 % | 40 % |
どちらが痛いかは、場面で違う
| 場面 | 重く見るもの | 閾値 |
|---|---|---|
| サーバー障害の検知 | 見逃したくない(止まったら困る) | 低く |
| 相場の急変アラート | 誤報が続くと無視される | 高く |
| 不正取引の検出 | 見逃しの損害が大きい | 低く |
| 自動売買の停止判断 | 誤って止めると機会損失 | 高く |
同じ手法でも、用途によって正しい閾値が変わります。 「この手法の精度は◯%」という言い方が成り立たないのは、そのためです。
基準そのものが、動いている
ここからが本題です。閾値を固定しても、判定は安定しません。 σ という単位が、直近の変動の大きさに依存しているからです。
前半が穏やか、後半が荒れる合成データで確かめました。
| 期間 | 日次の標準偏差 |
|---|---|
| 前半 | 0.88 % |
| 後半 | 1.74 %(2.0倍) |
同じ下落が、違う扱いになる
前半 (i=139) スコア 2.93 σ ← 閾値σ3 なら、ほぼ異常 後半 (i=330) スコア 0.86 σ ← 平常の範囲
同じ 2% の下落です。それが 2.93σ にも 0.86σ にもなる。 後半はもともとよく動いているので、2% 程度は「いつものこと」と判定されます。
前回の 「学習窓を変えると答えが変わる」と、同じ構造です。 あちらは予測、こちらは判定ですが、 どちらも「何を基準にするか」で結果が動きます。
線を、引いてみる
閾値と基準の窓を動かせます。仕込んだ急変が検出されるか、 いくつ誤検出が出るかを見てください。実データでも試せます。
閾値を σ2.0 あたりまで下げると、検出が一気に増えます。 逆に σ4 まで上げると、ほとんど反応しなくなる。 その間のどこかに線を引く根拠は、データの中にはありません。
「正解」がないという問題
ここまでは仕込んだ急変を正解として数えてきました。 合成データだからできることです。
これは異常検知の根本的な難しさです。予測なら「翌日の値」という答え合わせができますが、 異常検知は正解ラベルを人が作る必要があります。
| やり方 | 問題 |
|---|---|
| 既知の事件を正解とする | その事件を検出するよう調整してしまう |
| 大きく動いた日を正解とする | 循環論法(大きい=異常と定義している) |
| 人が目視でラベル付け | 基準が人によって違う。量も作れない |
| 検出後に何が起きたかで評価 | 時間がかかるが、実用的 |
それでも、使うために
実務的に効きそうなことを、いくつか挙げます。
| やること | 狙い |
|---|---|
| 閾値を明記する | 「異常5件」ではなく「σ3で5件」と書く |
| 基準の窓も明記する | σ は窓に依存する。単位ではない |
| スコアをそのまま見せる | 二値にせず、連続値のまま提示する |
| 絶対値の条件も併用 | 「σ3 かつ −3%以上」で、荒れた時期の鈍化を補う |
| 検出頻度を監視 | 週1回を超えたら、閾値か基準を見直す合図 |
とくに絶対値との併用は、§4で見た「荒れた時期に鈍くなる」問題に効きます。 σ だけだと基準が動きますが、「−3%以上の下落」は動きません。
まとめ
3回にわたって、自分で公開したツールを測り直してきました。 予測の精度、学習期間、そして異常の判定。 どれも「モデルが出した答え」に見えて、 実際にはこちらが決めた前提の産物でした。
この記事のまとめ
- モデルが出すのは連続値。「異常」に変えているのは実装した側の線引き。
- 閾値 σ1.5 で誤検出53件、σ3.5 で見逃し2件。どちらも同じデータ、同じ手法。
- 適合率と再現率はトレードオフ。どちらを重く見るかは用途で決まる。
- 誤検出が多いと人が見なくなる。検出できることと役立つことは別。
- σ は基準の窓に依存する。同じ −2% が 2.93σ にも 0.86σ にもなる。
- 荒れた時期ほど検出されにくい。基準が直近から作られるため。
- 実データには正解がない。適合率も再現率も計算できない。
- 絶対値の条件を併用すると鈍化を補えるが、恣意性は置き場所が変わるだけ。
- 予測は、当たっているのか
「精度」という言葉が隠すもの - 学習期間を変えると、答えが変わる
窓幅の選び方と、1行のリーク - 「異常」は、誰が決めたのか(この記事)
閾値と基準の恣意性




