[17/08/04 18:37 更新]
AIC等の計算をするサンプルスクリプトはtest.pl
というファイル名で用意してある。このスクリプトは、cubic00.csv
のデータをpoly_model.jag
のモデルで推定する。
cubic00.csv
)
ここで使うデータは、mkdata_00.pl
で生成した。3次関数に正規乱数を足したものだ。実行にはPDLが必要である。パラメータを変えて実行すれば、様子が違うデータが得られるはずだ。ここでは、alpha = [0, 1, 0, 0.1]
、sigma = 2
(tau=0.25
)とした。ちょっと見には、直線なのか高次の項が入ってるのか迷うようなデータになっている。
poly_model.jag
)
今回のモデルは、こんな感じ。
model{
x.bar <- mean(x)
for (i in 1:N) {
for (j in 1:K) {
xij[i, j] <- (x[i] - x.bar)^(j-1)
}
}
for (i in 1:N) {
y[i] ~ dnorm(mu[i], tau)
}
mu <- xij %*% alpha
for (i in 1:K) {
alpha[i] ~ dnorm(0, 1.0E-6)
}
tau ~ dgamma(1.0E-6, 1.0E-6)
sigma2 <- 1/tau
}
ちょっと分かりにくいかもしれないが、(x[i] - x.bar)
の多項式の周りに正規分布しているというモデルだ。ここで、x.bar
はx[i]
の平均値。おそらく、こうした方が、x[i]
の多項式にするより収束がよい。
test.pl
)
以下に、サンプルスクリプトtest.pl
をもとに、本パッケージの使い方を説明する。
スクリプトの前半は、多項式の項数K
を2から6まで振って推定してること以外は、reg_test.pl
とあまり変わらない。[ちなみに、項数がK
だと、次数はK-1
である] $coda->summary
のあとで、
$param = $jk->param;
@alpha = @{$param->get("alpha")->value};
push @alpha, 0;
$tau = $param->get("tau")->value;
としているのは、今回の推定値を次回の初期値に設定するための工夫である。
そのあとで、AIC等を計算し、結果を配列に収めている。
my $aic = $jk->aic;
my $aicc = $jk->aicc;
my $bic = $jk->bic;
push @result, "K = $k, AIC = $aic, AICc = $aicc, BIC = $bic\n";
ループを抜けてから、結果の表示。
print @result;
ここでmain
は終わりなのだが、次にMakeshift::Jags
を拡張している。これは、モデルに依存している部分なので、Makeshift/Jags.pm
には書きたくない。
package Makeshift::Jags;
use PDL ();
use PDL::Constants qw(PI);
use PDL::GSLSF::POLY;
# ic_param: give parameters to calculate xIC
# return: hash ref {loglik => log likelihood, nparam => number of parameters,
# ndata => number of data points}
sub xic_param {
my $self = shift;
my $x = PDL->new($self->data->get("x")->{value});
my $xbar = $x->avg;
my $y = PDL->new($self->data->get("y")->{value});
my $alpha = PDL->new($self->param->get("alpha")->value);
my $tau = $self->param->get("tau")->value;
my $mu = gsl_poly_eval($x - $xbar, $alpha);
my $lik = sqrt($tau / (2*PI)) * exp(-$tau*($y - $mu)**2/2);
my $loglik = log($lik)->sum;
my $ret = {loglik => $loglik, nparam => $alpha->nelem + 1,
ndata => $x->nelem};
return $ret;
}
ここではPDLを使っている。そうでないと、もっと長いコードになるうえに、計算速度も落ちるだろう。
これは、対数尤度、パラメータ数、データ点数をハッシュに収めて返すルーチンである。サブルーチン名(xic_param
)と、ハッシュのキー(loglik
、nparam
、ndata
)は変えないでほしい。あとの部分は、どんな名前でどうやって計算してもよい。ちなみに、パラメータ数は、多項式の項数にtau
の分を足している。
計算結果の末尾の部分を取り出すと、
K = 2, AIC = 64.7073005000188, AICc = 68.1358719285902, BIC = 65.9009863184139
K = 3, AIC = 66.9230544169621, AICc = 73.5897210836288, BIC = 68.5146355081556
K = 4, AIC = 52.6078217418123, AICc = 64.6078217418123, BIC = 54.5972981058042
K = 5, AIC = 54.3946154061608, AICc = 75.3946154061608, BIC = 56.781987042951
K = 6, AIC = 56.2295868715862, AICc = 93.5629202049195, BIC = 59.0148537811748
といった感じ。データは3次関数をもとにしているので、K=4
が正解なのだが、各指標とも、そこが最小になっている。
該当するパラメータの推定値は、
K = 4
# var, mean, sd, naive_se, time_series_se, geweke
alpha[1], 0.48221, 1.06165, 0.0150141, 0.028524, -0.47792
alpha[2], 0.27981, 0.55112, 0.0077941, 0.027061, 0.52308
alpha[3], -0.04185, 0.07932, 0.0011217, 0.002133, 0.99723
alpha[4], 0.12867, 0.02860, 0.0004045, 0.001369, -0.61282
tau, 0.24885, 0.13399, 0.0018950, 0.003104, -0.03633
実際は、alpha = [0, 1, 0, 0.1]
、tau=0.25
で作っているので、……、微妙。alpha[2]
以外は、誤差の範囲内で合ってるといっていいのかな?
何はともあれ、計算できた。
[「間に合わせのパッケージ」に戻る] [「PerlとJAGSで赤池情報量基準(AIC)」に戻る] [「あえてのPerl」に戻る]