カルマンフィルタのアドテクへの応用(理論編)

カルマンフィルタという数理手法がロケットの姿勢制御等で良く使われています。これをアドテクに応用できそうに思うのでシェアしてみます。

カルマンフィルタと関連手法(知ってる人は飛ばして次へ)

カルマンフィルタは一言でいうと「連続値の隠れ変数についてのモデルが既知でそれが線形で不定性をガウスノイズでくくれるような問題」に適用可能な手法です。

データサイエンティスト的な手法分類としては、線形じゃなくて非線形だったら粒子フィルタというのを使いますが、粒子フィルタはサンプリングといって乱数でシミュレートしてあたりをつけるみたいな方法なのに対して、カルマンフィルタは次の推定値を式一発でビシッと出してくれる(そういうのを「閉形式で解析的に求まっている」みたいな言い方をします)ので線形モデルで近似できそうならば線形モデルを使うことの利点はかなりあります。

隠れ状態が連続値でなく離散値だったら隠れマルコフモデル(HMM)というのを使います。離散値にガウスノイズもくそもないのでHMMの場合は状態遷移のモデル自体を多項分布で表現します*1

適用方針

カルマンフィルタにおける隠れ状態を「オーディエンス(1名でもいいし、DMPで作ったセグメントとかでもOK)の興味ベクトル」とします。興味というのは例えばアニメが好きだとか、ユニクロというブランドが好きだとか、そういうカテゴリ選好度やブランド選好度だと思ってください。

それとカルマンフィルタは隠れ状態の時間遷移を表す線形変換を指定可能なので「速度」という状態も入れましょう。そうすれば「アニメへの興味が日に日に増している」みたいな各興味要素の変化のスピードを加味できます。

変換行列は対角成分近辺以外はゼロな感じになりそうではありますが対角以外の部分の意味を考えると、競合ブランドの選好度をモデルに組み入れて自社ブランドの速度成分を競合への興味のマイナスとして影響させるようなこともできそうです。

つづいて観測変数ですが「広告への反応ベクトル」とします。おもにクリックやコンバージョン、可視領域の滞在時間とかでもいいかもですね。ベクトルの次元はそれぞれの広告バナーになるので、分析対象とするバナーの種類の数が次元数になります。

そして興味ベクトルから反応ベクトルが導びかれるメカニズムを線形変換(行列)として与えます。この行列は、各広告が反映する興味要素を並べたものになるでしょう。この行列を天下り的に与えないといけないところが難点ですが、とりあえずここは試行錯誤の強い要素だと割り切ることにします。(カルマンフィルタの観測モデル自体をベイズ推定する手法をもし知ってる人いましたら勉強ポイントなど示してもらえるとうれしいです。)

ざっくりとした話になりましたが、以下詳細を見ていきます。

モデルにアドテク変数をあてはめる

まずは興味ベクトルの時間遷移。

x_t = F_1*x_{t-1} + F_2*u_t + F_3*w_t

x_tは時刻tにおける興味ベクトル、F_1は上で述べた興味ベクトルの時間遷移です。(時刻tというのは単位時間を表すことにして、例えば1分とか、1時間とか、1日単位とか、分析案件に合わせて設定します。)

u_tの項は上述では触れてませんでしたがロケットでいうとハンドルを切ったりエンジンを噴射したりする制御要素なので、アドテクでいうと「広告を見せた」ということを表すことにして、広告ベクトルと呼びましょう。もし単位時間内に一つも広告を見せなかったらゼロベクトルですし、複数の広告を見せたら複数要素がノンゼロなベクトルです。この広告ベクトルの次元は上述した反応ベクトルの次元と同じです。

F_2は広告ベクトルから興味ベクトルへの変換行列です。とりあえず簡単のため、上で述べた次元が同じである反応ベクトルへの変換行列H(下で出てきます)転置行列(を適当にスケールしたもの)F_2 = \alpha * H^{T} (0 \leq \alpha)でいいでしょう。

w_tは多変量ガウスノイズです。これは意味的には一時的な興味の変動で、例えばソーシャルメディアでバズったので一時的にあるテーマへの興味が高まるみたいな外乱や、たまたまモデルの外できっかけが起きて何かに興味を持ったりとかいうのを加味する要素です。ここもいろんな要素を加味しようと思えば上の式のとおりにF_3を導入して次元数の多い多変量ガウスノイズから射影させることも可能ですが、とりあえず最初は単位行列F_3 = Iとしてw_kは興味ベクトルの次元数の分だけ多変量ガウス分布w_t \sim N(0,Q)(Qはノイズ生成用の共分散行列)で生成します。

さて、続いて観測モデルです。

 z_t = H*x_t + v_t

z_tは反応ベクトル、Hは興味ベクトルから反応ベクトルへの変換行列で、上述した意味合いのものです。v_tは観測ノイズでv_t \sim N(0,R)です。

なお、wikipediaを見るとF,H,Q,Rなどの行列はすべて時間に依存する形で書けるみたいですがここではとりあえずこれらは固定としておきます。

予測更新式

前節のようにあてはめた場合の予測式を書き下します。カルマンフィルタが計算してくれるのは、現在時刻の予測値x_tとその誤差の共分散行列P_tです。

誤差が共分散行列で出てくるというのはイメージ的にいうと、多次元空間上にあるベクトルx_tというのがあって、そのベクトルの矢印のさきっぽを中心として小さなラグビーボールが何らかの方向へ傾いた状態で固定されているような状態です。ラグビーボールの範囲がばらつきの大きさの等高線みたいな感じです。なのでラグビーボールがどんどん大きくなって行ってしまったら困りそうですが、観測変数z_tで順次補正をかけていくのでうまくいい感じの誤差におさまってラグビーボールが爆発したりしないのでしょう。たぶん。

そしてまず最初に、その初期値x_0P_0を与える必要があります。もし初期ベクトルがはっきりわかっていればラグビーボールはゼロ行列でよく、逆に初期ベクトルに不確実性がある場合は適度な大きさのラグビーボールで出発します。

そうしたときの興味ベクトルの予測式が以下になります。

  • x_t = F_1*x_{t-1}+F_2*u_t
  • P_t = F_1*P_{t-1}*F_1^T+Q (Tは転置)

ラグビーボールのイメージで考えるとQの項が単純に足し算になっているのがイメージ出来たりして良いですね。

そして反応ベクトルを得たときに興味ベクトルを更新する式が次に来ます。カルマンフィルタ(をはじめとする状態空間モデルにおいてフィルタリングを呼ばれる手法)では観測データの取得前(予測)と取得後(更新)とを分けて考えるのがポイントです。カルマンフィルターはビフォア・アフター、と覚えるといいかもしれません。なので更新ステップとして、上で予測した興味ベクトルと誤差行列を、反応ベクトルを加味した以下の式で上書きします。

まず以下のようにテンポラリ変数を計算しておいて

  • e = z_t - H*x_t
  • S = R + H*P_t*H^T
  • K = P_t*H^T*S^{-1}

それを使って

と更新します。

これで理論が出来上がりました。

続きは実践編で

次回は具体的なデータをでっち上げて実験したものをシェアします。

*1:ちなみに僕が修士課程でやった研究は、統計モデルをPrologで記述するとEM学習やサンプリングなどを自動的にやってくれるPRISMというプログラミング言語を使って将棋倶楽部24のの棋譜DB約24万局の表層的なモデリングをするというもので、対局者が強いか弱いかをシステム側で先読みを一切せずに一連の指し手の雰囲気だけから85%くらいの精度で推定できたのでした。PRISM言語はHMMやベイジアンネットや確率文脈自由文法といった、尤度関数が離散多項分布で表現可能な統計モデルであればPrologプログラムとして表現可能という優れものです。HMMとベイジアンネットを融合したダイナミックベイジアンネットワークとかでもさらっと記述できてEM学習が自動でできます。開発されて15年以上たつのに全然流行ってないのが残念ですが。