# get standard errors of predictions from model matrix and vcov ----
.standard_error_predictions <- function(model,
prediction_data,
typical,
terms,
type = "fixed",
vcov = NULL,
vcov_args = NULL,
condition = NULL,
interval = NULL,
verbose = TRUE) {
se <- tryCatch(
.safe_se_from_vcov(
model,
prediction_data,
typical,
terms,
type,
vcov,
vcov_args,
condition,
interval,
verbose = verbose
),
error = function(x) x,
warning = function(x) NULL,
finally = function(x) NULL
)
if (verbose && (is.null(se) || inherits(se, c("error", "simpleError")))) {
insight::print_color("Error: Confidence intervals could not be computed.\n", "red")
if (inherits(se, c("error", "simpleError"))) {
cat(sprintf("* Reason: %s\n", insight::safe_deparse(se[[1]])))
err.source <- insight::safe_deparse(se[[2]])
if (all(grepl("^(?!(safe_se_from_vcov))", err.source, perl = TRUE))) {
cat(sprintf("* Source: %s\n", err.source))
}
}
se <- NULL
}
se
}
.safe_se_from_vcov <- function(model,
prediction_data,
typical,
terms,
type,
vcov,
vcov_args,
condition,
interval,
verbose = TRUE) {
model_frame <- .get_model_data(model)
# check random effect terms. We can't compute SE if data has
# factors with only one level, however, if user conditions on
# random effects and only conditions on one level, it is indeed
# possible to calculate SE - so, ignore random effects for the
# check of one-level-factors only
re.terms <- insight::find_random(model, split_nested = TRUE, flatten = TRUE)
# we can't condition on categorical variables
if (!is.null(condition)) {
cn <- names(condition)
cn.factors <- vapply(cn, function(.x) is.factor(model_frame[[.x]]) && !(.x %in% re.terms), logical(1))
condition <- condition[!cn.factors]
if (.is_empty(condition)) condition <- NULL
}
# copy data frame with predictions
newdata <- .data_grid(
model,
model_frame,
terms,
typical = typical,
factor_adjustment = FALSE,
show_pretty_message = FALSE,
condition = condition,
verbose = FALSE
)
# add response to newdata. For models fitted with "glmmPQL",
# the response variable is renamed internally to "zz".
if (inherits(model, "glmmPQL")) {
new.resp <- 0
names(new.resp) <- "zz"
} else {
fr <- insight::find_response(model, combine = FALSE)
new.resp <- rep_len(0, length(fr))
names(new.resp) <- fr
}
new.resp <- new.resp[setdiff(names(new.resp), colnames(newdata))]
newdata <- cbind(as.list(new.resp), newdata)
# clean terms from brackets
terms <- .clean_terms(terms)
# sort data by grouping levels, so we have the correct order
# to slice data afterwards
for (i in rev(seq_along(terms))) {
trms <- terms[i]
newdata <- newdata[order(newdata[[trms]]), , drop = FALSE]
prediction_data <- prediction_data[order(prediction_data[[trms]]), , drop = FALSE]
}
# rownames were resorted as well, which causes troubles in model.matrix
rownames(newdata) <- NULL
rownames(prediction_data) <- NULL
vmatrix <- .safe(.vcov_helper(
model,
model_frame,
newdata,
vcov,
vcov_args,
terms,
full.vcov = FALSE,
verbose = verbose
))
pr_int <- FALSE
if (is.null(vmatrix) && verbose) {
insight::format_alert("Could not compute variance-covariance matrix of predictions. No confidence intervals are returned.") # nolint
se.fit <- NULL
} else {
pvar <- vmatrix
# condition on random effect variances
if (identical(interval, "prediction")) {
sig <- .get_residual_variance(model)
if (!is.null(sig) && sig > 0.0001) {
pvar <- pvar + sig
pr_int <- TRUE
}
}
se.fit <- sqrt(pvar)
n_pred <- nrow(prediction_data)
n_se <- length(se.fit)
match_len <- isTRUE(n_pred %% n_se == 0)
# shorten to length of prediction_data
if (inherits(model, c("polr", "multinom", "mixor", "multinom_weightit", "ordinal_weightit"))) {
se.fit <- rep(se.fit, each = .n_distinct(prediction_data$response.level))
} else if (type == "random" && n_se < n_pred && match_len) {
se.fit <- rep(se.fit, each = n_pred / n_se)
} else {
se.fit <- se.fit[1:n_pred]
}
}
std_error <- list(prediction_data = prediction_data, se.fit = se.fit)
attr(std_error, "prediction_interval") <- pr_int
std_error
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.