Nothing
#' Extract Samples From a `dynamitefit` Object as a Data Table
#'
#' Provides a `data.table` representation of the posterior samples of the model
#' parameters. See [as.data.frame.dynamitefit()] for details.
#'
#' @export
#' @export as.data.table
#' @family output
#' @aliases as.data.table
#' @importFrom data.table as.data.table
#' @param keep.rownames \[`logical(1)`]\cr Not used.
#' @inheritParams as.data.frame.dynamitefit
#' @return A `data.table` containing either samples or summary statistics of
#' the model parameters.
#' @examples
#' data.table::setDTthreads(1) # For CRAN
#' as.data.table(
#' gaussian_example_fit,
#' responses = "y",
#' types = "beta",
#' summary = FALSE
#' )
#'
as.data.table.dynamitefit <- function(x, keep.rownames = FALSE,
row.names = NULL, optional = FALSE,
types = NULL, parameters = NULL,
responses = NULL,
times = NULL, groups = NULL,
summary = FALSE, probs = c(0.05, 0.95),
include_fixed = TRUE, ...) {
stopifnot_(
!missing(x),
"Argument {.arg x} is missing."
)
stopifnot_(
is.dynamitefit(x),
"Argument {.arg x} must be a {.cls dynamitefit} object."
)
stopifnot_(
!is.null(x$stanfit),
"No Stan model fit is available."
)
stopifnot_(
checkmate::test_character(
x = parameters,
any.missing = FALSE,
min.len = 1L,
null.ok = TRUE
),
"Argument {.arg parameters} must be a {.cls character} vector."
)
stopifnot_(
checkmate::test_character(
x = responses,
any.missing = FALSE,
min.len = 1L,
null.ok = TRUE
),
"Argument {.arg responses} must be a {.cls character} vector."
)
types <- onlyif(is.character(types), tolower(types))
stopifnot_(
checkmate::test_character(
x = types,
any.missing = FALSE,
min.len = 1L,
null.ok = TRUE
),
"Argument {.arg types} must be a {.cls character} vector."
)
stopifnot_(
checkmate::test_numeric(
x = times,
min.len = 1L,
null.ok = TRUE
),
"Argument {.arg times} must be a {.cls integer} vector."
)
stopifnot_(
checkmate::test_vector(
x = groups,
min.len = 1L,
null.ok = TRUE
),
"Argument {.arg groups} must be a vector."
)
stopifnot_(
checkmate::test_flag(x = summary),
"Argument {.arg summary} must be a single {.cls logical} value."
)
stopifnot_(
checkmate::test_numeric(
x = probs,
lower = 0.0,
upper = 1.0,
any.missing = FALSE,
min.len = 1L
),
"Argument {.arg probs} must be a {.cls numeric} vector with values between
0 and 1."
)
stopifnot_(
checkmate::test_flag(x = include_fixed),
"Argument {.arg include_fixed} must be a single {.cls logical} value."
)
if (!is.null(parameters)) {
responses <- types <- NULL
}
all_responses <- unique(c(names(x$stan$responses), unlist(x$stan$responses)))
if (is.null(responses)) {
responses <- all_responses
} else {
valid_responses <- responses %in% all_responses
stopifnot_(
all(valid_responses),
c(
"Argument {.arg responses} contains invalid response variable names.",
`x` = "Response variable{?s} {.val {responses[!valid_responses]}}
{?is/are} not recognized.",
`i` = "The response variable{?s} of the model
{?is/are} {.val {all_responses}}."
)
)
}
if (is.null(types)) {
types <- ifelse_(
is.null(parameters),
all_types[!grepl("omega", all_types, fixed = TRUE)],
all_types
)
} else {
match_types <- match(types, all_types)
valid_types <- !is.na(match_types)
stopifnot_(
all(valid_types),
c(
"Argument {.arg types} contains invalid types.",
`x` = "Type{?s} {.val {types[!valid_types]}} {?is/are} not recognized.",
`i` = "Use {.fun get_parameter_types} to check available types."
)
)
}
values <- function(type, response, category) {
ycat <- ifelse_(
nzchar(category) & !is.na(category),
paste0("_", category),
""
)
if (type %in% c("xi", "corr_nu", "corr_psi")) {
draws <- get_draws(x$stanfit, pars = type)
} else {
draws <- get_draws(
x$stanfit,
pars = paste0(type, "_", response, ycat)
)
}
idx <- which(names(x$stan$responses) %in% response)
resps <- ifelse_(
identical(length(idx), 0L),
NULL,
x$stan$responses[[idx]]
)
d <- do.call(
what = paste0("as_data_table_", type),
args = list(
x = x,
draws = draws,
n_draws = prod(dim(draws)[1L:2L]),
response = response,
category = category,
include_fixed = include_fixed,
resps = resps
)
)
n_d <- d[, .N]
n_r <- nrow(draws)
n_c <- ncol(draws)
d[, response := rep(response, n_d)]
d[, type := rep(type, n_d)]
d[, .draw := rep_len(seq_len(n_r * n_c), n_d)]
d[, .iteration := rep_len(seq_len(n_r), n_d)]
d[, .chain := rep_len(rep(seq_len(n_c), each = n_r), n_d)]
if (!is.null(times)) {
d <- d[time %in% times, , env = list(times = times)]
}
if (!is.null(groups)) {
d <- d[group %in% groups, , env = list(groups = I(groups))]
}
d
}
# avoid NSE notes from R CMD check
.chain <- .draw <- .iteration <- NULL
category <- group <- parameter <- response <- NULL
catstr <- time <- type <- value <- NULL
out_all <- NULL
# shrinkage not supported for now
# if ("xi" %in% types) {
# out_all <- data.table::data.table(
# type = "xi",
# response = "",
# category = NA_character_,
# parameter = "xi"
# )
# }
if ("corr_nu" %in% types) {
out_all <- rbind(
out_all,
data.table::data.table(
type = "corr_nu",
response = "",
category = NA_character_,
parameter = "corr_nu"
)
)
}
if ("corr_psi" %in% types) {
out_all <- rbind(
out_all,
data.table::data.table(
type = "corr_psi",
response = "",
category = NA_character_,
parameter = "corr_psi"
)
)
}
categories <- unique(
c(
NA_character_,
ulapply(
unlist(x$stan$responses),
function(y) {
channel <- get_channel(x, y)
if (is_cumulative(channel$family)) {
seq_len(channel$S - 1L)
} else if (is_categorical(channel$family)) {
channel$categories[-1L]
} else {
NA_character_
}
}
)
)
)
tmp <- data.table::as.data.table(
expand.grid(
type = types,
response = responses,
category = categories,
stringsAsFactors = FALSE
)
)
tmp[, catstr := ifelse(
nzchar(category) & !is.na(category),
glue::glue("_{tmp$category}"),
""
)]
tmp[, parameter := as.character(
glue::glue("{tmp$type}_{tmp$response}{tmp$catstr}")
)]
tmp[, catstr := NULL]
out <- data.table::rbindlist(list(out_all, tmp))
rows <- apply(out, 1L, function(y) {
any(
grepl(
paste0("^", y["parameter"], "$"),
get_pars_oi(x$stanfit)
)
)
})
out <- out[rows, c("response", "category", "type")]
n_pars <- nrow(out)
stopifnot_(
n_pars > 0L,
"No parameters of type {.var {types}} were found for any of the response
channels {.var {responses}}."
)
all_values <- vector(mode = "list", length = n_pars + 1L)
# template for rbindlist
all_values[[1L]] <- data.table::data.table(
parameter = character(0L),
value = numeric(0L),
time = x$data[[x$time_var]][0L],
category = character(0L),
group = x$data[[x$group_var]][0L],
response = character(0L),
type = character(0L),
.draw = integer(0L),
.iteration = integer(0L),
.chain = integer(0L)
)
all_values[seq.int(2L, n_pars + 1L)] <- .mapply(
values,
dots = list(
type = out$type,
response = out$response,
category = out$category
),
MoreArgs = NULL
)
out <- data.table::rbindlist(all_values, fill = TRUE)
if (!is.null(parameters)) {
data.table::setkey(out, "parameter")
valid_pars <- parameters %in% unique(out$parameter)
stopifnot_(
all(valid_pars),
c(
"Argument {.arg parameters} contains invalid parameter names.",
`x` = "Parameter{?s} {.val {parameters[!valid_pars]}} {?is/are}
not recognized.",
`i` = "Use {.fun get_parameter_names} to check available parameters."
)
)
out <- out[parameters]
}
if (summary) {
pars <- unique(out$parameter)
out <- out[,
parameter := factor(parameter, levels = pars, ordered = TRUE)
][,
{
mean <- mean(value)
sd <- sd(value)
tmp <- quantile(value, probs = probs, na.rm = TRUE)
names(tmp) <- paste0("q", 100 * probs)
c(list(mean = mean, sd = sd), tmp)
},
by = list(parameter, time, group, category, response, type)
][,
parameter := as.character(parameter)
]
pnames <- c("time", "group", "category", "response", "type")
cnames <- setdiff(colnames(out), pnames)
data.table::setcolorder(out, neworder = c(cnames, pnames))
}
out
}
#' Get Channel Variables or Channel Group Variables
#'
#' @param x A `dynamitefit` object.
#' @param response The response variable name.
#' @noRd
get_channel <- function(x, response) {
if (is.null(x$stan$channel_vars[[response]])) {
x$stan$channel_group_vars[[response]]
} else {
x$stan$channel_vars[[response]]
}
}
#' Construct a Data Table for a Parameter Type from a `dynamitefit` Object
#'
#' Arguments for all as_data_frame_type functions are documented here.
#'
#' @inheritParams as.data.frame.dynamitefit
#' @param draws \[`list()`]\cr A Stan fit draws object.
#' @param n_draws \[`integer(1)`]\cr Number of draws.
#' @param response \[`character(1)`]\cr Response variable name.
#' @param categories \[`character()`]\cr Levels of categorical responses.
#' @noRd
as_data_table_default <- function(type, draws, response, ...) {
data.table::data.table(
parameter = paste0(type, "_", response),
value = c(draws)
)
}
#' Shrinkage feature removed at least for now.
#'
#' @describeIn as_data_table_default Data Table for a "xi" Parameter
#' @noRd
# as_data_table_xi <- function(x, draws, n_draws, ...) {
# D <- x$stan$model_vars$D
# data.table::data.table(
# parameter = rep(
# paste0("xi_d", seq_len(D - 1L)),
# each = n_draws
# ),
# value = c(draws)
# )
# }
#' @describeIn as_data_table_default Data Table for a "corr_nu" Parameter
#' @noRd
as_data_table_corr_nu <- function(x, draws, n_draws, ...) {
vars <- ulapply(
x$stan$channel_vars,
function(y) {
if (y$has_random || y$has_random_intercept) {
icpt <- ifelse_(
y$has_random_intercept,
"alpha",
NULL
)
vars <- paste0(y$y, "_", c(icpt, names(y$J_random)))
ifelse_(
is_categorical(y$family),
paste0(
rep(vars, y$S - 1L),
"_",
rep(y$categories[-1L], each = y$K_random)
),
vars
)
}
}
)
pairs <- apply(utils::combn(vars, 2L), 2L, paste, collapse = "__")
data.table::data.table(
parameter = rep(paste0("corr_nu_", pairs), each = n_draws),
value = c(draws)
)
}
#' @describeIn as_data_table_default Data Table for a "nu" Parameter
#' @noRd
as_data_table_nu <- function(x, draws, n_draws, response, category, ...) {
icpt <- ifelse_(
get_channel(x, response)$has_random_intercept,
"alpha",
NULL
)
var_names <- paste0(
"nu_", response, "_",
c(icpt, names(get_channel(x, response)$J_random))
)
groups <- sort(unique(x$data[[x$group_var]]))
n_group <- length(groups)
data.table::data.table(
parameter = rep(var_names, each = n_draws * n_group),
value = c(draws),
group = rep(groups, each = n_draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "alpha" Parameter
#' @noRd
as_data_table_alpha <- function(x, draws, n_draws,
response, category, include_fixed, ...) {
fixed <- x$stan$fixed
all_time_points <- sort(unique(x$data[[x$time_var]]))
if (get_channel(x, response)$has_varying_intercept) {
time_points <- ifelse_(
include_fixed,
all_time_points,
all_time_points[seq.int(fixed + 1L, length(all_time_points))]
)
n_na <- include_fixed * fixed * n_draws
n_time <- length(time_points)
n_time2 <- n_time - include_fixed * fixed
data.table::data.table(
parameter = paste0("alpha_", response),
value = c(
rep(NA, n_na),
c(draws[, , seq_len(n_time2)])
),
time = rep(time_points, each = n_draws),
category = category
)
} else {
data.table::data.table(
parameter = paste0("alpha_", response),
value = c(draws),
category = category
)
}
}
#' @describeIn as_data_table_default Data Table for a "beta" Parameter
#' @noRd
as_data_table_beta <- function(x, draws, n_draws, response, category, ...) {
var_names <- paste0(
"beta_", response, "_",
names(get_channel(x, response)$J_fixed)
)
data.table::data.table(
parameter = rep(var_names, each = n_draws),
value = c(draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "delta" Parameter
#' @noRd
as_data_table_delta <- function(x, draws, n_draws,
response, category, include_fixed, ...) {
fixed <- x$stan$fixed
all_time_points <- sort(unique(x$data[[x$time_var]]))
var_names <- paste0(
"delta_", response, "_",
names(get_channel(x, response)$J_varying)
)
n_vars <- length(var_names)
time_points <- ifelse_(
include_fixed,
all_time_points,
all_time_points[seq.int(fixed + 1L, length(all_time_points))]
)
n_na <- include_fixed * fixed * n_draws
n_time <- length(time_points)
n_time2 <- n_time - include_fixed * fixed
data.table::rbindlist(lapply(seq_len(n_vars), function(i) {
idx <- (i - 1L) * n_time2 + seq_len(n_time2)
data.table::data.table(
parameter = var_names[i],
value = c(
rep(NA, n_na),
c(draws[, , idx])
),
time = rep(time_points, each = n_draws),
category = category
)
}))
}
#' @describeIn as_data_table_default Data Table for a "tau" Parameter
#' @noRd
as_data_table_tau <- function(x, draws, n_draws, response, category, ...) {
var_names <- paste0(
"tau_", response, "_",
names(get_channel(x, response)$J_varying)
)
data.table::data.table(
parameter = rep(var_names, each = n_draws),
value = c(draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "omega" Parameter
#' @noRd
as_data_table_omega <- function(x, draws, n_draws, response, category, ...) {
D <- x$stan$model_vars$D
var_names <- paste0(
"omega_", response, "_",
names(get_channel(x, response)$J_varying)
)
k <- length(var_names)
params_ord <- rep(
paste0(rep(var_names, each = D), "_d", rep(seq_len(D), k)),
each = n_draws
)
tmp <- data.table::data.table(
parameter = rep(
paste0(var_names, "_d", rep(seq_len(D), each = k)),
each = n_draws
),
value = c(draws),
category = category
)
# avoid NSE notes from R CMD check
parameter <- NULL
tmp[
order(match(parameter, params_ord)), ,
env = list(params_ord = I(params_ord))
]
}
#' @describeIn as_data_table_default Data Table for a "omega_alpha" Parameter
#' @noRd
as_data_table_omega_alpha <- function(x, draws, n_draws, response,
category, ...) {
D <- x$stan$model_vars$D
data.table::data.table(
parameter = rep(
paste0("omega_alpha_", response, "_d", seq_len(D)),
each = n_draws
),
value = c(draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "tau_alpha" Parameter
#' @noRd
as_data_table_tau_alpha <- function(draws, response, category, ...) {
data.table::data.table(
parameter = paste0("tau_alpha_", response),
value = c(draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "sigma" Parameter
#' @noRd
as_data_table_sigma <- function(draws, response, ...) {
as_data_table_default("sigma", draws, response)
}
#' @describeIn as_data_table_default Data Table for a "sigma_nu" Parameter
#' @noRd
as_data_table_sigma_nu <- function(x, draws, n_draws, response, category, ...) {
icpt <- ifelse_(
get_channel(x, response)$has_random_intercept,
"alpha",
NULL
)
var_names <- paste0(
"sigma_nu_", response, "_",
c(icpt, names(get_channel(x, response)$J_random))
)
data.table::data.table(
parameter = rep(var_names, each = n_draws),
value = c(draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "phi" Parameter
#' @noRd
as_data_table_phi <- function(draws, response, ...) {
as_data_table_default("phi", draws, response)
}
#' @describeIn as_data_table_default Data Table for a "lambda" Parameter
#' @noRd
as_data_table_lambda <- function(x, draws, n_draws, response, ...) {
data.table::data.table(
parameter = paste0("lambda_", response),
value = c(draws),
group = rep(sort(unique(x$data[[x$group_var]])), each = n_draws)
)
}
#' @describeIn as_data_table_default Data Table for a "sigma_lambda" Parameter
#' @noRd
as_data_table_sigma_lambda <- function(draws, response, ...) {
as_data_table_default("sigma_lambda", draws, response)
}
#' @describeIn as_data_table_default Data Table for a "tau_psi" Parameter
#' @noRd
as_data_table_tau_psi <- function(draws, response, ...) {
as_data_table_default("tau_psi", draws, response)
}
#' @describeIn as_data_table_default Data Table for a "kappa" Parameter
#' @noRd
as_data_table_kappa <- function(draws, response, ...) {
as_data_table_default("kappa", draws, response)
}
#' @describeIn as_data_table_default Data Table for a "zeta" Parameter
#' @noRd
as_data_table_zeta <- function(draws, response, ...) {
as_data_table_default("zeta", draws, response)
}
#' @describeIn as_data_table_default Data Table for a "psi" Parameter
#' @noRd
as_data_table_psi <- function(x, draws, n_draws, response,
category, include_fixed, ...) {
fixed <- x$stan$fixed
all_time_points <- sort(unique(x$data[[x$time_var]]))
time_points <- ifelse_(
include_fixed,
all_time_points,
all_time_points[seq.int(fixed + 1L, length(all_time_points))]
)
n_na <- include_fixed * fixed * n_draws
n_time <- length(time_points)
n_time2 <- n_time - include_fixed * fixed
data.table::data.table(
parameter = paste0("psi_", response),
value = c(
rep(NA, n_na),
c(draws[, , seq_len(n_time2)])
),
time = rep(time_points, each = n_draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "omega_psi" Parameter
#' @noRd
as_data_table_omega_psi <- function(x, draws, n_draws, response,
category, ...) {
D <- x$stan$model_vars$D
data.table::data.table(
parameter = rep(
paste0("omega_psi_", response, "_d", seq_len(D)),
each = n_draws
),
value = c(draws),
category = category
)
}
#' @describeIn as_data_table_default Data Table for a "corr_psi" Parameter
#' @noRd
as_data_table_corr_psi <- function(x, draws, n_draws, ...) {
resp <- attr(x$dformulas$stoch, "lfactor")$responses
pairs <- apply(utils::combn(resp, 2L), 2L, paste, collapse = "__")
data.table::data.table(
parameter = rep(paste0("corr_psi_", pairs), each = n_draws),
value = c(draws)
)
}
#' @describeIn as_data_table_default Data Table for a "corr" Parameter
#' @noRd
as_data_table_corr <- function(x, draws, n_draws, resps, ...) {
pairs <- apply(utils::combn(resps, 2L), 2L, paste, collapse = "__")
data.table::data.table(
parameter = rep(paste0("corr_", pairs), each = n_draws),
value = c(draws)
)
}
#' @describeIn as_data_table_default Data Table for a "cutpoint" Parameter
#' @noRd
as_data_table_cutpoint <- function(x, draws, response,
n_draws, include_fixed, ...) {
channel <- get_channel(x, response)
S <- channel$S
fixed <- x$stan$fixed
all_time_points <- sort(unique(x$data[[x$time_var]]))
if (channel$has_varying_intercept) {
time_points <- ifelse_(
include_fixed,
all_time_points,
all_time_points[seq.int(fixed + 1L, length(all_time_points))]
)
n_na <- include_fixed * fixed * n_draws
n_time <- length(time_points)
n_time2 <- n_time - include_fixed * fixed
data.table::rbindlist(lapply(seq_len(S - 1L), function(i) {
idx <- (i - 1L) * n_time2 + seq_len(n_time2)
data.table::data.table(
parameter = paste0("cutpoint_", response),
value = c(
rep(NA, n_na),
c(draws[, , idx])
),
time = rep(time_points, each = n_draws),
category = i
)
}))
} else {
data.table::data.table(
parameter = paste0("cutpoint_", response),
category = rep(seq_len(S - 1L), each = n_draws),
value = c(draws)
)
}
}
# Parameter types ---------------------------------------------------------
all_types <- c(
"alpha",
"beta",
"corr",
"corr_nu",
"corr_psi",
"cutpoint",
"delta",
"lambda",
"nu",
"omega",
"omega_alpha",
"omega_psi",
"phi",
"psi",
"sigma",
"sigma_lambda",
"tau_psi",
"sigma_nu",
"tau",
"tau_alpha",
"kappa",
"zeta"
#"xi" # shrinkage not supported for now
)
fixed_types <- c(
"alpha",
"beta",
"corr",
"corr_nu",
"corr_psi",
"cutpoint",
"lambda",
"nu",
"omega",
"omega_alpha",
"omega_psi",
"phi",
"sigma",
"sigma_lambda",
"tau_psi",
"sigma_nu",
"tau",
"tau_alpha",
"kappa",
"zeta"
#"xi" # shrinkage not supported for now
)
varying_types <- c(
"alpha",
"cutpoint",
"delta",
"psi"
)
default_types <- c(
"alpha",
"beta",
"cutpoint",
"delta",
"lambda",
"nu",
"psi"
)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.