Nothing
## Runs blimp
# Copyright Brian Keller 2024, all rights reserved
#' Wrapper functions to provide Blimp functions in R
#' @description
#' `rblimp` will generate the input, run the script, and load most the saved data into an R object. `rblimp_fcs`
#' is used to specify the FCS command in Blimp. `rblimp_syntax` will generate the Blimp syntax file only.
#' @param model a character string or vector/list of character strings. Specifies Blimp's MODEL command. See details.
#' @param data a [`data.frame`] or a [`SIMULATE`] object.
#' If a data.frame, the data set used by Blimp.
#' If a SIMULATE object (created with [`SIMULATE()`]), Blimp will generate simulated data instead of using existing data
#' @param burn an integer. The number of burn-in iterations to be run
#' @param iter an integer. The number of post burn-in iterations to be run
#' @param seed a positive integer. The seeding value for Blimp's pseudo random number generator
#' @param thin an integer. The thinning interval for imputations only.
#' @param nimps an integer. The number of imputations to save.
#' @param latent a character string, formula, or vector/list of character strings. Specifies Blimp's LATENT command. See details.
#' @param randomeffect a character string or vector/list of character strings. Specifies Blimp's RANDOMEFFECTS command.
#' @param parameters a character string or vector/list of character strings. Specifies Blimp's MODEL command. See details.
#' @param clusterid a character string, formula, or vector/list of character strings. Specifies Blimp's CLUSTERID command. See details.
#' @param timeid a character string, formula, or vector/list of character strings. Specifies Blimp's TIMEID command. See details.
#' @param weight a character string, formula, or vector/list of character strings. Specifies Blimp's WEIGHT command. See details.
#' @param ordinal a character string, formula, or vector/list of character strings. Specifies Blimp's ORDINAL command. See details.
#' @param nominal a character string, formula, or vector/list of character strings. Specifies Blimp's NOMINAL command. See details.
#' @param count a character string, formula, or vector/list of character strings. Specifies Blimp's COUNT command. See details.
#' @param center a character string, formula, or vector/list of character strings. Specifies Blimp's CENTER command. See details.
#' @param chains an integer, character string, or vector/list of character strings. Specifies Blimp's CHAINS command.
#' @param simple a character string or vector/list of character strings. Specifies Blimp's SIMPLE command. See details.
#' @param waldtest a character string or vector/list of character strings. Specifies Blimp's WALDTEST command. See details.
#' @param options a character string or vector/list of character strings. Specifies Blimp's OPTIONS command.
#' @param transform a character string or vector/list of character strings. Specifies Blimp's TRANSFORM command.
#' @param dropout a character string, formula, or vector/list of character strings. Specifies Blimp's DROPOUT command. See details.
#' @param filter a character string. Specifies Blimp's FILTER command.
#' @param fixed a character string, formula, or vector/list of character strings. Specifies Blimp's FIXED command. See details.
#' @param output a character string or vector/list of character strings. Specifies Blimp's OUTPUT command
#' @param tmpfolder a character string. If specified `rblimp` will use the given
#' file path as a temporary directory instead of creating one with [`tempdir`]
#' @param add_save a single logical value or a list of logical values.
#' If `TRUE` then saveLatent, saveResidual, and savePredicted will be included in OPTIONS command.
#' Otherwise, it will be coerced to a list. The elements of the list should labeled `latent`, `residual`, and `predicted`
#' each containing a single logical value that can be used to toggle on or off them individually.
#' Missing elements will be defaulted to `TRUE`.
#' @param print_output The type of output printed to the console.
#' `'iteration'` or logical `TRUE` is only iteration history, `'none'` or logical `FALSE`
#' suppresses all output to console, and `'all'` prints all output to console.
#' @param nopowershell Windows only. Uses cmd.exe with some limited functions (instead of powershell).
#' @details
#' The above functions require knowledge of specifying Blimp commands. Blimp's syntax commands are
#' documented in the \href{https://docs.google.com/document/d/1D3MS79CakuX9mVVvGH13B5nRd9XLttp69oGsvrIRK64/edit?usp=sharing}{Blimp User Manual}
#'
#' By default, these commands can be inputted as character strings that will be used to generate the syntax.
#' For multiple lined commands, you can wrap multiple strings into a character [`vector`] or a [`list`].
#' The appropriate semicolons will be specified, so they are not required in any character strings.
#' If specifying a character [`vector`] or a [`list`] for the `model`, providing names to each element
#' will be used as blocks in Blimp's model syntax. Similarly, specifying named elements can be used
#' for the `center` command to specify if you would like centering within a cluster or
#' grand mean centering. This also works for the `latent` input when requesting latent
#' variables at a specific cluster identifier.
#' See the \href{https://docs.google.com/document/d/1D3MS79CakuX9mVVvGH13B5nRd9XLttp69oGsvrIRK64/edit?usp=sharing}{Blimp User Manual}
#' for more details about types of centering and specifying latent variables.
#'
#' In addition, R's formula syntax can be used to specify lists of variables
#' in place of character strings. For example, specifying the CLUSTERID command with
#' the variable `id` can be specified as ` ~ id` as opposed to a character string.
#' Similarly, `+` can be used to specify multiple variables. For example, to specify
#' two variables as ordinal the formula would be: `~ x1 + x2`. Finally, this can also be
#' used to specify centering and latent variables. For example, to center `x1` and `x2`
#' within cluster we can specify: `cwc ~ x1 + x2`.
#'
#' Running `rblimp` will also check if blimp is up to date.
#' See details in [`rblimp_source`] for more information.
#'
#' @seealso
#' - [`SIMULATE()`] for creating simulated data to fit within [`rblimp()`]
#' - [`rblimp_sim()`] for generating simulated datasets
#'
#' @returns [`blimp_obj`]
#' @importFrom graphics abline axis dotchart hist lines points
#' @importFrom methods new show
#' @importFrom stats coef median model.matrix ppoints pt qnorm quantile resid sd start vcov setNames
#' @importFrom utils read.csv read.table write.csv
#' @examplesIf has_blimp()
#' # Generate Data with `rblimp_sim`
#' mydata <- rblimp_sim(
#' c(
#' 'f ~ normal(0, 1)',
#' 'x1:x5 ~ normal(f, 1)',
#' 'y ~ normal(10 + 0.3*f, 1 - .3^2)'
#' ),
#' n = 500,
#' seed = 19723,
#' variables = c('y', 'x1:x5')
#' )
#'
#' # Fit SEM Model
#' model <- rblimp(
#' list(
#' structure = 'y ~ f',
#' measurement = 'f -> x1:x5'
#' ),
#' mydata,
#' seed = 3927,
#' latent = ~ f
#' )
#'
#' # View results
#' summary(model)
#' @export
rblimp <- function(model,
data,
burn = 10000,
iter = 10000,
seed,
thin,
nimps,
latent,
randomeffect,
parameters,
clusterid,
timeid,
weight,
ordinal,
nominal,
count,
center,
chains,
simple,
waldtest,
options,
transform,
dropout,
filter,
fixed,
output,
tmpfolder,
add_save = TRUE,
print_output = TRUE,
nopowershell = FALSE) {
# Check inputs
if (length(burn) != 1 || !is.numeric(burn) || burn < 0) throw_error(
"{.arg burn} must be a positive numeric value"
)
if (length(iter) != 1 || !is.numeric(iter) || iter < 0) throw_error(
"{.arg iter} must be a positive numeric value"
)
if (!missing(nimps)) {
if (length(nimps) != 1 || !is.numeric(nimps) || nimps < 0) throw_error(
"{.arg nimps} must be a positive numeric value"
)
}
# Check output
if (!is.logical(print_output)) {
if (print_output != "all" & print_output != "none" & print_output != "iteration") {
throw_error("Unrecognized {.arg output} choice: {print_output}")
}
} else {
if (print_output) {
print_output <- "iteration"
} else {
print_output <- "none"
}
}
# Get temp folder if needed
if (missing(tmpfolder)) {
tmpfolder <- tempfile()
if (!dir.create(tmpfolder)) throw_error(
"Was unable to create temporary directory."
)
}
# Check if data is a simulation specification or data.frame
is_simulation <- inherits(data, "blimp_simulate")
if (!is_simulation) {
# Check if data.frame
if (!is.data.frame(data)) throw_error(
"The {.arg data} must be a data.frame or a blimp_simulate object"
)
# Convert to data frame if a tibble
if ("tbl_df" %in% class(data)) {
cli::cli_alert_warning("Converting data to `data.frame`")
data <- as.data.frame(data)
}
# Get attributes loop over and convert to numeric
att_list <- vector('list', NCOL(data))
for (i in seq_along(att_list)) {
if (!is.numeric(data[, i])) {
att_list[[i]] <- attributes(data[,i])
data[, i] <- as.numeric(data[, i])
}
}
# Write data to temp folder
write.csv(data, file.path(tmpfolder, "data.csv"), row.names = FALSE, quote = FALSE)
} else {
# For simulation, no data file needed
att_list <- NULL
}
# Create saveCommand
saveCmd <- vector('list', 5L)
saveCmd[[1]] <- "estimates = estimates.csv"
saveCmd[[2]] <- "iterations = iter.csv"
saveCmd[[3]] <- "psr = psr.csv"
saveCmd[[4]] <- "avgimp = avgimp.csv"
saveCmd[[5]] <- "varimp = varimp.csv"
if (!missing(nimps)) saveCmd[[length(saveCmd) + 1]] <- "stacked = imps.csv"
if (!missing(waldtest)) saveCmd[[length(saveCmd) + 1]] <- "waldtest = waldtest.csv"
if (!missing(simple)) saveCmd[[length(saveCmd) + 1]] <- "simple = simple.csv"
## append to options
if (is.logical(add_save) && length(add_save) == 1) {
if (add_save) {
if (missing(options)) options <- NULL
options <- c(options, "savepredicted savelatent saveresidual")
}
}
else {
add_save <- as.list(add_save)
if (!is.null(add_save$predicted)) {
if (add_save$predicted) {
if (missing(options)) options <- NULL
options <- c(options, "savepredicted")
}
} else {
if (missing(options)) options <- NULL
options <- c(options, "savepredicted")
}
if (!is.null(add_save$latent)) {
if (add_save$latent) {
if (missing(options)) options <- NULL
options <- c(options, "savelatent")
}
} else {
if (missing(options)) options <- NULL
options <- c(options, "savelatent")
}
if (!is.null(add_save$residual)) {
if (add_save$residual) {
if (missing(options)) options <- NULL
options <- c(options, "saveresidual")
}
} else {
if (missing(options)) options <- NULL
options <- c(options, "saveresidual")
}
}
# Write input file
imp_file <- rblimp_syntax(
model,
data,
burn,
iter,
seed,
thin,
nimps,
latent,
randomeffect,
parameters,
clusterid,
timeid,
weight,
ordinal,
nominal,
count,
transform,
dropout,
filter,
fixed,
center,
chains,
simple,
waldtest,
options,
saveCmd,
output
)
# For data.frame: set data path and remove variables
# For simulation: keep variables, no data path
if (!is_simulation) {
imp_file$data <- file.path(tmpfolder, "data.csv")
imp_file$variables <- NULL
}
# Write imp file
fileConn <- file(file.path(tmpfolder, "input.imp"))
writeLines(as.character(imp_file), fileConn)
close(fileConn)
# Run File
result <- rblimp_source(
file.path(tmpfolder, "input.imp"),
plots = TRUE,
print_output,
nopowershell
)
exitcode <- attr(result, "exitcode")
# Check exit code
if (length(exitcode) == 1) {
if (exitcode == "1") {
if (missing(tmpfolder)) unlink(tmpfolder)
throw_error("Blimp had an error. Check output.")
}
}
# Read parameter labels
lab2 <- lab <- read.table(file.path(tmpfolder, "plots", "labels.dat"))[-1, ]
# Set outcome, parameter, and block type
oname <- lab$V1
ptype <- lab$V2
block <- lab$V5
# Handle parameters
oname[block == '#_parameter'] <- '#_parameter'
block[block == '#_parameter'] <- '#parameter'
# Handle predictor models
lab$V3[startsWith(ptype, "Level-")] |>
sapply(\(x) {
if(grepl('Var\\(|(Residual Var\\.)', x)) return('Variance')
else if (grepl('~', x)) return('Beta')
else if (grepl('Threshold', x)) return('Threshold')
else if (startsWith(x, 'Grand Mean#')) return('Grand Mean')
return ('Beta')
}) -> ptype[startsWith(ptype, "Level-")]
ptype[startsWith(lab$V3, 'Grand Mean#')] <- 'Grand Mean'
# parse labels file and create figure titles
lab$V2[lab$V3 == "Intercept" & lab$V2 != "Odds Ratio"] <- "intercept"
lab$V2[lab$V2 == "Beta" | grepl("Level-", lab$V2, fixed = TRUE) & (lab$V3 != "Residual Var.")] <- "regressed on"
lab$V2[lab$V2 == "Standardized Beta" | grepl("Level-", lab$V2, fixed = TRUE) & (lab$V3 != "Residual Var.")] <- "regressed on (standardized)"
lab$V2[lab$V2 == "Variance" & lab$V3 == "L2 Intercept (i)"] <- "level-2 intercept variance"
lab$V2[lab$V2 == "Variance" & lab$V3 == "L3 Intercept (i)"] <- "level-3 intercept variance"
lab$V2[lab$V2 == "Standard Deviation" & lab$V3 == "L2 Intercept (i)"] <- "level-2 intercept SD"
lab$V2[lab$V2 == "Standard Deviation" & lab$V3 == "L3 Intercept (i)"] <- "level-3 intercept SD"
lab$V2[grepl("L2 ", lab$V3, fixed = TRUE) & endsWith(lab$V3, ", Intercept") & lab$V2 == "Variance"] <- "level-2 intercept covariance with"
lab$V2[grepl("L3 ", lab$V3, fixed = TRUE) & endsWith(lab$V3, ", Intercept") & lab$V2 == "Variance"] <- "level-3 intercept covariance with"
lab$V2[grepl(",", lab$V3, fixed = TRUE) & grepl("L2 ", lab$V3, fixed = TRUE) & lab$V2 == "Variance"] <- "level-2 covariance between"
lab$V2[grepl(",", lab$V3, fixed = TRUE) & grepl("L3 ", lab$V3, fixed = TRUE) & lab$V2 == "Variance"] <- "level-3 covariance between"
lab$V2[grepl("L2 ", lab$V3, fixed = TRUE) & lab$V2 == "Variance"] <- "level-2 slope variance of"
lab$V2[grepl("L3 ", lab$V3, fixed = TRUE) & lab$V2 == "Variance"] <- "level-3 slope variance of"
lab$V2[grepl("L2 ", lab$V3, fixed = TRUE) & endsWith(lab$V3, ", Intercept") & lab$V2 == "Standard Deviation"] <- "level-2 intercept correlation with"
lab$V2[grepl("L3 ", lab$V3, fixed = TRUE) & endsWith(lab$V3, ", Intercept") & lab$V2 == "Standard Deviation"] <- "level-3 intercept correlation with"
lab$V2[grepl(",", lab$V3, fixed = TRUE) & grepl("L2 ", lab$V3, fixed = TRUE) & lab$V2 == "Standard Deviation"] <- "level-2 correlation between"
lab$V2[grepl(",", lab$V3, fixed = TRUE) & grepl("L3 ", lab$V3, fixed = TRUE) & lab$V2 == "Standard Deviation"] <- "level-3 correlation between"
lab$V2[grepl("L2 ", lab$V3, fixed = TRUE) & lab$V2 == "Standard Deviation"] <- "level-2 slope SD of"
lab$V2[grepl("L3 ", lab$V3, fixed = TRUE) & lab$V2 == "Standard Deviation"] <- "level-3 slope SD of"
lab$V2[lab$V2 == "Level-1" & lab$V3 == "Residual Var."] <- "level-1 residual variance"
lab$V2[lab$V2 == "Level-2" & lab$V3 == "Residual Var."] <- "level-2 residual variance"
lab$V2[lab$V2 == "Level-3" & lab$V3 == "Residual Var."] <- "level-3 residual variance"
lab$V2[lab$V2 == "Variance" & lab$V3 == "Residual Var."] <- "residual variance"
lab$V2[lab$V2 == "Standard Deviation" & lab$V3 == "Residual SD"] <- "residual SD"
r2sel <- lab$V2 == "R2"
lab$V2[r2sel] <- paste("R2:", lab$V3[r2sel])
lab$V3[r2sel] <- ""
lab$V3 <- gsub("\\|", "dummy code", lab$V3)
delete <- c(
"Grand Mean", "Variance", "Residual Var.", "Tau", "L2 Intercept (i)",
"L3 Intercept (i)", "L2 (i),", "L3 (i),", "L2: ", "L3: ", "L2", "L3",
", Intercept", "Intercept", "Residual SD"
)
for (i in seq_along(delete)) lab$V3 <- gsub(delete[i], "", lab$V3, fixed = TRUE)
# Deal with odds ratio
lab$V3[lab$V2 == "Odds Ratio" & lab$V3 == ""] <- "intercept"
lab$V2[lab$V2 == "Odds Ratio"] <- "regressed on (odds ratio)"
lab$V2 <- tolower(lab$V2)
# Parse multivariate models - map each row to correct pairwise combination
cov_sel <- lab$V2 == "variance" & startsWith(lab$V3, "Cov(")
if (any(cov_sel)) {
cov_indices <- which(cov_sel)
unique_var_sets <- unique(lab$V1[cov_indices])
for (var_set in unique_var_sets) {
matching_indices <- cov_indices[lab$V1[cov_indices] == var_set]
vars <- strsplit(var_set, " ")[[1]]
if (length(vars) >= 2 && length(matching_indices) > 1) {
pairs <- combn(vars, 2, simplify = FALSE)
# Map each row to its corresponding pair
for (i in seq_along(matching_indices)) {
if (i <= length(pairs)) {
lab$V1[matching_indices[i]] <- paste0(pairs[[i]], collapse = '.')
}
}
} else if (length(matching_indices) == 1) {
# Single pair case
lab$V1[matching_indices[1]] <- paste0(vars[1:min(2, length(vars))], collapse = '.')
}
}
lab$V2[cov_sel] <- "covariance"
lab$V3[cov_sel] <- ""
}
cor_sel <- lab$V2 == "correlations" & startsWith(lab$V3, "Cor(")
if (any(cor_sel)) {
cor_indices <- which(cor_sel)
unique_var_sets <- unique(lab$V1[cor_indices])
for (var_set in unique_var_sets) {
matching_indices <- cor_indices[lab$V1[cor_indices] == var_set]
vars <- strsplit(var_set, " ")[[1]]
if (length(vars) >= 2 && length(matching_indices) > 1) {
pairs <- combn(vars, 2, simplify = FALSE)
# Map each row to its corresponding pair
for (i in seq_along(matching_indices)) {
if (i <= length(pairs)) {
lab$V1[matching_indices[i]] <- paste0(pairs[[i]], collapse = '.')
}
}
} else if (length(matching_indices) == 1) {
# Single pair case
lab$V1[matching_indices[1]] <- paste0(vars[1:min(2, length(vars))], collapse = '.')
}
}
lab$V3[cor_sel] <- ""
}
# Parse parameters
param_select <- lab$V1 == lab$V2 & lab$V2 == lab$V3
lab$V1[param_select] <- "Parameter:"
lab$V3[param_select] <- ""
# Trim white space
lab$V3 <- trimws(lab$V3)
# Set up lab names
lab_names <- vector("character", nrow(lab))
for (i in seq_along(lab_names)) {
lab_names[i] <- paste(lab[i, 1], lab[i, 2], lab[i, 3], sep = ".")
}
# Remove trailing period
lab_names[endsWith(lab_names, ".")] <- gsub(
".{1}$", "", lab_names[endsWith(lab_names, ".")]
)
# Row Name parsing
lab2$V2[lab2$V2 == "Beta" & lab2$V3 == "Intercept"] <- "~ Intercept"
lab2$V2[lab2$V2 == "Beta" | grepl("Level-", lab2$V2, fixed = TRUE) & (lab2$V3 != "Residual Var.")] <- "~"
lab2$V3[lab2$V2 == "Standardized Beta" | grepl("Level-", lab2$V2, fixed = TRUE) & (lab2$V3 != "Residual Var.")] <-
paste0(lab2$V3[lab2$V2 == "Standardized Beta" | grepl("Level-", lab2$V2, fixed = TRUE) & (lab2$V3 != "Residual Var.")], " (standardized)")
lab2$V2[lab2$V2 == "Standardized Beta" | grepl("Level-", lab2$V2, fixed = TRUE) & (lab2$V3 != "Residual Var.")] <- "~"
lab2$V2[lab2$V2 == "Variance" & lab2$V3 == "L2 Intercept (i)"] <- "level-2 intercept variance"
lab2$V2[lab2$V2 == "Variance" & lab2$V3 == "L3 Intercept (i)"] <- "level-3 intercept variance"
lab2$V2[lab2$V2 == "Standard Deviation" & lab2$V3 == "L2 Intercept (i)"] <- "level-2 intercept SD"
lab2$V2[lab2$V2 == "Standard Deviation" & lab2$V3 == "L3 Intercept (i)"] <- "level-3 intercept SD"
lab2$V2[grepl(",", lab2$V3, fixed = TRUE) & grepl("L2 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Variance"] <- "level-2 covariance between"
lab2$V2[grepl(",", lab2$V3, fixed = TRUE) & grepl("L3 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Variance"] <- "level-3 covariance between"
lab2$V2[grepl("L2 ", lab2$V3, fixed = TRUE) & endsWith(lab2$V3, ", Intercept") & lab2$V2 == "Variance"] <- "level-2 intercept covariance with"
lab2$V2[grepl("L3 ", lab2$V3, fixed = TRUE) & endsWith(lab2$V3, ", Intercept") & lab2$V2 == "Variance"] <- "level-3 intercept covariance with"
lab2$V2[grepl("L2 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Variance"] <- "level-2 slope variance of"
lab2$V2[grepl("L3 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Variance"] <- "level-3 slope variance of"
lab2$V2[grepl(",", lab2$V3, fixed = TRUE) & grepl("L2 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Standard Deviation"] <- "level-2 correlation between"
lab2$V2[grepl(",", lab2$V3, fixed = TRUE) & grepl("L3 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Standard Deviation"] <- "level-3 correlation between"
lab2$V2[grepl("L2 ", lab2$V3, fixed = TRUE) & endsWith(lab2$V3, ", Intercept") & lab2$V2 == "Standard Deviation"] <- "level-2 intercept correlation with"
lab2$V2[grepl("L3 ", lab2$V3, fixed = TRUE) & endsWith(lab2$V3, ", Intercept") & lab2$V2 == "Standard Deviation"] <- "level-3 intercept correlation with"
lab2$V2[grepl("L2 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Standard Deviation"] <- "level-2 slope SD of"
lab2$V2[grepl("L3 ", lab2$V3, fixed = TRUE) & lab2$V2 == "Standard Deviation"] <- "level-3 slope SD of"
lab2$V2[lab2$V2 == "Level-1" & lab2$V3 == "Residual Var."] <- "level-1 residual variance"
lab2$V2[lab2$V2 == "Level-2" & lab2$V3 == "Residual Var."] <- "level-2 residual variance"
lab2$V2[lab2$V2 == "Level-3" & lab2$V3 == "Residual Var."] <- "level-3 residual variance"
lab2$V2[lab2$V2 == "Variance" & lab2$V3 == "Residual Var."] <- "residual variance"
lab2$V2[lab2$V2 == "Standard Deviation" & lab2$V3 == "Residual SD"] <- "residual SD"
r2sel <- lab2$V2 == "R2"
lab2$V2[r2sel] <- paste("R2:", lab2$V3[r2sel])
lab2$V3[r2sel] <- ""
lab2$V3 <- gsub("\\|", "dummy code", lab2$V3)
delete <- c(
"Grand Mean", "Variance", "Residual Var.", "Tau", "L2 Intercept (i)",
"L3 Intercept (i)", "L2 (i),", "L3 (i),", "L2: ", "L3: ",
"L2", "L3",", Intercept", "Intercept", "Residual SD"
)
for (i in seq_along(delete)) lab2$V3 <- gsub(delete[i], "", lab2$V3, fixed = TRUE)
# Deal with odds ratio
lab2$V3[lab2$V2 == "Odds Ratio" & lab2$V3 == ""] <- "Intercept"
lab2$V3[lab2$V2 == "Odds Ratio"] <- paste0(lab2$V3[lab2$V2 == "Odds Ratio"], " (odds ratio)")
lab2$V2[lab2$V2 == "Odds Ratio"] <- "~"
# Parse multivariate models - map each row to correct pairwise combination for row names
cov_sel <- lab2$V2 == "Variance" & startsWith(lab2$V3, "Cov(")
if (any(cov_sel)) {
cov_indices <- which(cov_sel)
unique_var_sets <- unique(lab2$V1[cov_indices])
for (var_set in unique_var_sets) {
matching_indices <- cov_indices[lab2$V1[cov_indices] == var_set]
vars <- strsplit(var_set, " ")[[1]]
if (length(vars) >= 2 && length(matching_indices) > 1) {
pairs <- combn(vars, 2, simplify = FALSE)
# Map each row to its corresponding pair
for (i in seq_along(matching_indices)) {
if (i <= length(pairs)) {
lab2$V1[matching_indices[i]] <- "Cov("
lab2$V2[matching_indices[i]] <- paste0(pairs[[i]], collapse = ', ')
lab2$V3[matching_indices[i]] <- ")"
}
}
} else if (length(matching_indices) == 1) {
# Single pair case
lab2$V1[matching_indices[1]] <- "Cov("
lab2$V2[matching_indices[1]] <- paste0(vars[1:min(2, length(vars))], collapse = ', ')
lab2$V3[matching_indices[1]] <- ")"
}
}
}
cor_sel <- lab2$V2 == "Correlations" & startsWith(lab2$V3, "Cor(")
if (any(cor_sel)) {
cor_indices <- which(cor_sel)
unique_var_sets <- unique(lab2$V1[cor_indices])
for (var_set in unique_var_sets) {
matching_indices <- cor_indices[lab2$V1[cor_indices] == var_set]
vars <- strsplit(var_set, " ")[[1]]
if (length(vars) >= 2 && length(matching_indices) > 1) {
pairs <- combn(vars, 2, simplify = FALSE)
# Map each row to its corresponding pair
for (i in seq_along(matching_indices)) {
if (i <= length(pairs)) {
lab2$V1[matching_indices[i]] <- "Cor("
lab2$V2[matching_indices[i]] <- paste0(pairs[[i]], collapse = ', ')
lab2$V3[matching_indices[i]] <- ")"
}
}
} else if (length(matching_indices) == 1) {
# Single pair case
lab2$V1[matching_indices[1]] <- "Cor("
lab2$V2[matching_indices[1]] <- paste0(vars[1:min(2, length(vars))], collapse = ', ')
lab2$V3[matching_indices[1]] <- ")"
}
}
}
# Parse parameters
param_select <- lab2$V1 == lab2$V2 & lab2$V2 == lab2$V3
lab2$V1[param_select] <- "Parameter:"
lab2$V3[param_select] <- ""
# Trim white space
lab2$V3 <- trimws(lab2$V3)
# Set up lab row names
lab_row_names <- vector("character", nrow(lab2))
for (i in seq_along(lab_row_names)) {
lab_row_names[i] <- paste(lab2[i, 1], lab2[i, 2], lab2[i, 3])
}
# Read data in
output <- list()
output$estimates <- as.matrix(read.csv(file.path(tmpfolder, "estimates.csv"), header = TRUE))
rownames(output$estimates) <- trimws(lab_row_names)
colnames(output$estimates) <- gsub('^X', '', colnames(output$estimates))
colnames(output$estimates) <- gsub('\\.$', '%', colnames(output$estimates))
output$iterations <- structure(
read.csv(file.path(tmpfolder, "iter.csv"), header = FALSE),
parameter_type = ptype
)
names(output$iterations) <- lab_names
# Set up outcome_name
attr(output$iterations, 'outcome_name') <- oname
# Set up outcome_name
attr(output$iterations, 'block_name') <- block
# Set up parameter_type
attr(output$iterations, 'parameter_type') <- ptype |> sapply(\(x) {
switch(
x,
Variance = 1,
Correlations = 1,
`residual SD` = 1,
`Standard Deviation` = 1,
Beta = 2,
`Grand Mean` = 2,
`Standardized Beta` = 3,
`Odds Ratio` = 3,
R2 = 4,
Threshold = 5,
6
)
}) |> factor(seq_len(6), labels = c(
'Var/Cov/Cor',
'Coefficient',
'Standardized',
'Rsquare',
'Threshold',
'Other'
))
output$psr <- tryCatch({
read.csv(file.path(tmpfolder, "psr.csv"), header = FALSE)
}, error = function(e) {
matrix(nrow = 0, ncol = NROW(lab_names)) |> as.data.frame()
})
names(output$psr) <- lab_names
output$burn <- list()
files <- list.files(file.path(tmpfolder, "plots"), pattern = "*.csv")
for (i in seq_along(files)) {
if (files[i] == "labels.dat") next
index <- as.numeric(gsub("[A-z \\.\\(\\)]", "", files[i]))
output$burn[[index]] <- cbind(index, read.table(file.path(tmpfolder, "plots", files[i]), sep = ","))
names(output$burn[[index]]) <- c("chain", "iteration", lab_names)
}
names(output$psr) <- lab_names
if (file.exists(file.path(tmpfolder, "imps.csv"))) {
tmp <- read.csv(file.path(tmpfolder, "imps.csv"), skip = 1, header = FALSE)
file.path(tmpfolder, "imps.csv") |> readLines(1) |>
parse_csv_header() -> names(tmp)
# Loop over and add attributes back in
for (i in seq_along(att_list)) {
if (!is.null(att_list[[i]])) {
tryCatch(
{attributes(tmp[, i + 1]) <- att_list[[i]]},
error = function(e) NULL
)
}
}
# Split imputations
output$imputations <- split(tmp[, -1, drop = FALSE], tmp[, 1])
} else {
output$imputations <- list()
}
# Waldtest
if (file.exists(file.path(tmpfolder, "waldtest.csv"))) {
output$waldtest <- read.csv(file.path(tmpfolder, "waldtest.csv"), header = TRUE)
} else {
output$waldtest <- data.frame(
test_number = numeric(),
df = numeric(),
statistic = numeric(),
probability = numeric()
)
}
# Simple
if (file.exists(file.path(tmpfolder, "simple.csv"))) {
output$simple <- read.csv(file.path(tmpfolder, "simple.csv"), skip = 1, header = FALSE)
file.path(tmpfolder, "simple.csv") |> readLines(1) |>
parse_csv_header() |> gsub(",", "", x = _) -> names(output$simple)
} else {
output$simple <- data.frame()
}
# Get average imputation
if (file.exists(file.path(tmpfolder, "avgimp.csv"))) {
output$average_imp <- read.csv(file.path(tmpfolder, "avgimp.csv"), skip = 1, header = FALSE)
file.path(tmpfolder, "avgimp.csv") |> readLines(1) |>
parse_csv_header() -> names(output$average_imp)
} else {
output$average_imp <- data.frame()
}
# Get variance of imputation
if (file.exists(file.path(tmpfolder, "varimp.csv"))) {
output$variance_imp <- read.csv(file.path(tmpfolder, "varimp.csv"), skip = 1, header = FALSE)
file.path(tmpfolder, "varimp.csv") |> readLines(1) |>
parse_csv_header() -> names(output$variance_imp)
} else {
output$variance_imp <- data.frame()
}
# Delete temp files
if (missing(tmpfolder)) unlink(tmpfolder)
# Return output
return(
new("blimp_obj",
call = match.call(), estimates = output$estimates, burn = output$burn,
iterations = output$iterations, psr = output$psr,
imputations = output$imputations, average_imp = output$average_imp,
variance_imp = output$variance_imp, waldtest = output$waldtest,
simple = output$simple, syntax = imp_file, output = result
)
)
}
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.