Nothing
#' Fit cross-sectional and idiographic moderated network models
#'
#' The main function that ties everything together for both cross-sectional and
#' idiographic (temporal) network models, moderated or otherwise.
#'
#' For GGMs, nodewise estimation is utilized to fit models to each node, and
#' then aggregate results into the final network. For temporal networks that
#' represent data for a single subject, SUR estimation based on feasible
#' generalized least squares (FGLS) is used. Also incorporates the variable
#' selection functions to integrate model selection and estimation. Nodewise
#' estimation is used for all GGMs, and SUR estimation is used for temporal
#' networks. See \code{systemfit} package for more information on the latter,
#' particularly via the \code{\link[systemfit:systemfit]{systemfit::systemfit}}
#' function.
#'
#' @param data \code{n x k} dataframe or matrix.
#' @param moderators Numeric or character vector indicating which variables (if
#' any) to use as moderators.
#' @param type Primarily used to supply a variable selection object, such as
#' those created with \code{\link{varSelect}} or \code{\link{modSelect}}, or
#' to indicate that a variable selection method should be employed by setting
#' the value to \code{"varSelect"}. Currently doesn't support setting the
#' value to \code{"resample"}, although this will be implemented in the
#' future. Alternatively, this can be used to specify the type of variable for
#' each node. In this case it should be either a single value --
#' \code{"gaussian"} or \code{"binomial"} -- or can be a vector of length
#' \code{k} to specify which of those two types apply to each variable. These
#' dictate which family to use for the call to
#' \code{\link[stats:glm]{stats::glm}}. Cannot use binomial models for SUR
#' networks.
#' @param lags Logical or numeric, to indicate whether to fit a SUR model or
#' not. Set to \code{TRUE} or 1 for a SUR model fit to temporal data for a
#' single subject.
#' @param seed Only useful if \code{type = "varSelect"}, and if the
#' \code{varSeed} argument is not specified in the \code{...}
#' @param folds Can be used to specify the number of folds in cross-validation
#' when \code{type = "varSelect"} and \code{criterion = "CV"}. Overwritten if
#' \code{nfolds} argument is provided.
#' @param gamma Only useful if \code{type = "varSelect"} and the criterion is
#' set to \code{"EBIC"}. This is the hyperparameter for the calculation of
#' EBIC.
#' @param which.lam Only useful if \code{criterion = "CV"}, or if a variable
#' selection object based on cross-validation is supplied for \code{type}.
#' Options include \code{"min"}, which uses the lambda value that minimizes
#' the objective function, or \code{"1se"} which uses the lambda value at 1
#' standard error above the value that minimizes the objective function.
#' @param rule Only applies to GGMs (including between-subjects networks) when a
#' threshold is supplied. The \code{"AND"} rule will only preserve edges when
#' both corresponding coefficients have p-values below the threshold, while
#' the \code{"OR"} rule will preserve an edge so long as one of the two
#' coefficients have a p-value below the supplied threshold.
#' @param threshold Determines whether to employ a p-value threshold on the
#' model. If \code{TRUE} then this defaults to .05. Not recommended, as
#' thresholds can be applied post-hoc through the plotting functions, or via
#' the \code{\link{net}} and \code{\link{netInts}} functions. Recommended to
#' leave as \code{FALSE}.
#' @param scale Determines whether to standardize all variables or not.
#' @param std Only applies to SUR networks. Logical. Provides input to the
#' \code{method} argument of the
#' \code{\link[systemfit:systemfit]{systemfit::systemfit}} function. If
#' \code{TRUE}, then the \code{method} will be \code{"SUR"}. If \code{FALSE},
#' then the \code{method} will be \code{"OLS"}. These two methods only differ
#' when constraints are applied. When a saturated model is fit, both methods
#' produce the same results.
#' @param center Determines whether to mean-center variables or not.
#' @param covariates Either a numeric value or character string -- this could
#' also be a vector -- to indicate which variables (if any) should be treated
#' as covariates in the model.
#' @param verbose Logical. Determines whether to return information about the
#' progress of the model fitting -- especially when variable selection is
#' employed -- as well as prints the amount of time it takes to fit the model
#' to the console.
#' @param exogenous Logical. Indicates whether moderator variables should be
#' treated as exogenous or not. If they are exogenous, they will not be
#' modeled as outcomes/nodes in the network. If the number of moderators
#' reaches \code{k - 1} or \code{k}, then \code{exogenous} will automatically
#' be \code{FALSE}.
#' @param mval Numeric value to set the moderator variable to when computing
#' model coefficients. Useful to create conditional networks -- i.e., those
#' whose values are conditioned on specific values of the moderator. Excellent
#' when the moderator is a categorical variable, or when it's desired to have
#' model estimates at +/- 1 SD around the mean of the moderator. These values
#' must be supplied explicitly. Can only specify a single value for a given
#' model.
#' @param residMat Character string indicating which type of residual covariance
#' matrix to compute for SUR models. Options include \code{"res", "dfres",
#' "sigma"}. \code{"sigma"} uses the residual covariance matrix as computed by
#' the \code{systemfits} package. \code{"res"} and \code{"dfres"} compute the
#' matrix based directly on the residual values. \code{"dfres"} is the sample
#' estimator that uses \code{N - 1} in the denominator, while \code{"res"}
#' just uses \code{N}. Input for \code{\link{SURnet}} function.
#' @param medges Only relevant when \code{lags = 1} and \code{exogenous =
#' FALSE}. Determines the linetype of moderated edges (corresponds to the lty
#' argument of \code{plot()}).
#' @param pcor Logical. Determines whether to operationalize the adjacency
#' matrix as the partial correlation matrix of the data, or to use nodewise
#' estimation. Only relevant for unmoderated networks.
#' @param maxiter See argument of \code{SURfit()} function.
#' @param getLL Logical. Determines whether to return log-likelihood statistics
#' with model results. Recommended to keep \code{TRUE}.
#' @param saveMods Logical. Determines whether to save the \code{fitobj} element
#' of the output, which contains the nodewise models, or the SUR model output
#' of \code{\link[systemfit:systemfit]{systemfit::systemfit}}.
#' @param binarize Logical. Determines whether to convert the output to a
#' binary, unweighted network. Only relevant for GGMs.
#' @param fitCoefs Determines whether to use the \code{\link{getFitCIs}}
#' function on the output. Not recommended to use. The downside is that this
#' will overwrite the \code{fitobj} element of the output which contains the
#' actual models. Better to leave this as \code{FALSE}, and then use the
#' \code{\link{getFitCIs}} function on the object separately.
#' @param detrend Logical. Determines whether to remove linear trends from time
#' series variables. Only applies to temporal networks.
#' @param beepno Character string or numeric value to indicate which variable
#' (if any) encodes the survey number within a single day. Must be used in
#' conjunction with \code{dayno} argument. Only relevant to temporal data.
#' @param dayno Character string or numeric value to indicate which variable (if
#' any) encodes the survey number within a single day. Must be used in
#' conjunction with \code{beepno} argument. Only relevant to temporal data.
#' @param ... Additional arguments.
#'
#' @return A ggm or SUR network
#' @export
#'
#' @examples
#' fit1 <- fitNetwork(ggmDat)
#'
#' \donttest{
#' fit2 <- fitNetwork(ggmDat, 'M', type = 'varSelect', criterion = 'BIC')
#' }
#'
#' fit3 <- fitNetwork(gvarDat, 'M', lags = 1)
fitNetwork <- function(data, moderators = NULL, type = "gaussian", lags = NULL,
seed = NULL, folds = 10, gamma = 0.5, which.lam = 'min',
rule = "OR", threshold = FALSE, scale = FALSE, std = TRUE,
center = TRUE, covariates = NULL, verbose = FALSE, exogenous = TRUE,
mval = NULL, residMat = "sigma", medges = 1, pcor = FALSE, maxiter = 100,
getLL = TRUE, saveMods = TRUE, binarize = FALSE, fitCoefs = FALSE,
detrend = FALSE, beepno = NULL, dayno = NULL, ...){
# START
t1 <- Sys.time()
# Alternative way of specifying that there is a lag
if(!identical(detrend, FALSE) | (!is.null(beepno) & !is.null(dayno))){lags <- 1}
# Check if moderators are specified by name -- NEW
if(isTRUE(is.character(moderators)) & !identical(moderators, 'all')){
moderators <- which(colnames(data) %in% moderators)
}
# Check if covariates are specified by name -- NEW
if(isTRUE(is.character(covariates))){
covariates <- which(colnames(data) %in% covariates)
}
# Check for missing values
if(any(is.na(data))){
ww <- which(apply(data, 1, function(z) any(is.na(z))))
if(is.null(lags) | identical(lags, 0)){
data <- data[-ww, ]
warning(paste0(length(ww), ' cases deleted due to missingness'))
} else {
stop(paste0(length(ww), ' rows contain missing values'))
}
}
# Collect additional arguments
args <- tryCatch({list(...)}, error = function(e){list()})
# Variable selection -- REMOVE SECOND PART
if(identical(type, 'varSelect')){
vargs <- list(data = data, m = moderators, lags = lags, exogenous = exogenous,
center = center, scale = scale, gamma = gamma, verbose = verbose)
vargs$method <- ifelse(!is.null(moderators), 'glinternet',
ifelse('method' %in% names(args), args$method, 'glmnet'))
otherargs <- c('criterion', 'nfolds', 'varSeed', 'useSE', 'nlam')
if(any(otherargs %in% names(args))){
if('criterion' %in% names(args)){ # This conditional is new
if(toupper(args$criterion) == 'CV'){
if(!'nfolds' %in% names(args)){args$nfolds <- folds}
}
}
vargs <- append(vargs, args[intersect(names(args), otherargs)])
}
if(!is.null(seed)){vargs$varSeed <- seed}
type <- do.call(varSelect, vargs)
} else if(identical(type, 1)){
type <- 'g'
lags <- 1
}
# Ensure that if lags == 0, then NULL
if(!is.null(lags)){if(all(lags == 0)){lags <- NULL}}
# Obviously related to bootNet; ensures that dataset will be data.frame
if(!is.null(lags)){
if(lags != FALSE){lags <- 1}
if("samp_ind" %in% names(attributes(data))){samp_ind <- attr(data, "samp_ind")}
data <- data.frame(data)
if(exists("samp_ind", inherits = FALSE)){attr(data, "samp_ind") <- samp_ind}
} else {
data <- data.frame(data)
}
# Checking for weird moderator specification
if(!is.null(moderators)){
if(all(moderators == 0)){moderators <- NULL}
if(all(moderators == "all")){moderators <- 1:ncol(data)}
}
# Covariates must be specified as a list? Or numeric?
if(ifelse(!is.null(covariates), ifelse(!is(covariates, 'list'), TRUE, FALSE), FALSE)){
if(length(covariates) >= ncol(data) - 1){stop("Must have at least 2 outcome variables")}
}
# adjust which.lam
if(grepl("min", which.lam)){which.lam <- "min"} else {which.lam <- "1se"}
### SETUP -- create output object
output <- list()
output$call <- list(type = type, moderators = moderators, mval = mval, lags = lags,
which.lam = which.lam, rule = rule, threshold = threshold,
center = center, scale = scale)
# Add extra arguments
if(length(args) != 0){output$call <- append(output$call, args)}
# Removing mval if it's null
if(is.null(mval)){output$call$mval <- NULL}
# Make adjustments to TYPE if variable selection was used; otherwise, setup gaussian and binomial
if(class(type) == "list"){
output$call$type <- lapply(type, function(z) unlist(z[[ifelse(which.lam == "min", 1, 2)]]))
if(attr(type, "criterion") != "CV"){output$call$which.lam <- attr(type, "criterion")}
if(attr(type, "criterion") == "EBIC"){output$call$gamma <- attr(type, "gamma")}
} else {
output$call$which.lam <- NULL
if(length(type) == 1){
type <- rep("gaussian", ncol(data))
bb <- unname(which(apply(data, 2, function(z) dim(table(z)) <= 2)))
if(length(bb) > 0){type[bb] <- "binomial"}
}
if("gaussian" %in% type){type[type == "gaussian"] <- "g"}
if("binomial" %in% type){
type[type == "binomial"] <- "c"
if(all(type == "c")){output$call[c("center", "scale")] <- center <- scale <- FALSE}
}
output$call$type <- type
}
### CROSS-SECTIONAL
if(is.null(lags)){
# Remove lags from output
output$call$lags <- NULL
# Ensure THRESHOLD is not a character
if(is.character(threshold)){output$call$threshold <- threshold <- FALSE}
# Update output with names of covariates
if(!is.null(covariates)){
if(class(covariates) == "list"){covs <- names(covariates)}
if(class(covariates) %in% c("numeric", "integer")){covs <- colnames(data)[covariates]}
output$call$covariates <- covs
}
# If moderators, collect names and remove 'pcor' option; otherwise check pcor option
if(!is.null(moderators)){
output$call$moderators <- ifelse(is.list(moderators), list(names(moderators)),
list(colnames(data)[moderators]))[[1]]
if("pcor" %in% names(output$call)){output$call$pcor <- NULL}
} else if("pcor" %in% names(output$call)){
if(pcor != FALSE){
if(threshold == FALSE){output$call$pcor <- TRUE}
output$call$rule <- NULL
}
}
# Resolve having both moderators and covariates specified
if(!is.null(covariates) & !is.null(moderators)){
if(!is.list(covariates) & !is.list(moderators)){
if(max(moderators) > min(covariates)){
if(is.character(type)){output$call$type <- type <- type[-covariates]}
covs <- list(data[, covariates])
data <- data[, -covariates]
names(covs) <- output$call$covariates
covariates <- covs
moderators <- which(colnames(data) %in% output$call$moderators)
}
}
}
# NODEWISE -- COMPUTE REGRESSIONS
mods0 <- nodewise(data = data, mods = moderators, varMods = type,
lambda = which.lam, center = center, scale = scale,
covariates = covariates, exogenous = exogenous)
# Provide warning if too many parameters
if(any(sapply(mods0$models, function(z) length(coef(z))) >= nrow(data))){
warning('Model is overspecified; not enough cases to estimate all parameters')
}
# MODNET -- FORM THE FINAL NETWORK MODEL
out <- modNet(models = mods0, threshold = threshold, rule = rule,
mval = mval, pcor = pcor, binarize = binarize)
# Append the result to the output list
output <- append(output, out)
# Then add mods0?
output$mods0 <- mods0
# I'll have to look into this...
if("moderator" %in% names(attributes(out))){
attr(output, "moderator") <- attr(out, "moderator")
output$call$exogenous <- attr(mods0$models, "exogenous")
}
# And this...
if("mval" %in% names(attributes(out))){attr(output, "mval") <- attr(out, "mval")}
# Set an attribute
attributes(output)$ggm <- TRUE
# Compute the log-likelihood
if(getLL){
output$modLL <- tryCatch({modLL(output, all = TRUE)}, error = function(e){list()})
if(length(output$modLL) == 0){
output$modLL <- NULL
} else {
dd <- output$data
output[c('data', 'mods0')] <- NULL
output$data <- dd
output$mods0 <- mods0
}
}
# Update the output classes
class(output) <- c('list', 'ggm')
# Prune off models; fitCoefs?
if(fitCoefs | !saveMods){
output$mods0$models <- NULL
output$fitobj <- if(fitCoefs){getFitCIs(output)} else {NULL}
}
# Print the time
if(verbose){print(Sys.time() - t1)}
# Release the kraken
return(output)
} else {
### TEMPORAL
if(!is.null(beepno) & !is.null(dayno)){
beepday <- list(beepno, dayno)
stopifnot(sum(sapply(c(1, nrow(data)), function(z) all(sapply(beepday, length) == z))) == 1)
if(all(sapply(beepday, length) == 1)){
if(is.character(beepno)){beepno <- which(colnames(data) == beepno)}
if(is.character(dayno)){dayno <- which(colnames(data) == dayno)}
data0 <- data[, -c(beepno, dayno)]
beepno <- data[, beepno]
dayno <- data[, dayno]
data <- data0
if(exists("samp_ind", inherits = FALSE)){
attr(data, "samp_ind") <- samp_ind
}
}
} else if(!is.null(beepno) & is.null(dayno) | !is.null(dayno) & is.null(beepno)){
stop('Must specify both beepno AND dayno, or neither')
}
if(!identical(detrend, FALSE)){
if(is(detrend, 'list')){
stopifnot(length(detrend) %in% 1:2)
if(is.null(names(detrend))){
if(length(detrend) == 1){
detrend <- detrend[[1]]
} else {
names(detrend)[order(sapply(detrend, length))] <- c('timevar', 'vars')
}
}
}
timevar <- switch(2 - isTRUE(detrend), NULL, ifelse(
is(detrend, 'list'), detrend$timevar, ifelse(
is(detrend, 'numeric'), colnames(data)[detrend], detrend)))
dvars <- switch(2 - is(detrend, 'list'), detrend$vars, NULL)
data <- detrender(data = data, timevar = timevar, vars = dvars, verbose = verbose)
if(exists("samp_ind", inherits = FALSE)){
attr(data, "samp_ind") <- samp_ind
}
}
if(!is.null(beepno) & !is.null(dayno)){
#consec <- mgm:::beepday2consec(beepvar = beepno, dayvar = dayno)
#consec <- mgm:::lagData(data = data, lags = 1, consec = consec)[[3]][-1]
consec <- makeConsec(beepvar = beepno, dayvar = dayno)
consec <- lagData(data = data, lags = 1, consec = consec)[[3]][-1]
output$call$consec <- which(consec)
} else {
consec <- NULL
}
output$call$rule <- NULL
if(threshold != FALSE){output$call$pcor <- ifelse(is.logical(pcor), "none", pcor)}
if(class(type) == "list"){
if(length(type) == 1){stop("Need more than one outcome to construct network")}
if(!attr(type, "method") %in% c("regsubsets", "glmnet")){
exogenous <- attr(type, "exogenous")
moderators <- attr(type, "moderators")
if(!is.character(moderators)){
attr(type, "moderators") <- moderators <- colnames(data)[moderators]
}
anymods <- any(sapply(moderators, function(z){
any(grepl(paste0(z, ":|:", z), unlist(output$call$type)))
}))
moderators <- which(colnames(data) %in% moderators)
if("covs" %in% names(attributes(type))){covariates <- attr(type, "covs")}
}
}
if(!is.null(union(moderators, covariates))){
mco <- sort(union(moderators, covariates))
stopifnot(identical(mco, sort(c(moderators, covariates))))
if(exogenous & length(mco) >= ncol(data) - 1){exogenous <- FALSE}
}
if(!is.null(moderators)){
output$call$moderators <- colnames(data)[moderators]
output$call$exogenous <- exogenous
}
if(exists("anymods", inherits = FALSE)){
if(!anymods){
covariates <- union(covariates, moderators)
moderators <- NULL
}
}
fit <- SURfit(data = data, varMods = type, m = moderators, mod = which.lam,
center = center, scale = scale, exogenous = exogenous,
covs = covariates, sur = std, maxiter = maxiter, consec = consec)
dat <- lagMat(data = data, type = type, m = moderators, covariates = covariates,
center = center, scale = scale, exogenous = exogenous, consec = consec)
net <- SURnet(fit = fit, dat = dat, s = residMat, m = moderators, pcor = pcor,
threshold = threshold, mval = mval, medges = medges)
if(!is.null(covariates)){
output$call$covariates <- net$call$covariates <- colnames(data)[covariates]}
output$SURnet <- net
attributes(output$SURnet)$SURnet <- TRUE
output$SURfit <- fit
if("mnet" %in% names(net)){
attr(output, "mnet") <- net$call$moderators
if("mval" %in% names(net$call)){attr(output, "mval") <- net$call$mval}
}
attributes(output)$SURnet <- TRUE
if(getLL){
output$SURll <- tryCatch({SURll(output, all = TRUE, s = residMat)}, error = function(e){list()})
if(length(output$SURll) == 0){output$SURll <- NULL}
}
attr(output, 'rank') <- sum(sapply(lapply(output$SURnet$mods, '[[', 'model'), nrow))
class(output) <- c('list', 'SURnet')
if(fitCoefs | !saveMods){
output$SURfit <- if(fitCoefs){getFitCIs(output)} else {NULL}
}
if(verbose){print(Sys.time() - t1)}
return(output)
}
}
##### nodewise: nodewise regression, with option to simulate/add moderators
nodewise <- function(data, mods = NULL, varMods = NULL, lambda = "min", center = TRUE,
scale = FALSE, covariates = NULL, exogenous = TRUE){
# Good lord...
data <- dat <- dat0 <- data.frame(data)
# Save them colnames
vs <- colnames(data)
# Variable selection/TYPE
if(!is.null(varMods)){
# Variable selection component
if(class(varMods) == "list"){
if(all(sapply(varMods, class) != "list")){
varMods <- lapply(varMods, list)
lambda <- "min"
}
if(is.null(names(varMods))){
if((is.null(mods) | (!is.null(mods) & class(mods) == "list")) &
(is.null(covariates) | (!is.null(covariates) & class(covariates) == "list"))){
names(varMods) <- colnames(data)
} else {
if(!is.null(mods) & class(mods) %in% c("numeric", "integer")){mc <- mods} else {mc <- NULL}
if(!is.null(covariates) & class(covariates) %in% c("numeric", "integer")){mc <- c(mc, covariates)}
names(varMods) <- colnames(data)[-mc]
}
}
if(!is.null(mods)){if(length(mods) > 1){mods <- NULL}}
if(length(varMods) == ncol(data)){exogenous <- FALSE}
if(is.null(unlist(lapply(varMods, '[[', "mod1se")))){lambda <- "min"}
lambda <- ifelse(lambda == "min", 1, 2)
type <- unname(sapply(varMods, attr, "family"))
if(all(type == "c")){center <- FALSE}
# TYPE component
} else {
type <- varMods
if(is.null(mods)){
varMods <- NULL
} else if(length(mods) == 1){
varMods <- NULL
} else {
varMods <- setNames(lapply(1:ncol(data), function(z){
mains <- vs[-z]
ints <- apply(combn(mains, 2), 2, paste0, collapse = ":")
if(!z %in% mods){ints <- ints[apply(combn(mains, 2), 2, function(zz) any(vs[mods] %in% zz))]}
return(list(mod0 = c(mains, ints)))
}), vs)
if(exogenous & length(mods) < (ncol(data) - 1)){
varMods <- varMods[vs[-mods]]
} else {
exogenous <- FALSE
}
mods <- NULL
lambda <- 1
}
}
} else if(!is.null(mods)){
if(length(mods) > 1){
varMods <- lapply(1:ncol(data), function(z){
mains <- vs[-z]
ints <- apply(combn(mains, 2), 2, paste0, collapse = ":")
if(!z %in% mods){ints <- ints[apply(combn(mains, 2), 2, function(zz) any(vs[mods] %in% zz))]}
return(list(mod0 = c(mains, ints)))
})
names(varMods) <- vs
type <- unname(ifelse(apply(data, 2, function(z) dim(table(z))) <= 2, "c", "g"))
exogenous <- FALSE
mods <- NULL
lambda <- 1
}
}
# intMatrix function
intMatrix <- function(data, mods = NULL, covariates = NULL){
if(class(mods) == "list"){stopifnot(!is.null(names(mods)))}
data <- as.data.frame(data)
vars <- colnames(data)
eqs <- list()
if(!is.null(mods)){
for(i in 1:length(vars)){
modTerms <- list()
for(j in 1:length(mods)){modTerms[[j]] <- paste0(names(mods[j]), " + ", paste(paste0(vars[-i], ":", names(mods[j])), collapse = " + "))}
modTerms <- paste(modTerms, collapse = " + ")
eqs[[i]] <- paste0(vars[i], " ~ ", paste(vars[-i], collapse = " + "), " + ", modTerms)
}
} else {
for(i in 1:length(vars)){eqs[[i]] <- paste0(vars[i], " ~ ", paste(vars[-i], collapse = " + "))}
}
if(!is.null(covariates)){
for(i in 1:length(vars)){eqs[[i]] <- paste0(eqs[[i]], " + ", paste(names(covariates), collapse = " + "))}
}
eqs <- setNames(lapply(eqs, as.formula), vars)
return(eqs)
}
# Covariates
if(!is.null(covariates)){
if(class(covariates) %in% c("numeric", "integer")){
if(length(covariates) > 1){
covs <- as.list(data[, covariates])
} else {
covs <- list(data[, covariates])
names(covs) <- colnames(data)[covariates]
}
data <- dat <- dat0 <- data[, -covariates]
covariates <- covs
}
}
# Moderators
if(!is.null(mods)){
if(class(mods) %in% c("numeric", "integer")){
mod <- list(data[, mods])
names(mod) <- colnames(data)[mods]
data <- data[, -mods]
if(length(type) > ncol(data)){type <- c(type[-mods], type[mods])}
mods <- mod
}
if(length(mods) != 1){stop("Cannot specify more than on exogenous moderator")}
dat <- dat0 <- data.frame(data, mods)
}
# Centering and standardizing
if(center != FALSE){
binary <- unname(which(apply(dat, 2, function(z) dim(table(z)) <= 2)))
if(length(binary) == ncol(dat) | ifelse(!is.null(mods), length(binary) == ncol(dat) - 1, FALSE)){
type <- "binomial"
}
if(!is.null(mods) & dim(table(mods[[1]])) <= 2 | center != TRUE){
if(length(binary) > 0){
dat[, -union(binary, ncol(dat))] <- apply(dat[, -union(binary, ncol(dat))], 2, scale, TRUE, scale)
} else {
dat[, -ncol(dat)] <- apply(dat[, -ncol(dat)], 2, scale, TRUE, scale)
}
} else {
if(length(binary) > 0){
dat[, -binary] <- apply(dat[, -binary], 2, scale, TRUE, scale)
} else {
dat <- apply(dat, 2, scale, TRUE, scale)
}
}
if(!is.null(covariates)){
covariates <- lapply(covariates, function(z){
ifelse(dim(table(z)) <= 2 | center != TRUE, list(z), list(scale(z, TRUE, scale)))[[1]]
})
}
dat <- dat0 <- data.frame(dat)
}
# Return the covariates
if(!is.null(covariates)){dat <- data.frame(dat, covariates)}
# Variable selection?
if(!is.null(varMods)){
ints <- as.list(paste(names(varMods), "~", lapply(varMods, function(z) paste0(z[[lambda]], collapse = " + "))))
if(!is.null(covariates) & ifelse("covariates" %in% names(attributes(varMods)), FALSE, TRUE)){
ints <- lapply(ints, paste0, " + ", paste(names(covariates), collapse = " + "))
}
names(ints) <- names(varMods)
} else {
ints <- intMatrix(data, mods, covariates)
if(!is.null(mods) & !exogenous){ints <- append(ints, list(as.formula(paste0(names(mods), " ~ .^2"))))}
}
# Check TYPE, FIT MODELS
if(exists("type", inherits = FALSE)){
if(length(type) == 1){
type <- rep(match.arg(type, c("g", "c", "gaussian", "binomial")), length(ints))
}
if(any(type %in% c("g", "c"))){
type <- unname(sapply(type, switch, "g" = "gaussian", "c" = "binomial"))
}
m <- suppressWarnings(lapply(1:length(ints), function(z){
#if(type[z] == "gaussian"){mglm <- lm(ints[[z]], dat)}
#if(type[z] == "binomial"){mglm <- glm(ints[[z]], data = dat, family = type[z])}
mglm <- glm(ints[[z]], data = dat, family = type[z])
attr(mglm, "family") <- type[z]
return(mglm)
}))
} else {
m <- lapply(ints, function(z) lm(z, dat))
}
# Not sure what's going on here...
if(!is.null(mods) & !exogenous){
data0 <- data
data <- dat0
}
# Collect coefficients
mm <- lapply(lapply(m, coef), function(z) z[which(names(z) %in% colnames(data))])
# Pvalues for coefficients
ps1 <- lapply(m, function(z){
z1 <- is.na(coef(z))
z2 <- t(data.frame(summary(z)$coefficients))
z0 <- ifelse(any(z1), list(names(z1[!z1])), list(names(coef(z))))[[1]]
z3 <- z2[4, which(z0 %in% colnames(data)), drop = FALSE]
rownames(z3) <- NULL
return(z3[1, ])
})
# Pvalues when moderators included
if(!is.null(mods)){
mname <- names(mods)
m2 <- lapply(lapply(m, coef), function(z) z[grep(paste0(":", mname, "$"), names(z))])
ps2 <- lapply(m, function(z){
z2 <- t(data.frame(summary(z)$coefficients))
z3 <- z2[4, grep(paste0(":", mname, "$"), colnames(z2)), drop = FALSE]
rownames(z3) <- NULL
return(z3[1, ])
})
vs <- ifelse(exogenous, list(colnames(data)), list(colnames(data0)))[[1]]
mx <- paste0(vs, ":", mname)
psx <- bx <- suppressWarnings(diag(mx))
rownames(psx) <- rownames(bx) <- vs
colnames(psx) <- colnames(bx) <- mx
diag(psx) <- diag(bx) <- 1
m3 <- lapply(m, function(z) summary(z)$coefficients)
names(m3) <- vs
bm <- do.call(rbind, lapply(m3, function(z) z[rownames(z) == mname, ]))
if(!exogenous){
m2 <- m2[-ncol(data)]
ps2 <- ps2[-ncol(data)]
m3 <- m3[-ncol(data)]
}
}
# More summary when covariates are included
if(!is.null(covariates)){
m4 <- lapply(m, function(z) summary(z)$coefficients)
names(m4) <- ifelse(!is.null(mods), list(vs), list(colnames(data)))[[1]]
cnames <- names(covariates)
bcovs <- list()
for(i in 1:length(cnames)){
bcovs[[i]] <- do.call(rbind, lapply(m4, function(z) z[rownames(z) == cnames[i], ]))
}
names(bcovs) <- cnames
}
#b <- ps <- matrix(NA, nrow = ncol(data), ncol = ncol(data))
#for(i in 1:ncol(data)){
# b[i, match(names(mm[[i]]), colnames(data))] <- mm[[i]]
# ps[i, match(names(ps1[[i]]), colnames(data))] <- ps1[[i]]
# if(!is.null(mods)){
# if(exogenous | (!exogenous & i < ncol(data))){
# bx[i, match(names(m2[[i]]), mx)] <- m2[[i]]
# psx[i, match(names(ps2[[i]]), mx)] <- ps2[[i]]
# }
# }
#}
#for(i in 1:length(ints)){
# b[i, match(names(mm[[i]]), names(ints))] <- mm[[i]]
# ps[i, match(names(ps1[[i]]), names(ints))] <- ps1[[i]]
# if(!is.null(mods)){
# if(exogenous | (!exogenous & i < ncol(data))){
# bx[i, match(names(m2[[i]]), mx)] <- m2[[i]]
# psx[i, match(names(ps2[[i]]), mx)] <- ps2[[i]]
# }
# }
#}
# Setup results in matrix format
b <- ps <- matrix(NA, nrow = length(ints), ncol = length(ints))
for(i in 1:length(ints)){
mm0 <- mm[[i]][which(names(mm[[i]]) %in% names(ints))]
ps0 <- ps1[[i]][which(names(ps1[[i]]) %in% names(ints))]
b[i, match(names(mm0), names(ints))] <- mm0
ps[i, match(names(ps0), names(ints))] <- ps0
if(!is.null(mods)){
if(exogenous | (!exogenous & i < ncol(data))){
bx[i, match(names(m2[[i]]), mx)] <- m2[[i]]
psx[i, match(names(ps2[[i]]), mx)] <- ps2[[i]]
}
}
}
diag(b) <- diag(ps) <- 1
if(any(is.na(b))){b[is.na(b)] <- 0}
if(any(is.na(ps))){ps[is.na(ps)] <- 0}
out <- list(models = setNames(m, names(ints)), B = list(b = b, ps = ps))
# Set attributes for moderators
if(is.null(mods)){
attributes(out$models)$noMods <- TRUE
if(length(ints) != ncol(data)){attr(out$models, 'exogenous') <- TRUE}
} else {
attributes(out$models)$exogenous <- exogenous
if(nrow(bm) >= 1 & exogenous){out$Bm <- bm}
out$Bx <- list(bx = bx, px = psx)
}
# Not sure if this is about moderators or variable selection, or both
if(!is.null(varMods)){
if(!any(grepl(":", unlist(sapply(out$models, function(z) names(coef(z))))))){
attributes(out$models)$noMods <- TRUE
out$Bx <- NULL
}
attributes(out$models)$varMods <- c("min", "1se")[lambda]
}
# Setup covariate output
if(!is.null(covariates)){
out$dat <- dat0
out$covariates <- list(covs = do.call(cbind.data.frame, covariates), Bcovs = bcovs)
} else {
out$dat <- dat
}
# Gotta figure out this "exists type" thing
if(exists("type", inherits = FALSE)){attr(out, "type") <- type}
# RETURN
return(out)
}
##### modNet: create moderated network from nodewise regression models
modNet <- function(models, data = NULL, threshold = FALSE, rule = "AND", mval = NULL,
pcor = FALSE, useCIs = FALSE, nsims = 5000, mlty = 2, binarize = FALSE){
# Get models and data
if("models" %in% names(models)){
mods0 <- models
models <- models$models
if(is.null(data)){
if("noMods" %in% names(attributes(models)) & length(models) == ncol(mods0$dat)){
data <- mods0$dat
} else if(isTRUE(attr(models, "exogenous"))){
#data <- mods0$dat[, -ncol(mods0$dat)]
data <- mods0$dat[, names(models)]
} else {
data <- mods0$dat
}
}
}
# Setup
p <- ncol(data)
n <- nrow(data)
vs <- colnames(data)
# Collect coefficients
mods <- lapply(models, function(z){
z2 <- matrix(coef(z), ncol = 1)
rownames(z2) <- names(coef(z))
return(z2)
})
# Removing intercept? And turning matrices into vectors
mods2 <- lapply(mods, function(z) z[which(rownames(z) %in% vs), ])
# Get pvalues
pvals <- lapply(models, function(z){
z1 <- is.na(coef(z))
z2 <- t(data.frame(summary(z)$coefficients))
z0 <- ifelse(any(z1), list(names(z1[!z1])), list(names(coef(z))))[[1]]
z3 <- z2[4, which(z0 %in% vs), drop = FALSE]
rownames(z3) <- NULL
return(z3[1, ])
})
# Get standard errors
ses <- lapply(models, function(z){
z1 <- is.na(coef(z))
z2 <- t(data.frame(summary(z)$coefficients))
z0 <- ifelse(any(z1), list(names(z1[!z1])), list(names(coef(z))))[[1]]
z3 <- z2[2, which(z0 %in% vs), drop = FALSE]
rownames(z3) <- NULL
return(z3[1, ])
})
# Turn them all into matrices
b <- matrix(0, p, p)
pvals2 <- ses2 <- matrix(1, p, p)
for(i in 1:p){
b[i, match(names(mods2[[i]]), vs)] <- mods2[[i]]
ses2[i, match(names(ses[[i]]), vs)] <- ses[[i]]
pvals2[i, match(names(pvals[[i]]), vs)] <- pvals[[i]]
}
# Compute results for each model separately
results <- lapply(1:p, function(z){
notype <- !"type" %in% names(attributes(mods0))
if(notype | ifelse(!notype, ifelse(attr(mods0, "type")[z] == "gaussian", TRUE, FALSE), TRUE)){
yhat <- predict(models[[z]])
deviance <- sum((data[, z] - yhat)^2)
s <- sqrt(deviance/n)
LL_model <- sum(dnorm(data[, z], mean = yhat, sd = s, log = TRUE))
k <- nrow(mods[[z]]) + 1
aic <- (2 * k) - (2 * LL_model)
bic <- (log(n) * k) - (2 * LL_model)
} else {
deviance <- deviance(models[[z]])
LL_model <- as.numeric(logLik(models[[z]]))
aic <- AIC(models[[z]])
bic <- BIC(models[[z]])
}
pees <- as.matrix(summary(models[[z]])$coefficients[, 4], ncol = 1) ###
return(list(deviance = deviance, LL_model = LL_model, AIC = aic, BIC = bic, model = mods[[z]], pvals = pees)) ###
})
# Not sure how this works...
if(!"noMods" %in% names(attributes(models))){pcor <- FALSE}
# Formatting base on whether moderators are included? Not sure... maybe related to variable selection
if("noMods" %in% names(attributes(models))){
inds <- ints <- mval <- vars1 <- intMats <- NULL
} else if("varMods" %in% names(attributes(models))){
nmods <- ifelse(attr(models, "exogenous") == TRUE, length(mods), length(mods) - 1)
inds0 <- lapply(mods, function(z) rownames(z)[grepl(":", rownames(z))])[1:nmods]
inds1 <- unlist(lapply(inds0, function(z) gsub(":.*", "", z)))
inds <- data.frame(outcome = rep(1:nmods, sapply(inds0, length)), interaction = unlist(inds0))
vars <- lapply(models, vcov)[1:nmods]
vars1 <- ints <- list()
for(i in 1:nrow(inds)){
ints[[i]] <- mods[[inds[i, 1]]][inds[i, 2], 1]
vars1[[i]] <- c(vars[[inds[i, 1]]][inds1[i], inds1[i]], vars[[inds[i, 1]]][inds[i, 2], inds[i, 2]], vars[[inds[i, 1]]][inds1[i], inds[i, 2]])
names(vars1[[i]]) <- c(inds1[i], inds[i, 2], "cov")
}
} else {
nmods <- ifelse(attr(models, "exogenous") == TRUE, length(mods), length(mods) - 1)
inds <- t(combn(1:nmods, 2))
ints <- vector("list", nrow(inds))
for(i in 1:nrow(inds)){
ints[[i]][1] <- mods[[inds[i, 1]]][nmods + inds[i, 2], ]
ints[[i]][2] <- mods[[inds[i, 2]]][nmods + inds[i, 1] + 1, ]
}
vars <- lapply(models, vcov)[1:nmods]
vars1 <- list()
for(i in 1:nmods){
vars1[[i]] <- vector("list", nmods - 1)
for(j in 1:(nmods - 1)){
vars1[[i]][[j]] <- c(vars[[i]][j + 1, j + 1], vars[[i]][j + nmods + 1, j + nmods + 1], vars[[i]][j + 1, j + nmods + 1])
names(vars1[[i]][[j]]) <- c(colnames(vars[[i]])[j + 1], colnames(vars[[i]])[j + nmods + 1], "cov")
}
names(vars1[[i]]) <- colnames(vars[[i]])[2:nmods]
}
names(vars1) <- colnames(data)[1:nmods]
}
# Function for converting betas to GGM
b2ggm <- function(b, rule = "AND", pcor = FALSE, threshold = FALSE, n = NULL){
rule <- match.arg(tolower(rule), c("and", "or"))
if(rule == "and" & pcor == FALSE){
bb <- cbind(b[upper.tri(b)], t(b)[upper.tri(t(b))])
notBoth <- !apply(bb, 1, function(z) (z[1] == 0 & z[2] == 0) | (z[1] != 0 & z[2] != 0))
if(any(notBoth)){
bb[notBoth, ] <- 0
b[upper.tri(b)] <- bb[, 1]
b <- t(b)
b[upper.tri(b)] <- bb[, 2]
b <- t(b)
}
}
if(pcor != FALSE){
bb <- sign(b) * sqrt(b * t(b))
if(pcor == 'cor'){
diag(bb) <- 1
bb <- corpcor::pcor2cor(bb)
} else if(grepl('cor_auto', pcor)){
bb <- qgraph::cor_auto(data, npn.SKEPTIC = TRUE)
if(pcor == 'cor_auto2'){bb <- corpcor::cor2pcor(bb)}
}
diag(bb) <- 0
if(threshold != FALSE){
pcor <- ifelse(isTRUE(pcor) | grepl('cor', pcor), 'none', pcor)
if(is.character(threshold)){pcor <- threshold}
if(!is.numeric(threshold)){threshold <- .05}
dimnames(bb) <- rep(list(paste0("X", 1:ncol(bb))), 2)
sigMat <- ifelse(psych::corr.p(bb, n, adjust = pcor)[[4]] <= threshold, 1, 0)
sigMat0 <- matrix(0, ncol(bb), ncol(bb))
sigMat0[upper.tri(sigMat0)] <- sigMat[upper.tri(sigMat)]
sigMat0 <- as.matrix(Matrix::forceSymmetric(sigMat0))
bb <- bb * sigMat0
bb <- unname(bb)
}
return(bb)
} else {
return((b + t(b))/2)
}
}
# If there are moderators in the model, AND you want a conditional network
if(!is.null(mval)){
margSE <- function(x, vars){sqrt(vars[1] + ((x^2) * vars[2]) + (2 * x * vars[3]))}
if("varMods" %in% names(attributes(models))){
inds1.1 <- match(inds1, vs)
for(i in 1:length(ints)){
b[inds[i, 1], inds1.1[i]] <- b[inds[i, 1], inds1.1[i]] + (mval * ints[[i]])
ses[[inds[i, 1]]][inds1[i]] <- margSE(mval, vars1[[i]])
}
for(i in 1:p){ses2[i, match(names(ses[[i]]), vs)] <- ses[[i]]}
} else {
for(i in 1:length(ints)){
b[inds[i,1], inds[i,2]] <- b[inds[i,1], inds[i,2]] + (mval * ints[[i]][1])
b[inds[i,2], inds[i,1]] <- b[inds[i,2], inds[i,1]] + (mval * ints[[i]][2])
}
inds2 <- rbind(inds, cbind(inds[, 2], inds[, 1]))
inds2 <- inds2[order(inds2[, 1]), ]
inds3 <- cbind(inds2[, 1], rep(c(1:(p - 1)), p))
for(i in 1:nrow(inds3)){ses[[inds3[i, 1]]][inds3[i, 2]] <- margSE(mval, vars1[[inds3[i, 1]]][[inds3[i, 2]]])}
for(i in 1:p){ses2[i, match(names(ses[[i]]), vs)] <- ses[[i]]}
}
bmval <- b
dimnames(bmval) <- rep(list(colnames(data)), 2)
dfs <- matrix(sapply(models, function(z) z$df.residual), ncol = p, nrow = p)
pvals2 <- (2 * pt(abs(b/ses2), df = dfs, lower.tail = FALSE))
if(any(is.na(pvals2))){pvals2[is.na(pvals2)] <- 1}
}
# Thresholding!
if(threshold != FALSE & pcor == FALSE){
if(threshold == TRUE){threshold <- .05}
b <- b * ifelse(pvals2 <= threshold, 1, 0)
}
# PRODUCE THE NETWORK
bb <- b2ggm(b, rule = rule, pcor = pcor, threshold = threshold, n = n)
# getEdgeColors function -- CHECK
getEdgeColors <- function(adjMat){
obj <- sign(as.vector(adjMat))
colMat <- rep(NA, length(obj))
if(any(obj == 1)){colMat[obj == 1] <- "darkgreen"}
if(any(obj == 0)){colMat[obj == 0] <- "darkgrey"}
if(any(obj == -1)){colMat[obj == -1] <- "red"}
colMat <- matrix(colMat, ncol = ncol(adjMat), nrow = nrow(adjMat))
colnames(colMat) <- colnames(adjMat)
rownames(colMat) <- rownames(adjMat)
colMat
}
# Making the edge colors; more uncertainty around noMods
if(!"noMods" %in% names(attributes(models))){
if(useCIs & nsims > 0 & attr(models, "exogenous") == TRUE){
cis <- margCIs(mods = mods0, alpha = ifelse(threshold == FALSE, .05, threshold), nsims = nsims)
modEdgesNW <- getInts(x = cis, allInts = TRUE)
} else {
modEdgesNW <- ifelse(mods0$Bx$px <= ifelse(threshold == FALSE, .05, threshold), 1, 0)
if(any(mods0$Bx$px == 0)){modEdgesNW <- modEdgesNW * ifelse(mods0$Bx$px == 0, 0, 1)}
colnames(modEdgesNW) <- rownames(modEdgesNW)
}
modEdges <- t(modEdgesNW) * modEdgesNW
modEdgesNW <- (modEdgesNW * (mlty - 1)) + 1
modEdges <- (modEdges * (mlty - 1)) + 1
rule <- match.arg(tolower(rule), c("and", "or"))
if(rule == "or"){
modEdges <- modEdgesNW + t(modEdgesNW)
modEdges[modEdges == 2] <- 1
modEdges[modEdges > 2] <- mlty
}
intMat1 <- mods0$Bx$bx
intPs <- mods0$Bx$px
if(any(intPs == 0)){intPs[intPs == 0] <- 1}
if(threshold != FALSE){intMat1 <- intMat1 * ifelse(intPs <= threshold, 1, 0)}
intMat2 <- b2ggm(intMat1, rule = rule, pcor = FALSE)
diag(intMat1) <- diag(intMat2) <- 0
intMats <- list(avgInts = t(intMat2), nwInts = list(adj2NW = t(intMat1), pvals2NW = t(intPs)))
} else {
modEdges <- modEdgesNW <- matrix(1, p, p)
}
# Format results
diag(modEdges) <- diag(modEdgesNW) <- 0
dimnames(b) <- dimnames(bb) <- dimnames(pvals2) <- rep(list(colnames(data)), 2)
names(mods) <- names(models) <- names(results) <- colnames(data)
out <- list(adjMat = bb, edgeColors = getEdgeColors(bb), modEdges = t(modEdges),
nodewise = list(adjNW = t(b), edgeColsNW = getEdgeColors(t(b)),
pvalsNW = t(pvals2), modEdgesNW = t(modEdgesNW)),
interactions = list(intMats = intMats, inds = inds, ints = ints, coefvars = vars1))
# Making binary edges grey
if(binarize){
out$adjMat[out$adjMat != 0] <- 1
out$edgeColors[out$edgeColors != 'darkgrey'] <- 'darkgrey'
}
# More noMods uncertainty...
if("noMods" %in% names(attributes(models))){
out[c("interactions", "modEdges")] <- NULL
out[["nodewise"]]["modEdgesNW"] <- NULL
} else if(attr(models, "exogenous") == FALSE){
out[["modEdges"]] <- rbind(cbind(out[["modEdges"]], 1), 1)
out[["nodewise"]][["modEdgesNW"]] <- rbind(cbind(out[["nodewise"]][["modEdgesNW"]], 1), 1)
colnames(out$modEdges)[p] <- rownames(out$modEdges)[p] <- colnames(mods0$dat)[p]
colnames(out$nodewise$modEdgesNW)[p] <- rownames(out$nodewise$modEdgesNW)[p] <- colnames(mods0$dat)[p]
attributes(out)$moderator <- colnames(mods0$dat)[ncol(mods0$dat)]
} else {
if(useCIs){out$interactions$cis <- cis}
attributes(out)$moderator <- colnames(mods0$dat)[ncol(mods0$dat)]
if("Bm" %in% names(mods0)){
mp <- ncol(bb)
madj <- medges <- matrix(0, mp + 1, mp + 1)
md <- matrix(FALSE, mp + 1, mp + 1)
madj[1:mp, 1:mp] <- bb
dimnames(madj) <- dimnames(medges) <- dimnames(md) <- rep(list(colnames(mods0$dat)), 2)
if(nrow(mods0$Bm) != p){mpp <- which(colnames(data) %in% rownames(mods0$Bm))} else {mpp <- 1:mp}
if(threshold != FALSE){
madj[(mp + 1), mpp] <- ifelse(mods0$Bm[, 4] <= threshold, mods0$Bm[, 1], 0)
} else {
madj[(mp + 1), mpp] <- mods0$Bm[, 1]
}
medges[1:mp, 1:mp] <- t(modEdges)
medges[(mp + 1), 1:mp] <- 1
md[(mp + 1), 1:mp] <- TRUE
ints <- out$interactions
out$interactions <- NULL
out$mnet <- list(adjMat = madj, edgeColors = getEdgeColors(madj), modEdges = medges, d = md)
out$interactions <- ints
}
}
# Format output
out$mods <- results
out$fitobj <- models
out$data <- data
if(!is.null(mval)){
attributes(out)$mval <- mval
if(threshold != FALSE){out$nodewise[[paste0("adjMval", mval)]] <- t(bmval)}
}
# Set ggm attribute
attributes(out)$ggm <- TRUE
# RETURN
return(out)
}
#' Provides model coefficients with confidence intervals
#'
#' Requires that either \code{fitobj} or \code{SURfit} is included in the object
#' from \code{\link{fitNetwork}}. Returns a list of nodewise model coefficients,
#' including confidence intervals computed from the estimated standard errors.
#'
#' The \code{select} column in the output indicates whether the variable would
#' be selected given the supplied alpha level.
#'
#' @param fit Output from \code{\link{fitNetwork}}, or either the
#' \code{fixedNets} or \code{betweenNet} element of the output from
#' \code{\link{mlGVAR}}
#' @param allNames Character vector containing all the predictor names. Do not
#' change, as these are automatically detected.
#' @param alpha Type 1 error rate. The complement of the confidence level.
#'
#' @return List of tables containing model coefficients along with confidence
#' intervals
#' @export
#'
#' @seealso \code{\link{fitNetwork}, \link{plotCoefs}}
#'
#' @examples
#' x <- fitNetwork(ggmDat)
#' getFitCIs(x)
getFitCIs <- function(fit, allNames = NULL, alpha = .05){
if("SURnet" %in% names(fit)){
if(!'SURfit' %in% names(fit)){stop('Requires SURfit')}
if(is(fit$SURfit, 'fitCoefs')){return(fit$SURfit)}
fit <- append(fit$SURnet, list(fitobj = fit$SURfit$eq))
}
if(is.null(allNames)){
allNames <- lapply(fit$mods, function(z) rownames(z$model)[-1])
} else if(all(c("mods", "call") %in% names(allNames))){
allNames <- lapply(allNames$mods, function(z) rownames(z$model)[-1])
}
if('fitobj' %in% names(fit)){
fitobj <- fit$fitobj
} else {
fitobj <- fit
}
if(is(fitobj, 'fitCoefs')){return(fitobj)}
fitCoefs <- suppressWarnings(suppressMessages(
lapply(seq_along(fitobj), function(z){
coefs1 <- summary(fitobj[[z]])$coefficients[-1, , drop = FALSE]
if(nrow(coefs1) == 0){return(NA)}
coefs2 <- confint(fitobj[[z]], level = 1 - alpha)[-1, , drop = FALSE]
coefs <- cbind.data.frame(coefs1, coefs2)
colnames(coefs) <- c("b", "se", "t", "P", "lower", "upper")
coefs <- coefs[match(allNames[[z]], rownames(coefs)), ]
coefs <- data.frame(predictor = factor(allNames[[z]]), lower = coefs$lower,
b = coefs$b, upper = coefs$upper, Pvalue = coefs$P,
select = ifelse(is.na(coefs$b), FALSE, TRUE))
rownames(coefs) <- 1:nrow(coefs)
if(any(is.na(coefs))){coefs[is.na(coefs)] <- NA}
return(coefs)
})))
names(fitCoefs) <- names(fitobj)
class(fitCoefs) <- c('list', 'fitCoefs')
return(fitCoefs)
}
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.