バナナでもわかる話

計量経済学・統計学が専門の大学院生です。統計学・経済学・投資理論・マーケティング等々に関する勉強・解説ブログ。ときどき趣味も。極力数式は使わずイメージで説明出来るよう心掛けていますが、時々暴走します。

Rのplotを使ってNealの漏斗を可視化してみる

今日は、「StanとRでベイズ統計モデリング」という本の10章にあるNealの漏斗問題の可視化を簡単なコードだけで行ってみたいと思います。

ちなみにStanとRでベイズ統計モデリングとは、こちらの本です。

こちらの本、全てのコードがしっかりサポートページに掲載されていて、とても勉強になるのですが、10章にあるNealの漏斗の図は省略されていて(私が見た限り載っていなくて/2019年1月3日現在)、どうやって可視化すればいいんだろうと思ったのでやってみました。
とりあえず、綺麗な図というよりは確認出来ればいいので簡単なplotで試してみたいと思います。

スポンサーリンク


Nealの漏斗問題

まず、Nealの漏斗問題とは何かというと、ベイズモデルを作った際に、パラメータ同士対数事後周辺尤度が次のような漏斗状の形になることで生じるサンプリング問題を指します。
f:id:bananarian:20190103152542p:plain

このような状況になると、愚直にStanでモデリングを行っても、サンプルを効率よく取ってくることが出来ません。そこで再パラメータ化という、一旦独立な分布からサンプリングしてやったのち、変数変換を行う処置をとるわけです。

Rコード

では、コードを打っていきます。

まず、rstanの読み込み

library(rstan)

次にモデルを作っておきます

model="
parameters{
	real a;
	vector[1000] r;
}

model{
	a~normal(0,3);
	r~normal(0,exp(a/2));
}"

fit_a=stan(model_code=model,seed=1234,chains=1,iter=4000)
a1=rstan::extract(fit_a)$a
r1=rstan::extract(fit_a)$r[,1]

この状態でのサンプリングはあまりうまくいきません。それをplotでチェックします。

r=seq(-10,10,0.025)
a=seq(-10,10,0.025)
n=length(r)
lp1=matrix(,n,n)
for(i in r){
	for(j in a){
		lp1[which(r==i),which(a==j)]=log(dnorm(i,0,3))+log(dnorm(j,0,exp(i/2)))
	}
}
lp1[lp1==-Inf]=0
contour(r,a,t(lp1))
points(r1,a1,col="red")

f:id:bananarian:20190103153136p:plain

あまりうまくサンプリング出来ていないことが確認出来ました。

さて、再パラメータ化を行った場合はどうでしょう。

model2="
parameters{
	real a_raw;
	vector[1000] r_raw;
}

transformed parameters{
	real a;
	vector[1000] r;
	a=3.0*a_raw;
	r=exp(a/2)*r_raw;
}

model{
	a_raw~normal(0,1);
	r_raw~normal(0,1);
}"

fit_b=stan(model_code=model2,seed=1234,chains=1,iter=4000)
a2=rstan::extract(fit_b)$a
r2=rstan::extract(fit_b)$r[,1]

重ねてみる

contour(r,a,t(lp1))
points(r2,a2,col="green")

f:id:bananarian:20190103153354p:plain

漏斗の先も取ってきて来れていることが確認出来ました!