時系列データで自分の生活と向き合う

PyLadies TokyoのAdvent calendarで久々に記事書きます。

今回は悩んだ結果、時系列データで遊んだことを書こうと思います。

状態空間モデルっておいしいの?

状態空間モデルって最近よく耳にするんです。時間的変化を扱う時系列分析という領域で特に良く聞く訳で。でも、それがどんなモデルなのかとか、時系列分析の定石ARIMAとかとどう違うのかとか、気になっていました。

せっかくだからPythonで噂の「状態空間モデル」をやってみたので、それを徒然と書こうかなと思います。

ちなみに今回の記事に関しては、基本的な時系列分析の知識については扱いません。ごめんなさい。
そして「状態空間モデル」についても、すごく細かいアルゴリズム的なものもあまり触れないのです。なんとなく状態空間モデルがイメージできるところを目指してみます。

もともとは制御工学の分野みたいで、入力があって出力がある中で状態変数というものを仮定した方程式で表す数理モデルです。
制御工学とか言われると難しくて泣きそうになるので、時系列分析として理解を深めていきたいと思います。
時系列って領域でいうと、時系列のデータの中に潜んでいる真の状態と呼ばれる因果を特定して、モデル化していく手法です。


状態空間モデルは2つの式で表すことができます。

y_{t} = H_{t}x_{t} + w_{t} \label{math::kansoku}
x_{t} = F_{t}x_{t-1} + G_{t}v_{t} \label{math::joutai}

上の式を観測方程式、下の式を状態方程式といいます。

簡単に言うと、実際に観測した値というのはそこに「真の状態」というものが隠れていて、それに何らかの観測ノイズが入っていると考えます。そして「真の状態」は、過去(前の時点)から影響を受けたものに状態ノイズ(システムノイズ)というものがプラスされているということです。

例えばとあるKananの日々のビールの消費量を考えたとします。
Kananは誰かと飲みに行くのが好きで、毎日飲みに行くチャンスを伺っています。
しかし仕事も忙しい時期は残業で飲み始める時間も遅くなります。
この場合、Kananのn時点の「真の状態」はn-1時点のビール消費量(忙しさ)をベースに何らかのノイズを加味して推測できます。これはランダムウォークと呼ばれる考え方です。そしてn時点の「真の状態」に観測誤差があって実際のn時点の観測値になります。観測誤差というのは、料理をするときに10mlの調味料を入れる際に測って入れても寸分狂わずぴったり10mlを入れることはできません。誤差は理論上0mlを平均とした正規分布で発生することになります。

そして、この2つの式は同時確率問題となり、マルコフ性を仮定して分解することで計算可能な式にするといったベイズのジャンルでもあります。

では状態空間モデルってどのへんがNiceなのでしょう。
私が解釈した良いところひとつめは、多変量として扱うことができること。これはVARモデルもそうです。
ふたつめは、ひとつめと重なりますが、ドメイン知識を組み込んでいくことができる。これが一番大きいのかなと思います。
そして最後は時系列特有の定常化等の前処理をせずにモデルを作ることができます。

とりあえずどんなものかやってみないとわからないので、LET'S CHALLENGEしてみたいと思います。

環境は、Windows 10のAnaconda 4.6.12(Python 3.7.0)を使用します。
状態空間モデルはstatsmodelsのUnobservedComponentsで実装することができるので活用することにします。

Kananがどれほどにビールを飲むのかざっくりデータを理解する

時系列系のサンプルデータで有名なのはナイル川の水量のデータやアイスクリームの売上のデータ等があります。
でも今回は独自のデータを使ってやってみたいということで、とあるKananのビール消費量のデータを用意しました。
2019年2月から2019年5月までのデータで、ビールのみの消費量が記録されています。もちろん厳密な数値ではなくどのくらいの大きさのジョッキ(または缶)を何杯くらい飲んだかで算出しています。でも毎日記録しているので、ボリューム的にはざっくり正しいデータとなります。

f:id:asunasa:20191205121118p:plain
kananのビールの3ヶ月間の消費量

グラフにしてみると、まぁほぼ毎日飲んでいますね。
毎日飲んでいますが、なかなか振れ幅が大きい感じがします。
なさそうなのはぱっと見わかりますが、この時系列データに自己相関関係があるかを確認してみたいと思います。
自己相関というのは元のデータと元のデータをずらしたデータとの相関を指します。
自己相関はstatsmodelsのstattools.acf、偏自己相関はstattools.pacfを使用して算出し、matplotlibで描画してみます。

f:id:asunasa:20191205121316p:plain
時系列データの自己相関を確認

これだけガタガタしているとやはり相関係数としては高い値は出てきませんが、中でも値の高いところや低いところの感覚を見てみると7の周期性のようなものがありそうな気がします。
そこで、statsmodelsのseasonal_decomposeでトレンド成分や季節成分を一応見てみることにします

f:id:asunasa:20191205121445p:plain
トレンド成分と季節成分、残差に分解

一番上のグラフがオリジナルのデータです。
次がトレンド成分、その下が季節成分、そして最後に誤差がグラフになっています。
トレンド成分は大まかな傾向を表していますが、4月末が結構上昇しています。ここは2つのカンファレンスに参加する為にアメリカに滞在していた期間です。現地に仲間も多かったので、大いに学び、大いに飲んだくれたということでしょう。
続いて季節成分ですが、やはり7の周期性が抽出されています。低いところはたぶん週末です。週末はイベントかなにかあると外に繰り出して飲みますが、家に引きこもっているとKananはほとんど飲みません。誰かと飲みに行くのが好きなのです。
ただこの季節成分は誤差と比べて値が低いので、周期性としては若干の傾向があるといったところでしょう。

あ。状態空間までたどり着けてないですが、次回は状態空間モデルを使ってこのデータをフィッティングしていきたいと思います(先は長そうだ)