Skip to content

Commit

Permalink
core code complete
Browse files Browse the repository at this point in the history
  • Loading branch information
CoryMcCartan committed Apr 23, 2020
1 parent d4e60f7 commit 9d60a4b
Show file tree
Hide file tree
Showing 31 changed files with 522 additions and 85 deletions.
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ S3method(pull,adjustr_weighted)
S3method(rename,adjustr_spec)
S3method(select,adjustr_spec)
S3method(slice,adjustr_spec)
S3method(summarise,adjustr_weighted)
S3method(summarize,adjustr_weighted)
export(adjust_weights)
export(extract_samp_stmts)
export(get_resampling_idxs)
Expand Down
2 changes: 2 additions & 0 deletions R/adjust_weights.R
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ adjust_weights = function(spec, object, data=NULL, keep_bad=F) {
if (!keep_bad)
adjust_obj$.weights[adjust_obj$.pareto_k > 0.7] = list(NA_real_)
attr(adjust_obj, "draws") = rstan::extract(object)
attr(adjust_obj, "data") = data
attr(adjust_obj, "iter") = object@sim$chains * (object@sim$iter - object@sim$warmup)
adjust_obj
}

Expand Down
1 change: 1 addition & 0 deletions R/adjustr-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#' \itemize{
#' \item \code{\link{make_spec}}
#' \item \code{\link{adjust_weights}}
#' \item \code{\link{summarize}}
#' }
#'
#' @importFrom methods is
Expand Down
2 changes: 1 addition & 1 deletion R/logprob.R
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,4 @@ if (requireNamespace("extraDistr", quietly=T)) {
}
# Turn mapping into an environment suitable for metaprogramming,
# and turn each density into its curried form (see `make_dens` above)
distr_env = new_environment(purrr::map(distrs, make_dens), parent=empty_env())
distr_env = new_environment(purrr::map(distrs, make_dens))
1 change: 1 addition & 0 deletions R/mockup.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ eightschools_m = stan(model_code=model_code, chains=2, data=model_d, warmup=500,
iter=510, save_dso=F, save_warmup=F)
eightschools_m@stanmodel@dso = new("cxxdso")
save(eightschools_m, file="tests/test_model.rda")
load("tests/test_model.rda")

#slot(eightschools_m@stanmodel, "dso", F) = NULL
#draws = extract(eightschools_m)
Expand Down
4 changes: 2 additions & 2 deletions R/parsing.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ get_parser = function() { # nocov start
}
} # nocov end

# Parse Satan `model_code` into a data frame which represents the parsing tree
# Parse Stan `model_code` into a data frame which represents the parsing tree
parse_model = function(model_code) {
parser_output = utils::capture.output(
get_parser()(model_code, function(name, value, pos, depth) {
cat(stringr::str_glue('"{name}","{value}",{pos},{depth}\n\n'))
cat('"', name, '","', value, '",', pos, ',', depth, '\n', sep="")
})
)
parser_csv = paste0("name,value,pos,depth\n",
Expand Down
90 changes: 90 additions & 0 deletions R/use_weights.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,93 @@ get_resampling_idxs = function(x, frac=1, replace=T) {
get_idxs(x)
}
}

#' Summarize Posterior Distributions Under Alternative Model Specifications
#'
#' Uses weights computed in \code{\link{adjust_weights}} to compute posterior
#' summary statistics. These statistics can be compared against their reference
#' values to quantify the sensitivity of the model to aspects of its
#' specification.
#'
#' @param .data An \code{adjustr_weighted} object.
#' @param ... Name-value pairs of expressions. The name of each argument will be
#' the name of a new variable, and the value will be computed for the
#' posterior distribution of eight alternative specification. For example,
#' a value of \code{mean(theta)} will compute the posterior mean of
#' \code{theta} for each alternative specification.
#' @param .resampling Wether to compute summary statistics by first resampling
#' the data according to the weights. Defaults to \code{FALSE}, but will be
#' used for any summary statistic that is not \code{mean}, \code{var} or
#' \code{sd}.
#' @param .model_data Stan model data, if not provided in the earlier call to
#' \code{\link{adjust_weights}}.
#'
#' @return An \code{adjustr_weighted} object, wth the new columns specified in
#' \code{...} added.
#'
#' @rdname summarize.adjustr_weighted
#' @export
summarise.adjustr_weighted = function(.data, ..., .resampling=F, .model_data=NULL) {
stopifnot(is.adjustr_weighted(.data)) # just in case called manually
args = enexprs(...)

broadcast = function(x) {
dims = c(dim(as.array(x)), iter)
x = array(rep(x, iter), dim=dims)
aperm(x, c(length(dims), 2:length(dims) - 1))
}
iter = attr(.data, "iter")
if (!is_null(.model_data)) attr(.data, "data") = .model_data
data = append(attr(.data, "draws"), map(attr(.data, "data"), broadcast))

n_args = length(args)
for (i in seq_along(args)) {
name = names(args)[i]
if (name == "") name = expr_name(args[[i]])

call = args[[i]]
if (!.resampling && exists(call_name(call), funs_env)) {
fun = call_fn(call, funs_env)
} else {
fun = function(x, ...) apply(x, 2, call_fn(call), ...)
.resampling = T
}

expr = expr_deparse(call_args(call)[[1]])
expr = stringr::str_replace_all(expr, "\\[(\\d)", "[,\\1")
expr = stringr::str_replace_all(expr, "(?<![a-zA-Z0-9._])mean\\(", "rowMeans(")
expr = stringr::str_replace_all(expr, "(?<![a-zA-Z0-9._])sum\\(", "rowSum(")
computed = as.array(eval_tidy(parse_expr(expr), data))
if (length(dim(computed)) == 1) dim(computed) = c(dim(computed), 1)

if (!.resampling) {
new_col = map(.data$.weights, ~ fun(computed, .))
} else {
idxs = map(.data$.weights, ~ sample.int(iter, iter, replace=T, prob=.))
new_col = map(idxs, function(idx) {
comp = as.array(computed[idx,])
if (length(dim(comp)) == 1) dim(comp) = c(dim(comp), 1)
exec(fun, comp, !!!map(call_args(call)[-1], eval_tidy))
})
}
if (length(new_col[[1]]) == 1 && is.numeric(new_col[[1]]))
new_col = as.numeric(new_col)
.data[[name]] = new_col
}

.data
}
#' @rdname summarize.adjustr_weighted
#' @export
summarize.adjustr_weighted = summarise.adjustr_weighted

# Weighted summary functions that work on arrays
wtd_array_mean = function(arr, wgt) colSums(as.array(arr)*wgt) / sum(wgt)
wtd_array_var = function(arr, wgt) wtd_array_mean((arr - wtd_array_mean(arr, wgt))^2, wgt)
wtd_array_sd = function(arr, wgt) sqrt(wtd_array_var(arr, wgt))

funs_env = new_environment(list(
mean = wtd_array_mean,
var = wtd_array_var,
sd = wtd_array_sd
))
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
sensitivity of a Bayesian model (fitted with [Stan](https://mc-stan.org)) to the
specification of its likelihood and priors. Users provide a series of alternate
sampling specifications, and the package uses Pareto-smoothed importance
sampling to estimate posterior quantities of interest under each specification.
The package also provides functions to summarize and plot how these quantities
sampling to estimate the posterior under each specification. The package also
provides functions to summarize and plot how posterior quantities quantities
change across specifications.

The package aims to provide simple interface that makes it as easy as possible
for modellers to try out various adjustments to their Stan models, without
needing to write any specific Stan code or even recompile or rerun their model.

The package works by parsing Stan model code, so everything works best if the
model was written by the user. The complexity of **rstanarm** and **brms**
models makes it harder to make interpretable adjustments, but in principle
these are possible too.
model was written by the user. Models made using **brms** may in principle be
used as well. Models made using **rstanarm** are constructed using more
complex model templates, and cannot be used.

## Getting Started

Expand Down
9 changes: 3 additions & 6 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ navbar:
- icon: fa-twitter
href: https://twitter.com/mcmc_stan
- icon: fa-github
href: https://github.com/stan-dev/bayesplot
href: https://github.com/CoryMcCartan/adjustr/
- icon: fa-users
href: https://discourse.mc-stan.org/

Expand Down Expand Up @@ -72,17 +72,14 @@ reference:
contents:
- make_spec
- adjust_weights
- summarise.adjustr_weighted
- title: "Helper Functions"
desc: >
Various helper functions for examining a model or building sampling
specifications.
contents:
- extract_samp_stmts
- as.data.frame.adjustr_spec
- dplyr.adjustr_spec
- get_resampling_idxs
- pull.adjustr_weighted
- title: "Plotting Functions"
desc: >
Functions to visualize changes to a model's posterior across
specifications.
contents:
2 changes: 1 addition & 1 deletion docs/404.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/LICENSE-text.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/authors.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions docs/index.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pandoc: 2.3.1
pkgdown: 1.5.1
pkgdown_sha: ~
articles: []
last_built: 2020-04-19T01:34Z
last_built: 2020-04-23T01:51Z
urls:
reference: https://corymccartan.github.io/adjustr//reference
article: https://corymccartan.github.io/adjustr//articles
Expand Down
8 changes: 4 additions & 4 deletions docs/reference/adjust_weights.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions docs/reference/adjustr.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/reference/as.data.frame.adjustr_spec.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/reference/dplyr.adjustr_spec.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/reference/extract_samp_stmts.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/reference/get_resampling_idxs.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9d60a4b

Please sign in to comment.