データ分析ガチ勉強アドベントカレンダー 22日目。
今日は、データ分析の練習も兼ねて、ちょっとした実験!! 対象は最近話題の仮想通貨。 乱高下の激しい通貨に対して、データ分析技術がどこまで通用するかと言うのを検証してみる。
使う技術 : Change Finder
change finder とは、データマイニングによる異常検知に出てくる、変化検知の技術。
ざっくりいうと、データをある時系列モデルで予測し、そこからの変化具合を評価する手法
全体の流れ
- 窓幅kで時系列モデル(ARモデル)を用意してSDARアルゴリズム(忘却型学習アルゴリズム)で学習する
- 時刻からまでの値で、それ以降の時系列を予測するモデルが完成する
- 時系列モデルの学習は SDARアルゴリズムと統計的手法による時系列からの外れ値と変化点の検出が、詳しい。単なるARモデルの推定ではなくて、より新しいデータを重視する**忘却機能がついている
- 忘却機能がARモデルでは許されない非定常性のモデルも許す。
- 上記の時系列モデルに対して、時刻での異常値スコアを次のように算出
- もしくはヘリンジャースコア(参考)
- 幅Tのウィンドウを設けて、スコアの平均を計算する(smoothing)
- 時刻での移動平均スコアは、下式
- 平滑化された時系列データに対して、再度ARモデルを用意してSDARアルゴリズムで学習する
- 時刻からまでの値で、それ以降の時系列を予測するモデルが完成する
- 幅のウィンドウを設けて、スコアの平均を計算する(下式)
ポイントは、2回学習しているところ。一回目のsmoothingで、ノイズに反応した外れ値の除去を行っている。 そのため、本質的な変動を捉えられるようになっている。
SDARで設定する忘却パラメータはかなり大事で、どのくらい過去の影響を重視するかに関わってくる。これについては後で見てみる。
ライブラリ
何気なく「changefinder python」で調べると、作っている素晴らしい人がいた。
なので拝借。上記ページにも書かれているように、numpy
, scipy
, nose
, statsmodels
は必要
pip install changefinder
で入る。二種類のアルゴリズムが用意されていて、通常のChangeFinder
と、ARモデルをARIMAモデルに変更したChangeFinderARIMA
*1
ChangeFinder
changefinder.ChangeFinder(r=0.5,order=1, smooth=7)
主要パラメータは下記の通り
r
: 忘却パラメータsmooth
: 外れ値スコアをsmoothingするための区間長order
: 時系列モデルの次数
実験に使うデータ
- 12/13-12/21の仮想通貨の価格データ ((githubの
coindata.csv
に保管している)) - 草コインも含めて868銘柄のデータを10分おきに保管している
データの集め方については以前記事にしたAPIを使っている。
コード
詳しくは、githubに上げている。 github.com
銘柄を指定し、changefinderにかけてグラフ表示するまで
%matplotlib inline import changefinder import pandas as pd from datetime import datetime as dt import matplotlib.pyplot as plt import numpy as np import os def str2datetime(tstr): if tstr.__class__.__name__ == "datetime": return tstr ts = tstr.split(".")[0] return dt.strptime(ts, "%Y-%m-%d %H:%M:%S") def calc_cf(name, df, cf, threshold=30): values = df[name].values scores = np.array([cf.update(value) for value in values]) print(scores) # 描画 fig, ax1 = plt.subplots(figsize=(15,5)) ax1.set_title(name) ax1.plot(df.index, scores,color="red") ax1.set_ylabel("anom_score") ax2 = ax1.twinx() # 2つのプロットを関連付ける ax2.plot(df.index, df[name].values) ax2.set_ylabel("value") # しきい値越えリスト df["score"] = scores - threshold for i in range(1,len(df)): if df.iloc[i-1]["score"] < 0 and df.iloc[i]["score"] >= 0: print("time:{}".format(df.iloc[i]["timestamp"])) ax2.plot(df.index[i],df.iloc[i][name],"o") plt.show() return df cf = changefinder.ChangeFinder(r=0.01, order=1, smooth=3) df = pd.read_csv("coindata.csv").dropna() df.index = df.timestamp.apply(str2datetime) calc_cf(name="btc",df=df, cf=cf, threshold=15)
実行結果
r=0.01, order=1, smooth=3
で実行してみた。結果がコチラ
ふむ、一見よく捉えられているようにも見える。 でも、実際はそんなに簡単じゃない。
パラメータによる違い。
r=0.01, 0.02, r=0.05
で試してみる。結果は↓
r | グラフ |
---|---|
0.01 | |
0.02 | |
0.05 |
忘却パラメータに関しては、与えるパラメータによってかなり変わってくる。 センシティブなので、ナゾの場所で変化検知する場合もあり、シビアな調整が必要そうだ。
また、r=0.01, order=1
は固定で、smoothを3と18で比べてみた。
smoothing | グラフ |
---|---|
3 | |
18 |
やはり平滑化をしすぎると、反応は遅れるのだなという感じ。しかし、結構変化に敏感に反応はできているという印象を受けた。
注意したいのが、グラフの縦軸は全然値が変わっているところ。この辺のしきい値の調整もシビアそう。
結論
暴騰暴落を捉えられたか?
- 正直微妙
- ピークが捉えられたとして、少し反応が遅れると暴落に飲み込まれる
- 後述するパラメータ調整がシビアすぎる印象
って感じ。正直、強いトレンドを見るならボリンジャーバンドでいいのでは?って思った。 そう思って、ボリンジャーバンドでもトレンド検知をしてみた。結果がこれ(赤が買いトレンド、青が売りトレンド)
若干ミスってはいるものの、トレンドを割と追従できてる気がする。真ん中の2点は要らないけど、超安定してたから仕方ない気もする。sigmaの絶対値でしきい値設ければ弾けそう。 これもパラメータ調整が難儀ではあるが、changefinderよりも直感的になので、やりやすそう。
モデルに関して
- 特に忘却係数の調整がシビア
- 基本的に反応は早めだが、smoothing次第で遅れる。ノイズとの兼ね合い
- スコアもパラメータによって変わるので、相対的な判断が強いられる
あたりが難しそうだなと思ったところ。探索的に調べたが、なかなか直感にバシッと合うようなものは見つけられなかった。 パラメータの調整方法としては、Day15で書いたベイズ的最適化を使ってやってみるのも面白いと思うので、もうちょっと良いパラメータを見つけたいトコロ。
*1:ARIMAは計算が重い&非定常な時系列に対して時間窓を区切ってARIMAモデルを独立に作成しているので、モデルの妥当性は不明とのこと。