setClass("ubmsSubmodel",
slots = c(
name = "character",
type = "character",
data = "data.frame",
formula = "formula",
link = "character",
missing = "logical",
prior_intercept = "list",
prior_coef = "list",
prior_sigma = "list"
),
prototype = list(
name = NA_character_,
type = NA_character_,
data = data.frame(),
formula = ~1,
link = NA_character_,
missing = logical(0),
prior_intercept = list(),
prior_coef = list(),
prior_sigma = list()
)
)
ubmsSubmodel <- function(name, type, data, formula, link,
prior_intercept, prior_coef, prior_sigma){
out <- new("ubmsSubmodel", name=name, type=type, data=data,
formula=formula, link=link, prior_intercept=prior_intercept,
prior_coef=prior_coef, prior_sigma=prior_sigma)
out@missing <- apply(model.matrix(out), 1, function(x) any(is.na(x)))
out
}
setClass("ubmsSubmodelTransition", contains = "ubmsSubmodel")
#' @importFrom methods as
ubmsSubmodelTransition <- function(name, type, data, formula, link, T,
prior_intercept, prior_coef, prior_sigma){
data <- drop_final_year(data, T)
out <- ubmsSubmodel(name, type, data, formula, link, prior_intercept,
prior_coef, prior_sigma)
out <- as(out, "ubmsSubmodelTransition")
if(any(out@missing)){
stop("Missing values are not allowed in yearlySiteCovs", call.=FALSE)
}
out
}
drop_final_year <- function(yr_df, nprimary){
to_drop <- seq(nprimary, nrow(yr_df), by=nprimary)
yr_df <- yr_df[-to_drop,,drop=FALSE]
droplevels(yr_df)
}
setClass("ubmsSubmodelScalar", contains = "ubmsSubmodel")
ubmsSubmodelScalar <- function(name, type, link, prior_intercept){
out <- ubmsSubmodel(name, type, data.frame(1), ~1, link,
prior_intercept, null_prior(), null_prior())
as(out, "ubmsSubmodelScalar")
}
placeholderSubmodel <- function(type){
ubmsSubmodel("Placeholder", type, data.frame(), ~1, "identity",
null_prior(), null_prior(), null_prior())
}
is_placeholder <- function(submodel){
length(model.matrix(submodel)) == 0
}
setGeneric("model_frame", function(object, ...)
standardGeneric("model_frame"))
# Need to make this a different generic
setMethod("model_frame", "ubmsSubmodel",
function(object, newdata=NULL, ...){
data <- object@data
formula <- reformulas::nobars(object@formula)
mf <- model.frame(formula, data, na.action=stats::na.pass)
if(is.null(newdata)) return(mf)
check_newdata(newdata, formula)
model.frame(stats::terms(mf), newdata, na.action=stats::na.pass,
xlev=get_xlev(data, mf))
})
setMethod("model.matrix", "ubmsSubmodel",
function(object, newdata=NULL, na.rm=FALSE, warn=FALSE, ...){
mf <- model_frame(object, newdata)
formula <- reformulas::nobars(object@formula)
out <- model.matrix(formula, mf)
if(na.rm) out <- out[!object@missing,,drop=FALSE]
if(warn & !all(is.na(out))){
max_cov <- max(out, na.rm=TRUE)
if(max_cov > 4){
warning(paste0("Covariates possibly not standardized (max value = ", max_cov,
").\nStandardizing covariates is highly recommended."), call.=FALSE)
}
}
out
})
setGeneric("model_offset", function(object, ...) standardGeneric("model_offset"))
setMethod("model_offset", "ubmsSubmodel", function(object, newdata=NULL, na.rm=FALSE, ...){
mf <- model_frame(object, newdata)
off <- stats::model.offset(mf)
if(is.null(off)){
mm <- model.matrix(object, newdata, na.rm)
off <- rep(0, nrow(mm))
} else if(na.rm){
off <- off[!object@missing]
}
if(any(is.na(off))) stop("Missing values in offset term are not allowed", call.=FALSE)
off
})
#Check if all required variables are in newdata
check_newdata <- function(newdata, formula){
inp_vars <- names(newdata)
term_vars <- all.vars(formula)
not_found <- ! term_vars %in% inp_vars
if(any(not_found)){
stop(paste0("Required variables not found in newdata: ",
paste(term_vars[not_found], collapse=", ")), call.=FALSE)
}
}
get_xlev <- function(data, model_frame){
fac_col <- data[, sapply(data, is.factor), drop=FALSE]
xlevs <- lapply(fac_col, levels)
xlevs[names(xlevs) %in% names(model_frame)]
}
get_reTrms <- function(formula, data, newdata=NULL){
fb <- reformulas::findbars(formula)
mf <- model.frame(reformulas::subbars(formula), data, na.action=stats::na.pass)
if(is.null(newdata)) return(reformulas::mkReTrms(fb, mf, drop.unused.levels=FALSE))
new_mf <- model.frame(stats::terms(mf), newdata, na.action=stats::na.pass,
xlev=get_xlev(data, mf))
reformulas::mkReTrms(fb, new_mf, drop.unused.levels=FALSE)
}
Z_matrix <- function(object, newdata=NULL, na.rm=FALSE, ...){
data <- object@data
formula <- object@formula
check_formula(formula, data)
if(is.null(reformulas::findbars(formula))) return(matrix(0,0,0))
Zt <- get_reTrms(formula, data, newdata)$Zt
Z <- t(as.matrix(Zt))
if(is.null(newdata) & na.rm){
Z <- Z[!object@missing,,drop=FALSE]
}
Z
}
check_formula <- function(formula, data){
rand <- reformulas::findbars(formula)
if(is.null(rand)) return(invisible())
char <- paste(reformulas::findbars(formula)[[1]], collapse=" ")
if(grepl(":|/", char)){
stop("Nested random effects (using / and :) are not supported",
call.=FALSE)
}
theta <- get_reTrms(formula, data)$theta
if(0 %in% theta){
stop("Failed to create random effects model matrix.\n
Possible reasons:\n
(1) Correlated slopes and intercepts are not supported. Replace | with || in your formula(s).\n
(2) You have specified random slopes for an R factor variable. Try converting the variable to a series of indicator variables instead.",
call.=FALSE)
}
}
beta_names <- function(submodel){
colnames(model.matrix(submodel))
}
b_names <- function(submodel){
if(!has_random(submodel)) return(NA_character_)
group <- get_reTrms(submodel@formula, submodel@data)
group_nms <- names(group$cnms)
z_nms <- character()
for (i in seq_along(group$cnms)) {
nm <- group_nms[i]
nms_i <- paste(group$cnms[[i]], nm)
levels(group$flist[[nm]]) <- gsub(" ", "_", levels(group$flist[[nm]]))
if (length(nms_i) == 1) {
z_nms <- c(z_nms, paste0(nms_i, ":", levels(group$flist[[nm]])))
} else {
#When there is a random slope for a factor variable
z_nms <- c(z_nms, c(t(sapply(paste0(nms_i), paste0, ":",
levels(group$flist[[nm]])))))
}
}
z_nms
}
sigma_names <- function(submodel){
if(!has_random(submodel)) return(NA_character_)
nms <- get_reTrms(submodel@formula, submodel@data)$cnms
nms <- paste0(unlist(nms), "|", names(nms))
nms <- gsub("(Intercept)", "1", nms, fixed=TRUE)
paste0("sigma [", nms, "]")
}
setGeneric("has_random", function(object){
standardGeneric("has_random")
})
setMethod("has_random", "ubmsSubmodel", function(object){
!is.null(reformulas::findbars(object@formula))
})
#Check if submodel has intercept term
has_intercept <- function(submodel){
mm <- model.matrix(submodel)
"(Intercept)" %in% colnames(mm)
}
#Quickly generate parameter names from ubmsSubmodel
b_par <- function(object){
paste0("b_", object@type)
}
beta_par <- function(object){
paste0("beta_", object@type)
}
sig_par <- function(object){
paste0("sigma_", object@type)
}
setClass("ubmsSubmodelList", slots=c(submodels="list"),
prototype=list(submodels=list()))
ubmsSubmodelList <- function(...){
submodels <- list(...)
names(submodels) <- sapply(submodels, function(x) x@type)
new("ubmsSubmodelList", submodels=submodels)
}
#' Extract a ubmsSubmodel From a ubmsSubmodelList Object
#'
#' @param x Object of class \code{ubmsSubmodelList}
#' @param i The name of a submodel
#'
#' @return An object of class \code{ubmsSubmodel}.
#'
#' @export
setMethod("[", c("ubmsSubmodelList", "character", "missing", "missing"),
function(x, i){
types <- names(x@submodels)
if(! i %in% types){
stop(paste("Possible types are:", paste(types, collapse=", ")),
call. = FALSE)
}
x@submodels[[i]]
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.