読者です 読者をやめる 読者になる 読者になる

F@N Ad-Tech Blog

株式会社ファンコミュニケーションズ nend・nex8のエンジニア・技術ブログ

季節変動を考慮した異常値の発見をやってみた話

ご無沙汰しています。情報科学技術研究所のy_kawasakiです。今回も無事、Blogを書くタイミングで所属名が変わってます。これで、今までの投稿ですべて違う、所属名(≠所属)で記事を書いています。

やりたいこと

例えば、imp数の監視をしたいということがあると思います。しかし、imp数は季節トレンド(例えば、時間帯や曜日に応じての変化)、さらには、長期トレンド(例えば人気記事の追加など)、さらに突発的な変化があります。そこで、それらを分解して監視すれば、突発的な変化なのか、実はトレンドの変化なのかということが追えるはずです。

やったこと

長期トレンド

これは、簡単に n 日間移動平均を取ってやります。n 日間の n をいくつにするかがミソです。あんまり短いと、何のトレンドを取っているのかわからなくなります。あんまり長いと、追従に時間がかかりすぎてしまいます。適当にいい塩梅にエイヤッと決めればいいと思います。グリッドサーチ的にいろいろ試してみるのもありだと思います。

季節トレンド

季節と言っていますが、別に季節でなくても、曜日でも時間でもいいです。imp数から、長期トレンドを除いたものを、FFTとか使ってかっこよく周期を求めてもいいのですが、どうせ、時間帯に依存していることは、データを見れば一目瞭然だったので、ここでは、時間を季節トレンドとして、分離します。これもまた適当に、前 n 回の同じ時間の平均を求めてあげます。前 n 回の n をいくつにするかがミソです。(以下ry。まぁ、長期トレンド程は感覚的には効きませんので、適当でOKです。

残差

imp数から、長期トレンドを引いて、季節トレンドを引いたものを残差とします。これが、毎回の変動になります。ここまで求めれば、この残差が大きすぎるとか、小さすぎるとかで異常があるとか判定すれば良さげな感じになる気がします。例えば、平均と標準偏差で2σを超えたらアラートをあげるとか、確率分布に変換して、信頼区間を求めてその範囲外になれば、アラートをあげるとか。この辺はお好みに応じて、いろんな手法をやればいいと思います。

イメージ図

実際に適用するとこんな感じ。

f:id:fan_y_kawasaki:20161220151608p:plain

やってみて

パラメータの調整にいろいろ手こずりました。捕捉率はいいのですが、オオカミ少年になってしまってた時期がありましたが、最近は安定して運用できています。

モデル自体は超簡単なので、実装も簡単でした。ちなみに、scikit-learnにもあるのですが、移動平均が、前方移動平均ではなかったので、若干使いづらく、自前実装しました。状態空間モデルということで、カルマンフィルターを使うということも検討したのですが、あまり結果は良くなく、単純な方法での実装に落ち着きました。ちなみに、Rだとdecompose関数でやれたりします。

今後の課題

このモデルだと祝日が考慮されていませんので、本当は、考慮したいところです。さらに、障害が発生した場合は、トレンドから抜くとかの処理もしたいのですが、現状やっていません。やっていなくてもそれなりにうまいこと動いているので、これはこれでいいのかなぁと思っています。

終わり。