Nothing
# ============================================================================ #
# brma.dffits.R
# ============================================================================ #
#
# This file contains the dffits method for brma model fits. DFFITS measures
# the number of standard deviations that the fitted value changes if observation
# i is removed.
#
# ============================================================================ #
#' @export
dffits <- function(model, ...) UseMethod("dffits")
#' @title DFFITS for brma Objects
#'
#' @description Computes DFFITS (Difference in FITS, standardized) for a
#' fitted brma object. DFFITS measures how much the fitted value for observation
#' \eqn{i} changes if observation \eqn{i} is removed, standardized by the
#' estimated standard error of the fit.
#'
#' @param model a fitted normal-outcome \code{brma} object without a
#' weightfunction component.
#' @param ... additional arguments (currently ignored).
#'
#' @details
#' DFFITS values are computed as a PSIS leave-one-out deletion diagnostic. For
#' each observation \eqn{i}, the leave-one-out posterior mean fitted value at
#' that observation is estimated with normalized PSIS weights and compared to
#' the full-posterior fitted value:
#' \deqn{DFFITS_i =
#' \frac{\hat{\mu}_i - \hat{\mu}_{i(-i)}}{SD_{(-i)}(\mu_i)}}
#'
#' This targets deletion influence on fitted values directly. It does not use
#' LOO-PIT residuals, which are predictive outlier diagnostics rather than
#' fitted-value deletion diagnostics.
#'
#' Estimate-unit LOO must first be computed with
#' \code{model <- add_loo(model, unit = "estimate")}. If the leave-one-out
#' posterior SD of a fitted value is near zero, the corresponding DFFITS value
#' is returned as \code{NA}.
#'
#' @return A named numeric vector of DFFITS values, one for each observation.
#'
#' @examples \dontrun{
#' if (requireNamespace("metadat", quietly = TRUE)) {
#' data(dat.lehmann2018, package = "metadat")
#' fit <- bPET(yi = yi, vi = vi, data = dat.lehmann2018, measure = "SMD")
#' fit <- add_loo(fit)
#'
#' dffits(fit)
#' }
#' }
#'
#' @seealso \code{\link{influence.brma}}, \code{\link{cooks.distance.brma}}, \code{\link{hatvalues.brma}}
#' @aliases dffits
#' @exportS3Method
dffits.brma <- function(model, ...) {
# the function relies on the normal-normal hat matrix
outcome_type <- .outcome_type(model)
is_weightfunction <- .is_weightfunction(model)
if (outcome_type != "norm") {
stop("dffits is only available for normal outcome models.", call. = FALSE)
}
if (is_weightfunction) {
stop("dffits is not available for selection models (weightfunction).", call. = FALSE)
}
fit_samples <- .influence_fit_samples(model)
weights <- .diagnostic_psis_weights(model)
dffits_vec <- .dffits_internal(fit_samples, weights)
dffits_vec <- .diagnostic_set_names(dffits_vec, model)
return(dffits_vec)
}
.dffits_internal <- function(fit_samples, weights) {
summary <- .psis_fit_influence_summary(fit_samples, weights)
delta <- summary[["full_fit"]] - diag(summary[["loo_fit"]])
se <- sqrt(diag(summary[["loo_var"]]))
out <- delta / se
out[se <= sqrt(.Machine$double.eps)] <- NA_real_
names(out) <- colnames(fit_samples)
return(out)
}
# ---------------------------------------------------------------------------- #
# .influence_fit_samples
# ---------------------------------------------------------------------------- #
#
# Posterior fitted-value samples for fixed location terms used by PSIS deletion
# diagnostics.
#
# ---------------------------------------------------------------------------- #
.influence_fit_samples <- function(model) {
data <- model[["data"]]
priors <- model[["priors"]]
posterior_samples <- .get_posterior_samples(model[["fit"]])
K <- nrow(data[["outcome"]])
fit_samples <- .evaluate.brma.mu(
fit = model[["fit"]],
outcome_data = data[["outcome"]],
mods_data = data[["mods"]],
mods_formula = if (.is_mods(model)) .create_fit_formula_list(data = data, "mods") else NULL,
mods_priors = priors[["mods"]],
is_mods = .is_mods(model),
is_PET = .is_PET(model),
is_PEESE = .is_PEESE(model),
effect_direction = .effect_direction(model),
bias_adjusted = FALSE,
K = K,
posterior_samples = posterior_samples
)
colnames(fit_samples) <- .get_estimate_labels(model)
return(fit_samples)
}
# ---------------------------------------------------------------------------- #
# .psis_fit_influence_summary
# ---------------------------------------------------------------------------- #
#
# Full and PSIS leave-one-out fitted-value moments.
#
# ---------------------------------------------------------------------------- #
.psis_fit_influence_summary <- function(fit_samples, weights) {
if (!is.matrix(fit_samples)) {
fit_samples <- as.matrix(fit_samples)
}
if (!is.matrix(weights)) {
weights <- as.matrix(weights)
}
if (nrow(fit_samples) != nrow(weights) ||
ncol(fit_samples) != ncol(weights)) {
stop("'fit_samples' and 'weights' must have the same dimensions.",
call. = FALSE)
}
full_fit <- colMeans(fit_samples)
loo_fit <- crossprod(weights, fit_samples)
loo_m2 <- crossprod(weights, fit_samples^2)
loo_var <- pmax(loo_m2 - loo_fit^2, 0)
return(list(
full_fit = full_fit,
loo_fit = loo_fit,
loo_var = loo_var
))
}
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.