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:
library(rstan)
fit <- stan_demo("eight_schools", refresh = 0)
Warning: There were 3 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See
http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
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.
list_of_draws <- extract(fit)
print(names(list_of_draws))
[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] 17.485041 7.811984 17.485555 7.892279 10.900572 2.891970
head(list_of_draws$tau)
[1] 1.0471755 0.4587495 9.9680219 0.1007184 3.2761209 4.2399999
head(list_of_draws$theta)
iterations [,1] [,2] [,3] [,4] [,5] [,6]
[1,] 19.280406 17.7994321 18.617346 17.110101 17.355373 16.274623
[2,] 8.615382 7.7502768 8.300409 7.874559 7.684811 7.671890
[3,] 24.357232 22.3714257 -5.547075 15.853349 8.016347 15.191077
[4,] 7.845430 7.8820044 7.771158 7.904784 8.067953 7.920660
[5,] 9.602114 12.1133064 12.560551 15.147464 7.692133 9.891669
[6,] 0.627199 0.3938821 6.913463 -1.260281 -2.926099 1.562390
iterations [,7] [,8]
[1,] 16.912059 17.078409
[2,] 7.059112 8.121503
[3,] 27.031001 34.452037
[4,] 7.891332 7.797977
[5,] 12.454904 9.428657
[6,] 6.996572 1.247808
The as.matrix
, as.data.frame
, and as.array
functions can also be used to retrieve the posterior draws from a stanfit object:
matrix_of_draws <- as.matrix(fit)
print(colnames(matrix_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__"
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__"
array_of_draws <- as.array(fit)
print(dimnames(array_of_draws))
$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:
print(dim(matrix_of_draws))
print(dim(df_of_draws))
print(dim(array_of_draws))
[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:
mu_and_theta1 <- as.matrix(fit, pars = c("mu", "theta[1]"))
head(mu_and_theta1)
parameters
iterations mu theta[1]
[1,] 9.918092 29.056100
[2,] 8.219386 9.988808
[3,] 5.749259 8.174150
[4,] 5.715203 7.101814
[5,] 4.331191 5.383148
[6,] 6.377430 5.144341
Summary statistics are obtained using the summary
function. The object returned is a list with two components:
fit_summary <- summary(fit)
print(names(fit_summary))
[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.73097198 0.11747698 4.8519300 -1.5476445 4.4913829
tau 6.22545709 0.14666104 5.3577321 0.2280811 2.1846471
eta[1] 0.39765414 0.01776585 0.8952167 -1.4952902 -0.1830388
eta[2] 0.02151760 0.01652189 0.8276465 -1.6944626 -0.4817205
eta[3] -0.17819643 0.01621554 0.9018889 -1.9399048 -0.7864082
eta[4] -0.02292258 0.01764078 0.8902046 -1.8254567 -0.5965126
eta[5] -0.33512060 0.01860331 0.8962075 -2.1252321 -0.9099636
eta[6] -0.18254378 0.01761093 0.9248454 -1.9414058 -0.7983549
eta[7] 0.32848149 0.01764591 0.8882398 -1.4300651 -0.2462207
eta[8] 0.08280693 0.01643426 0.9214570 -1.7289300 -0.5404707
theta[1] 11.02768652 0.18006530 7.8209783 -1.0917102 5.9453471
theta[2] 7.82521271 0.10157504 5.8712819 -3.8140961 4.0899849
theta[3] 6.24526633 0.13681235 7.2558193 -9.9829204 2.3216931
theta[4] 7.61239346 0.10639108 6.3846174 -5.9922316 3.9095378
theta[5] 5.13645659 0.10889147 6.3431920 -8.3392041 1.3608763
theta[6] 6.05291473 0.11653215 6.6570064 -8.0640270 2.0994204
theta[7] 10.29722247 0.13646111 6.7005241 -1.1360283 5.6585567
theta[8] 8.38318070 0.15316388 7.7916731 -6.5958234 3.7543853
lp__ -39.52491534 0.07979577 2.6765786 -45.4407483 -41.1778574
50% 75% 97.5% n_eff Rhat
mu 7.710300640 10.8201595 17.911860 1705.782 1.0011798
tau 4.934660076 8.6865976 20.060263 1334.543 1.0002570
eta[1] 0.446463362 0.9974604 2.123625 2539.127 1.0015390
eta[2] 0.032663748 0.5577853 1.660854 2509.403 1.0003477
eta[3] -0.176944010 0.4221599 1.568372 3093.450 1.0001283
eta[4] -0.009576566 0.5522899 1.707047 2546.503 1.0016068
eta[5] -0.332853459 0.2384485 1.511246 2320.794 1.0005783
eta[6] -0.200192814 0.3973778 1.721141 2757.869 1.0006981
eta[7] 0.336165749 0.9267875 2.107704 2533.799 1.0005539
eta[8] 0.089375860 0.7237699 1.879359 3143.764 0.9993661
theta[1] 9.987920033 14.8592466 30.175273 1886.523 0.9995775
theta[2] 7.776935129 11.5481649 19.714621 3341.118 0.9995209
theta[3] 6.694730289 10.6788537 19.591093 2812.693 1.0007810
theta[4] 7.619696315 11.4786594 20.276933 3601.300 1.0003961
theta[5] 5.569884496 9.4783695 16.218592 3393.345 1.0005970
theta[6] 6.214564570 10.3633545 18.442690 3263.371 1.0000984
theta[7] 9.654788879 14.1503354 25.270990 2411.014 0.9999078
theta[8] 8.094676929 12.6035994 25.343160 2587.907 1.0011317
lp__ -39.275838629 -37.6116771 -34.939284 1125.124 1.0001105
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.730972 0.117477 4.851930 1.5780088 14.02927 1705.782 1.001180
tau 6.225457 0.146661 5.357732 0.8157504 13.64416 1334.543 1.000257
Since mu_tau_summary
is a matrix we can pull out columns using their names:
mu_tau_80pct <- mu_tau_summary[, c("10%", "90%")]
print(mu_tau_80pct)
10% 90%
mu 1.5780088 14.02927
tau 0.8157504 13.64416
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.8600566 0.8313094 0.8103682 0.7940533
max_treedepth_by_chain <- sapply(sampler_params, function(x) max(x[, "treedepth__"]))
print(max_treedepth_by_chain)
[1] 4 4 4 3
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:
inits <- get_inits(fit)
inits_chain1 <- inits[[1]]
print(inits_chain1)
$mu
[1] -1.116136
$tau
[1] 0.4804578
$eta
[1] 1.434757 1.950301 1.948562 -1.830643 -1.710742 -1.614347 1.036691
[8] -1.598933
$theta
[1] -0.4267955 -0.1790988 -0.1799339 -1.9956827 -1.9380753 -1.8917616
[7] -0.6180498 -1.8843557
The get_seed
function returns the (P)RNG seed as an integer:
print(get_seed(fit))
[1] 1244074710
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.029773 0.029291
chain:2 0.025882 0.025523
chain:3 0.027275 0.030373
chain:4 0.026627 0.022287