vignettes/stanfit_objects.Rmd
stanfit_objects.Rmd
This vignette demonstrates how to access most of data stored in a
stanfit object. A stanfit object (an object of class
"stanfit"
) contains the output derived from fitting a Stan
model using Markov chain Monte Carlo or one of Stan’s variational
approximations (meanfield or full-rank). Throughout the document we’ll
use the stanfit object obtained from fitting the Eight Schools example
model:
Warning: There were 1 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.
Warning: Examine the pairs() plot to diagnose sampling problems
class(fit)
[1] "stanfit"
attr(,"package")
[1] "rstan"
There are several functions that can be used to access the draws from
the posterior distribution stored in a stanfit object. These are
extract
, as.matrix
,
as.data.frame
, and as.array
, each of which
returns the draws in a different format.
The extract
function (with its default arguments)
returns a list with named components corresponding to the model
parameters.
[1] "mu" "tau" "eta" "theta" "lp__"
In this model the parameters mu
and tau
are
scalars and theta
is a vector with eight elements. This
means that the draws for mu
and tau
will be
vectors (with length equal to the number of post-warmup iterations times
the number of chains) and the draws for theta
will be a
matrix, with each column corresponding to one of the eight
components:
head(list_of_draws$mu)
[1] 8.158595 7.880213 14.086734 1.992156 7.283674 15.916944
head(list_of_draws$tau)
[1] 11.5467890 3.1630415 8.9115022 0.7782174 3.3101477 4.7479295
head(list_of_draws$theta)
iterations [,1] [,2] [,3] [,4] [,5] [,6]
[1,] 28.4498512 13.812518 27.569254 9.143677 15.323212 18.270046
[2,] 9.4066896 9.594654 5.298375 5.605437 7.827925 6.899140
[3,] 14.0018236 18.129483 27.020226 15.679345 -10.604681 -3.521928
[4,] 0.8767176 2.344286 1.289285 1.479599 1.725346 2.312681
[5,] 4.9130196 5.703014 9.707277 9.056205 4.472401 9.378470
[6,] 15.0274075 5.513797 16.454255 14.355015 21.074407 9.402672
iterations [,7] [,8]
[1,] 1.479218 15.372751
[2,] 14.243631 1.350251
[3,] 25.729921 12.187797
[4,] 2.758654 2.501818
[5,] 7.335756 9.839808
[6,] 16.360368 11.608590
The as.matrix
, as.data.frame
, and
as.array
functions can also be used to retrieve the
posterior draws from a stanfit object:
[1] "mu" "tau" "eta[1]" "eta[2]" "eta[3]" "eta[4]"
[7] "eta[5]" "eta[6]" "eta[7]" "eta[8]" "theta[1]" "theta[2]"
[13] "theta[3]" "theta[4]" "theta[5]" "theta[6]" "theta[7]" "theta[8]"
[19] "lp__"
df_of_draws <- as.data.frame(fit)
print(colnames(df_of_draws))
[1] "mu" "tau" "eta[1]" "eta[2]" "eta[3]" "eta[4]"
[7] "eta[5]" "eta[6]" "eta[7]" "eta[8]" "theta[1]" "theta[2]"
[13] "theta[3]" "theta[4]" "theta[5]" "theta[6]" "theta[7]" "theta[8]"
[19] "lp__"
$iterations
NULL
$chains
[1] "chain:1" "chain:2" "chain:3" "chain:4"
$parameters
[1] "mu" "tau" "eta[1]" "eta[2]" "eta[3]" "eta[4]"
[7] "eta[5]" "eta[6]" "eta[7]" "eta[8]" "theta[1]" "theta[2]"
[13] "theta[3]" "theta[4]" "theta[5]" "theta[6]" "theta[7]" "theta[8]"
[19] "lp__"
The as.matrix
and as.data.frame
methods
essentially return the same thing except in matrix and data frame form,
respectively. The as.array
method returns the draws from
each chain separately and so has an additional dimension:
[1] 4000 19
[1] 4000 19
[1] 1000 4 19
By default all of the functions for retrieving the posterior draws
return the draws for all parameters (and generated quantities).
The optional argument pars
(a character vector) can be used
if only a subset of the parameters is desired, for example:
parameters
iterations mu theta[1]
[1,] 12.822571 15.297461
[2,] 9.392738 11.477776
[3,] 6.081793 5.126646
[4,] 7.517083 7.173908
[5,] 8.536018 24.396196
[6,] 12.179750 9.792373
Summary statistics are obtained using the summary
function. The object returned is a list with two components:
[1] "summary" "c_summary"
In fit_summary$summary
all chains are merged whereas
fit_summary$c_summary
contains summaries for each chain
individually. Typically we want the summary for all chains merged, which
is what we’ll focus on here.
The summary is a matrix with rows corresponding to parameters and
columns to the various summary quantities. These include the posterior
mean, the posterior standard deviation, and various quantiles computed
from the draws. The probs
argument can be used to specify
which quantiles to compute and pars
can be used to specify
a subset of parameters to include in the summary.
For models fit using MCMC, also included in the summary are the Monte
Carlo standard error (se_mean
), the effective sample size
(n_eff
), and the R-hat statistic (Rhat
).
print(fit_summary$summary)
mean se_mean sd 2.5% 25%
mu 7.88112638 0.11886981 5.1400521 -2.1874849 4.5862578
tau 6.45264757 0.14793579 5.6059239 0.2438317 2.4334292
eta[1] 0.36243921 0.01534587 0.9281426 -1.4718403 -0.2628066
eta[2] 0.01886754 0.01341454 0.8668440 -1.6882721 -0.5607231
eta[3] -0.16085954 0.01555826 0.9356425 -1.9333095 -0.8083447
eta[4] -0.02161591 0.01528133 0.8929354 -1.7499464 -0.6141818
eta[5] -0.37753813 0.01462871 0.8545046 -2.0589638 -0.9574080
eta[6] -0.21296151 0.01452506 0.9063613 -1.9594580 -0.8191162
eta[7] 0.34961133 0.01448700 0.9062853 -1.5323017 -0.2308520
eta[8] 0.06684927 0.01482872 0.9363868 -1.8603479 -0.5547307
theta[1] 11.14131968 0.15570247 8.2709442 -2.6106520 6.0436778
theta[2] 7.95859334 0.09304677 6.2312790 -4.3871431 3.9185803
theta[3] 6.41387106 0.12989815 7.6799788 -11.0819752 2.2992616
theta[4] 7.60884404 0.10202428 6.5850034 -6.0371411 3.5611151
theta[5] 4.94911661 0.10464727 6.2732871 -9.3887854 1.2949771
theta[6] 6.20658841 0.10725834 6.8355631 -8.3747947 2.1210493
theta[7] 10.60462091 0.12250274 6.6961993 -0.6030978 6.1064082
theta[8] 8.47344823 0.14454695 8.0284266 -7.4842285 3.8346619
lp__ -39.58643914 0.06863020 2.6044560 -45.5215532 -41.1448851
50% 75% 97.5% n_eff Rhat
mu 7.787782492 11.1431031 18.388916 1869.786 0.9995491
tau 5.088594901 8.9653879 20.987474 1435.978 1.0029909
eta[1] 0.373245147 0.9923146 2.129075 3658.022 1.0004282
eta[2] -0.004334584 0.5905507 1.717842 4175.711 0.9997220
eta[3] -0.181754770 0.4567332 1.691041 3616.576 1.0000403
eta[4] -0.024249343 0.5771657 1.765282 3414.425 0.9997084
eta[5] -0.390550370 0.1578636 1.371040 3412.063 0.9995389
eta[6] -0.217677125 0.3668237 1.612039 3893.739 0.9999304
eta[7] 0.357785797 0.9556616 2.131229 3913.571 0.9998760
eta[8] 0.095595700 0.7077347 1.812303 3987.523 1.0010843
theta[1] 9.983158055 15.3383770 30.678479 2821.754 1.0005669
theta[2] 7.915022564 11.7913960 20.958119 4484.890 0.9995185
theta[3] 6.792102722 10.9150764 21.121257 3495.539 1.0018001
theta[4] 7.645471822 11.8346127 20.775881 4165.862 0.9996712
theta[5] 5.393538462 9.1365562 16.129178 3593.640 0.9997582
theta[6] 6.585073185 10.5238483 19.289236 4061.500 0.9999494
theta[7] 9.962639496 14.5929002 25.730154 2987.894 1.0005973
theta[8] 8.139927461 12.8687269 25.952480 3084.914 1.0010763
lp__ -39.331531763 -37.7405538 -35.308693 1440.136 1.0009663
If, for example, we wanted the only quantiles included to be 10% and
90%, and for only the parameters included to be mu
and
tau
, we would specify that like this:
mu_tau_summary <- summary(fit, pars = c("mu", "tau"), probs = c(0.1, 0.9))$summary
print(mu_tau_summary)
mean se_mean sd 10% 90% n_eff Rhat
mu 7.881126 0.1188698 5.140052 1.5573901 14.50957 1869.786 0.9995491
tau 6.452648 0.1479358 5.605924 0.9572862 13.24043 1435.978 1.0029909
Since mu_tau_summary
is a matrix we can pull out columns
using their names:
10% 90%
mu 1.5573901 14.50957
tau 0.9572862 13.24043
For models fit using MCMC the stanfit object will also contain the
values of parameters used for the sampler. The
get_sampler_params
function can be used to access this
information.
The object returned by get_sampler_params
is a list with
one component (a matrix) per chain. Each of the matrices has number of
columns corresponding to the number of sampler parameters and the column
names provide the parameter names. The optional argument inc_warmup
(defaulting to TRUE
) indicates whether to include the
warmup period.
sampler_params <- get_sampler_params(fit, inc_warmup = FALSE)
sampler_params_chain1 <- sampler_params[[1]]
colnames(sampler_params_chain1)
[1] "accept_stat__" "stepsize__" "treedepth__" "n_leapfrog__"
[5] "divergent__" "energy__"
To do things like calculate the average value of
accept_stat__
for each chain (or the maximum value of
treedepth__
for each chain if using the NUTS algorithm,
etc.) the sapply
function is useful as it will apply the
same function to each component of sampler_params
:
mean_accept_stat_by_chain <- sapply(sampler_params, function(x) mean(x[, "accept_stat__"]))
print(mean_accept_stat_by_chain)
[1] 0.8514222 0.8829814 0.8919147 0.8416380
max_treedepth_by_chain <- sapply(sampler_params, function(x) max(x[, "treedepth__"]))
print(max_treedepth_by_chain)
[1] 4 5 4 4
The Stan program itself is also stored in the stanfit object and can
be accessed using get_stancode
:
code <- get_stancode(fit)
The object code
is a single string and is not very
intelligible when printed:
print(code)
[1] "data {\n int<lower=0> J; // number of schools\n real y[J]; // estimated treatment effects\n real<lower=0> sigma[J]; // s.e. of effect estimates\n}\nparameters {\n real mu;\n real<lower=0> tau;\n vector[J] eta;\n}\ntransformed parameters {\n vector[J] theta;\n theta = mu + tau * eta;\n}\nmodel {\n target += normal_lpdf(eta | 0, 1);\n target += normal_lpdf(y | theta, sigma);\n}"
attr(,"model_name2")
[1] "schools"
A readable version can be printed using cat
:
cat(code)
data {
int<lower=0> J; // number of schools
real y[J]; // estimated treatment effects
real<lower=0> sigma[J]; // s.e. of effect estimates
}
parameters {
real mu;
real<lower=0> tau;
vector[J] eta;
}
transformed parameters {
vector[J] theta;
theta = mu + tau * eta;
}
model {
target += normal_lpdf(eta | 0, 1);
target += normal_lpdf(y | theta, sigma);
}
The get_inits
function returns initial values as a list
with one component per chain. Each component is itself a (named) list
containing the initial values for each parameter for the corresponding
chain:
$mu
[1] 1.830195
$tau
[1] 1.48977
$eta
[1] -1.9644185 1.2900084 -0.5047292 1.3198299 -1.9966361 -1.9750366 1.8860891
[8] 1.8957488
$theta
[1] -1.096337 3.752011 1.078264 3.796438 -1.144334 -1.112156 4.640034
[8] 4.654425
The get_elapsed_time
function returns a matrix with the
warmup and sampling times for each chain:
print(get_elapsed_time(fit))
warmup sample
chain:1 0.050 0.042
chain:2 0.047 0.051
chain:3 0.051 0.049
chain:4 0.046 0.043