はじめに
共立出版のOne point シリーズの野村俊一(著)「カルマンフィルタ」を読みました。
カルマンフィルタ ―Rを使った時系列予測と状態空間モデル― (統計学One Point 2)
- 作者:野村 俊一
- 発売日: 2016/09/08
- メディア: 単行本
最後に粒子フィルタに触れています。
昔に、岩波データサイエンスVol.6で概要だけ知っている状態だったため、簡単にまとめてみました。
非線形非ガウス状態空間モデル
一般的な状態空間モデルは次にように表現される。
上から順に、状態に依存して観測値が生成される観測モデル、 状態から状態の遷移を表現したシステムモデル、 初期状態分布を構成する式である。
ここで、各時点のおよびのは条件付き確率密度関数あるいは条件付き確率関数, は初期状態の周辺確率密度関数である。
観測モデルに関して、同時点の状態を与えれば、それ以前の状態と観測値は依存しない。
また、システムモデルでも、同時点の状態を与えれば、それ以前の状態と観測値は依存しない。
上記の性質は時系列モデルにおけるマルコフ性と呼ばれている。
線形ガウスモデルの状態空間モデルに対する処理は、推定する状態や予測値の条件付き分布が全て正規分布であったため、条件付き平均と条件付き分散を推定できればよかった。
しかし、非ガウスモデルでは、条件付き分布の特定には確率関数の推定が必要になる。
以下で示す漸化式は確率密度関数を逐次計算するものとなる。
フィルタリング漸化式
各時点における、フィルタ化密度と状態と観測値の1期先予測密度, は、以下の漸化式1~3を順に繰り返すことで得られる。
- 観測値の1期先密度関数を用いてフィルタ化密度
- フィルタ化密度から状態の1期先予測密度の算出
- 状態の1期先予測密度から観測値の1期先予測密度を算出
状態平滑化漸化式
先に示したフィルタリング漸化式の結果を用いて観測値が与えられたもとでの状態の状態平滑化密度をえる。
予測漸化式
について、状態の期先の予測密度 と、 観測値の期先の予測密度 は、以下の漸化式1と2をの順に繰り返すことで得られる。
- 状態の期先の予測密度から状態の期先の予測密度を算出
2.状態の期先の予測密度から観測値の期先の予測密度を算出
粒子フィルタ
ここまでの漸化式は非線形非ガウス状態空間モデルにおいて、積分計算が解析的に不可能である。
そのため、非線形非ガウス状態空間モデルでは粒子フィルタと呼ばれるフィルタリング手法を用いる。
粒子フィルタによるフィルタリング
の順に、一時点前のフィルタ化分布からのサンプルを元に、時刻のフィルタ化分布からのサンプルを以下の1~3の手順を繰り返し得る操作を取る。
なお、観測値が欠損している場合は手順2,3をスキップする。
1.1期先予測サンプリング において、前時点の状態を とおいた時の1期先予測分布からサンプルを一つ抽出してとおく。
尤度による重み付け において、観測値に対する尤度を、サンプルに対する重みをする。
サンプリング サンプルとその重みから、次のインポータンスサンプリングを行い、重複を許したN個の状態サンプルを抽出する
3-1.割り当て関数の作成 に対して累積相対重みを次のように定義する。
そこからに対する割り当て関数を次にように定義する。
3-2.層化サンプリング 区間(0,1)上の一様分布からの1つのサンプルを抽出し、の値に基づいてから次のようにリサンプリングを行う
これは、尤度の低い外れ値のようなサンプルを高確率で除き、尤度の高いサンプルを重視することを意味する操作である。
図で示すと次にようになる。
粒子フィルタによる状態平滑化
粒子フィルタの結果からでは平滑化することができない。
そのために、固定ラグ平滑化という方法が提案されている。
観測値が得られたもとでのL時点前の状態を条件付き分布からサンプリングを行うことで、平滑化状態分布からの近似サンプルとして利用する方法である。
固定ラグ平滑化では、時点の状態に対して、時点前までの状態を結合した、拡大した状態ベクトル に対して粒子フィルタを実行する。
具体的には粒子フィルタの手順1を次のように行う。
1'. 前時点の状態サンプルの最初の要素を用いた1期先予測分布からサンプルを一つ抽出してとおく。
それを前時点の状態サンプルと結合してとおく。
そして、2以降の手順をフィルタリングの時と同様に行う。
現在の尤度を用いて過去の状態に対してサンプリングを適用することを繰り返すことになる。
これにより、時刻L先までの状態の尤度が高くなるように多くのサンプルが消滅することになる。
粒子フィルタによる状態予測
期先予測は、1期先予測サンプリングをまでを繰り返すことで可能である。
Rで粒子フィルタ
こちらの記事に掲載されているコードを参考にさせてもらいました。
ぞれぞれの関数を次にように作成しました。
# 尤度計算 likelihoods = function(xt,yt) { return(exp(-(yt-xt)**2)) } # リサンプリングを行う関数 resampling <- function(x,w) { # input dim(x) = (N*M,D) # --> output dim = (D,N) N <- length(x) wsum <- c() for (i in 1:N) { wsum <- c(wsum,sum(w[1:i])) } total <- sum(w) pos <- (1:N) * total/N r <- runif(1,0,total) # roulette pos <- (pos+r) %% total point <- c() for (i in 1:N) { j <- which(wsum>=pos[i])[1] point <- append(point,j) } return(point) } fixedlag_smooth <- function(X, XX, t, point, width){ for (w in 1:(width-1)) { tmp <- t-(width-w) if(tmp<1){ tmp <- 1 } #message(tmp) XX[[tmp]] <- XX[[tmp]][point] } XX[[t]] <-X[point] return(XX) } # フィルタリングを行う関数 particle_filter <- function(y, x0, N, sys.nois) { tmax <- length(y) D <- length(x0) # == ncol(y) xx <- list(rep(x0,N)) for (t in 1:tmax) { #message(t) x <- xx[[t]] + rnorm(N, 0, sys.nois) w <- likelihoods(x, y[t]) sp <- resampling(x, w) xx[[t+1]] <- x[sp] } return(xx) } # スムージングを行う関数 particle_smoother <- function(y, x0, N, L, sys.nois) { tmax <- length(y) D <- length(x0) # == ncol(y) xx <- list(rep(x0,N)) for (t in 1:tmax) { #message(t) x <- xx[[t]] + rnorm(N, 0, sys.nois) #t+1の状態のサンプリング(予測) w <- likelihoods(x, y[t]) # 尤度の計算 sp <- resampling(x, w) # リサンプリングでインデックス取得 xx <- fixedlag_smooth(x, xx, t, sp, L) # xx[[t+1]] <- xx[[t]] } return(xx) }
今回適用したデータは岩波データサイエンスVol.6で用いられているデータをサポートページから持ってきました。
真の状態の変化と観測値を確認してみます。
時刻20付近で大きくトレンドがシフトしています。 その後、緩やかにトレンドがドリフトしていることを確認できます。
上記で定義した関数を用いて、フィルタリングを行ってみました。
resFil <- particle_filter(y = dat$y, x0 = -0.5, N = 5000, sys.nois = 0.2)
そして、上記で定義した関数を用いて、スムージングを行ってみました。
resSm <- particle_smoother(y = dat$y, x0 = -0.5, N = 5000, L = 20, sys.nois = 0.2)
いい感じに滑らかになっていると思います。
書籍の一番最後に乗っていた金利の変化のCIRモデルを実装したかったですが、とりあえず、ここで一旦終わります。