LoginSignup
43
43

More than 5 years have passed since last update.

異常検知でGo!

Last updated at Posted at 2014-11-30

異常検知でGo!

こんにちは。ちょびえです。4日めですがいかがお過ごしでしょうか?
今日はGoで異常検知を試してみましたのでレポートしてみたいと思います。

異常検知の世界

ふつうのWebプログラマーの私がデータマイニングによる異常検知読んで、機械学習ってなんて便利なんだろう!?と驚いたと共に機械学習の魅力に引き込まれていきました。

https://github.com/muddydixon/fluent-plugin-anomalydetect のSDAR部分を再実装したものです。私は高校をドロップアウトしてるので線形代数周りの理解・実装でだいぶ難儀しましたが、良き実装があればなんとかなるもんだなぁ、、、とw

anomalydetectorはChangeFinder部分のスムージングなどの実装は含んでいないのでこんな感じで作ってみてください。

package main

import (
    "fmt"
    "bufio"
    "strconv"
    "os"
    "strings"
    anomalydetector "github.com/chobie/go-anomalydetector"
)

type ChangeFinder struct {
    O         *anomalydetector.AnomalyDetector
    S         *anomalydetector.AnomalyDetector
    Smooth    int
    Last      float64
    LastScore float64
    Buffer    []float64
    Buffer2   []float64
}

func sum(array *[]float64) float64 {
    sum := 0.0
    for _, value := range *array {
        sum += value
    }
    return sum
}

func (finder *ChangeFinder) Update(v float64) float64 {
    var score float64 = 0.0

    if v == finder.Last && finder.LastScore < 3.0 {
        score = finder.LastScore
    } else {
        r := finder.O.Update(v)
        finder.Buffer = append(finder.Buffer, r)

        if len(finder.Buffer) > finder.Smooth {
            finder.Buffer = finder.Buffer[1:]
        }

        score = finder.S.Update(sum(&finder.Buffer) / float64(len(finder.Buffer)))
    }

    finder.Last = v
    finder.LastScore = score

    return finder.LastScore
}

func NewChangePoint(outlier_term int, outlier_discount float64, score_term int, score_discount float64, smooth_term int) *ChangeFinder {
    v := ChangeFinder{}
    v.O = anomalydetector.NewAnomalyDetector(outlier_term, outlier_discount)
    v.S = anomalydetector.NewAnomalyDetector(score_term, score_discount)
    v.Smooth = smooth_term

    return &v
}

func main() {
    p, err := os.Open("go.tsv")
    if err != nil {
        panic(err)
    }
    defer p.Close()

    cp := NewChangePoint(12, 0.0275, 6, 0.1, 12)
    scanner := bufio.NewScanner(p)
    for scanner.Scan() {
        args := strings.Split(scanner.Text(), "\t")
        result, err := strconv.ParseFloat(args[1], 64)
        if err != nil {
            panic(err)
        }
        score := cp.Update(result)
        fmt.Printf("%s\t%f\t%f\n", args[0], result, score)
    }
}

Google TrendでGolangを検索した結果を下記にはりつけておきます。ダウンロードしてgo.tsvで保存して置いてください。
https://gist.github.com/chobie/16b15c35f8452ed8d59f

それでは実行結果をExcelでPlotしてみたいと思います。スコアはそのままだと小さくて読みづらいのでなんとなく自乗しときました。

Screenshot_11_30_14__22_54.png

2008/9は記憶にありませんが、2009/11といえばコレですね

それじゃ、Happy Hacking

43
43
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
43
43