fluent-plugin-anomalydetect 作りました

jubatusでも異常値検知がリリースされたばかりですが、簡単でメモリも食わずに異常値検知できるといろいろ捗るかなぁと思い、異常値検知のpluginを作りました。

一日動かしてみましたが、手元の環境では特にリークもなく、fluentd本体、このplugin、node.js expressを立ち上げ、abで適当に負荷をかけ続けましたが、全体で60MBくらいでした。

<match access.**>
    type anomalydetect
    tag anomaly.access
    tick 86400
</match>

こんな感じで設定すると、tickで指定した時間(秒)にaccess.**に入ってくるデータ数を数えてそれの異常値をスコアリングします。 また

<match access.**>
    type anomalydetect
    tag anomaly.access
    tick 86400
    target fieldname
</match>

こんな感じにすると、targetで指定したfieldの値をtickで指定した時間の間の平均値に対する異常値をスコアリングします。

結果

{time: XXX, outlier: 0.354, score: 0.1335, target: 3543.33}

結果は上のような形式で出力され、それぞれの意味は下記のようになります

  • target: 異常値を検出する対象となる値 (平たく言うと入力値)
  • outlier: targetの異常値
  • score: outlierだけだとピークが立ちすぎるので平滑化してそれの異常値をとるとかごにょごにょした結果の値<=ここを見る

異常検知(変化点検出)のパッケージを作ってみたでの株式のデータで試してみると実装がarimaとSDARで異なるためにピークの立ち方は異なりますが、グラフの定性的な形式は同じようになっていたので、あってると思います(が、間違ってることに気づかれたら教えて下さい

また、arimaと違い、結構いくつかパラメタのチューニングが必要となります。

詳細なパラメタ

    outlier_term 7
    outlier_discount 0.5
    smooth_term 7
    score_term 28
    score_discount 0.01

理論のところで参照した本をあたっていただけるとわかるのですが、SDARは過去のデータの重みを割引つつ、特定の窓のデータを処理することで計算量を減じて、処理速度をあげています。 そのため、これらがパラメタとして存在し、チューニングが必要になります。

うまくピークが立たない場合はpluginの設定でこれらの値を適当にいじってみてください。

理論

データマイニングによる異常値検知にある、SDAR (sequential discount AR)をそのまま素で実装しました。 過去のデータを割引ながら、特定の窓でARモデルを作成し、それに対して入力値が生起する確率を計算し、負の対数値=対数損失をスコアとしています。 デフォルトでは窓のサイズは28にしていますが、この値が大きくなればなるほどメモリも計算量も増えます。 が、arimaや系列全てからモデルの変化点を検出するものと比べればデータのサイズに対しては定数の計算量でかたがつくので、fluentdには向いていると思います。

TODO

  • 閾値のセット:これを超えた時だけ出力するようにすれば、これをikachanとかtwitterに飛ばして捗る
  • FFTとかで周期イベントのキャッチ:せっかく計算量を減じたんですが、これだと敬老の日とかのイベントをキャッチできないので、なんとかしたいなぁと
  • 損失関数の切り替え:いまは大数損失だけを実装していますが、ヘリンジャースコアとかに切り替えたほうがいい時もあるだろうと思います

追記

あ、あと、僕のクリスマスもまだ終わっていません・・・(白目

追記2

CROSS2013データ解析の専門家も、ログを取る専門家も、ログを視覚化する専門家も、話をしてくれるので、来たらいいと思います。