Amazon SageMakerのRandom Cut Forestで異常検知をする(shingling処理の検証)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

概要

こんにちは、yoshimです。
今回はSageMakerでビルトインアルゴリズムとして実装されている「Random Cut Forest」アルゴリズムを使って「異常検知」をしてみます。
また、時系列データの前処理の一種である「shingling」処理の有無で計算結果にどのような差異が生じるかを見てみようと思います。

目次

1.最初に

本エントリーは「SageMaker」の「Random Cut Forest」のチュートリアルを実際にやってみてその結果、解釈についてご説明するエントリーです。

そもそも「Random Cut Forest」とはなんぞや、という方は下記のエントリーをご参照ください。
AWSのドキュメント
Random Cut Forestの理論について
チュートリアルをやってみた

今回のエントリーは上記の「チュートリアルをやってみた」の続編といった位置付けです。
具体的には、前回は「1次元」のデータで異常検知をしていたのですが、これを「48次元」のデータに変更する(「shingling」という前処理をします)ことで結果にどのような違いが出るのか、ということを確認します。
(今回利用するデータは30分ごとのタクシー利用客数なのですが、これを48次元にすることで、24時間分のデータを1レコードに保持することになります)

「shingling」については、AWSのドキュメントをご参照いただきたいのですが、処理のイメージとしては下記の通りです。


参照:AWSのドキュメント

具体的には、下記のような変換をしました。

このような1次元の時系列データを

このように48次元に(見えないけど)

なぜ「shingling」のような前処理をするのかと言うと、「ノイズの影響を小さくできる」、「データの周期性をより良く反映できる」といった利点からです。

今回利用したコードがある場所は下記の通りです。

Gitだとこちらです。

2.実際にやってみた

では、実際にやってみようと思います。
今回は「shingling」処理の有無で結果にどのような違いがあるのかを確認します。

2-1.利用するデータについて

今回利用するデータは「NYCのタクシーの利用客数データ」です。
下記は実際のデータを上から5行表示しているのですが、このようにタクシー利用客数を30分ごとに記録したデータです。
2014年7月1日0時0分〜2015年1月31日23時55分まで記録してあります。

今回の主旨ではないのでこれ以上データの確認はしませんが、もし中身をもう少し確認したい場合はこちらの「3.やってみよう」をご参照ください。

2-2.今回設定したハイパーパラメータ

基本的にチュートリアルに設定してある通りです。

num_samples_per_tree=512
num_trees=50

もし各ハイパーパラメータの意味について関心がある方は下記をご参照ください。
rcfのハイパーパラメータ
Choosing Hyperparameters

2-3.全期間

ここからは同一期間における結果を「shingling」処理の有無で比較します。
まずは「全期間(2014年7月1日〜2015年1月31日)」での差異を見てみます。

「shingling」無

「shingling」有

青色の棒グラフが「乗客数」、オレンジ色が「異常値」です。
「異常」だと判断したポイントについては黒丸がついています。
(異常値スコアが平均から3標準偏差離れていたら異常、と今回は定義しています)

「shingling」処理を施すことで、全体的に異常値が落ち着いているのがわかるかと思います。
これは、「shingling」処理の結果、ノイズの影響が小さくなっているためと考えられます。

また、下記に「異常値スコア」が高い時間帯TOP10を「shingling」処理の有無でそれぞれ表示しているのですが、これを見ると「異常値スコア」が随分と変化していることがわかります。
(「score」が「shingling」無しの異常値スコア、「scores_shingled」が「shingling」有りの異常値スコア)

続いて、特定の時間帯に注目して、「shingling」処理による変化を見てみようと思います。

2-4.横軸=0~200

横軸だと0~200と表示されているのですが、日時でいうと「2014-07-01 00:00:00〜2014-07-05 03:30:00」の計算結果です。
見ての通り、「shingling」無しの場合はちょこちょこ「異常」と見なされるデータポイントが存在する一方、「shingling」有の場合は「異常」と見做すデータポイントはありませんでした。
「Random Cut Forest」は計算するたびに結果が変わってしまうのでなんとも言えないのですが、「shingling」処理によって外れ値の影響が小さくなったため、「異常」と見做すデータポイントが減ったことが要因である可能性が高そうです。

「shingling」無

「shingling」有

2-5.横軸=3200~3300

日時でいうと「2014-09-05 16:00:00〜2014-09-07 17:30:00」の計算結果です。
この期間も「2-4.横軸=0~200」と同じ考察ができそうです。

「shingling」無

「shingling」有

2-6.横軸=5900~6000

日時でいうと「2014-10-31 22:00:00〜2014-11-02 23:30:00」の計算結果です。
この期間では、「shingling」処理の有無で異常と見做すデータポイントが異なりました。

「shingling」処理をしない場合は「乗客数(青色の棒グラフ)」が大きいか小さいかだけで異常かどうかを判断している一方、「shingling」処理をした場合は「連続する48個のデータ」から異常かどうかを判断することになるため、このような違いが出たのではないかと思われます。

「shingling」無

「shingling」有

この結果だけを見ていても「横軸=5900~6000」の間を異常値と見做すかといった判断は難しそうです。
結局のところ「異常値を見つける目的」、「異常値を見つけてどのようなアクションに結びつけたいか」といった業務課題の整理をしないと「shingling」処理をそもそもするのか、「異常と見做す閾値」の設定、等の作業は難しいという結論になるのではないでしょうか?

(余談ですが、「Random Cut Forest」に限らず「異常検出系」のアルゴリズムは、よくそのような結論に陥りがちな気がします)

2-7.横軸=10000~10100

日時でいうと「2015-01-25 08:00:00〜2015-01-27 09:30:00」の計算結果です。
これも「shingling」処理の有無で随分と「異常値スコア」が異なります。
「shingling」処理を施した場合は、後続の48データポイントを含めて異常値スコアを計算するため、ちょっと早めから異常値スコアが大きくなっています。

「shingling」無

「shingling」有

3.まとめ

今回は「Random Cut Forest」アルゴリズムを使った異常検出において、「shingling」処理の有無による結果の差異について確認しました。
「shingling」処理をすることで外れ値の影響を小さくすることができるのですが、「2-6.横軸=5900~6000」の結果からわかる通り、結局のところ「業務課題の整理」の重要性を痛感する結果となりました。

4.引用

AWSのドキュメント
Random Cut Forestの理論について
チュートリアルをやってみた
ソースコード@Git
rcfのハイパーパラメータ
Choosing Hyperparameters