Package 'psychonetrics'

Title: Structural Equation Modeling and Confirmatory Network Analysis
Description: Multi-group (dynamical) structural equation models in combination with confirmatory network models from cross-sectional, time-series and panel data <doi:10.31234/osf.io/8ha93>. Allows for confirmatory testing and fit as well as exploratory model search.
Authors: Sacha Epskamp [aut, cre]
Maintainer: Sacha Epskamp <[email protected]>
License: GPL-2
Version: 0.16
Built: 2026-06-13 23:14:09 UTC
Source: https://github.com/sachaepskamp/psychonetrics

Help Index


Structural Equation Modeling and Confirmatory Network Analysis

Description

Multi-group (dynamical) structural equation models in combination with confirmatory network models from cross-sectional, time-series and panel data <doi:10.31234/osf.io/8ha93>. Allows for confirmatory testing and fit as well as exploratory model search.

Details

The DESCRIPTION file:

Package: psychonetrics
Type: Package
Title: Structural Equation Modeling and Confirmatory Network Analysis
Version: 0.16
Authors@R: person(given = "Sacha",family = "Epskamp", role = c("aut", "cre"), email = "[email protected]")
Maintainer: Sacha Epskamp <[email protected]>
Description: Multi-group (dynamical) structural equation models in combination with confirmatory network models from cross-sectional, time-series and panel data <doi:10.31234/osf.io/8ha93>. Allows for confirmatory testing and fit as well as exploratory model search.
License: GPL-2
Copyright: see file COPYRIGHTS. Bundles the LBFGS++ (LBFGSpp) headers by Yixuan Qiu and others (MIT license) in inst/include.
LinkingTo: Rcpp (>= 0.11.3), RcppArmadillo, RcppEigen, pbv, roptim
Depends: R (>= 4.3.0)
Imports: methods, qgraph, numDeriv, dplyr, Matrix (>= 1.6-5), lavaan, corpcor, glasso, mgcv, optimx, nloptr, pbapply, parallel, magrittr, IsingSampler, tidyr, psych, rlang, MASS
Suggests: psychTools, semPlot, graphicalVAR, metaSEM, mvtnorm, ggplot2, tinytest
ByteCompile: true
URL: https://psychonetrics.org/
BugReports: https://github.com/SachaEpskamp/psychonetrics/issues
StagedInstall: true
NeedsCompilation: yes
RoxygenNote: 7.3.3
Config/pak/sysreqs: cmake libglpk-dev make libicu-dev libjpeg-dev libpng-dev libuv1-dev libxml2-dev
Repository: https://sachaepskamp.r-universe.dev
Date/Publication: 2026-06-13 21:50:03 UTC
RemoteUrl: https://github.com/sachaepskamp/psychonetrics
RemoteRef: HEAD
RemoteSha: 59804e8d8619e069c04011e1ac6b6516beb81b04
Author: Sacha Epskamp [aut, cre]

Index of help topics:

addMIs                  Model updating functions
aggregate_bootstraps    Aggregate Bootstrapped Models
allequal                Constrain all elements of a matrix equal within
                        groups
bifactor                Bi-factor models
BlumeCapel              Blume-Capel model
bootstrap               Bootstrap a psychonetrics model
changedata              Change the data of a psychonetrics object
checkJacobian           Diagnostic functions
CIplot                  Plot Analytic Confidence Intervals
compare                 Model comparison
covML                   Maximum likelihood covariance estimate
dlvm1                   Lag-1 dynamic latent variable model family of
                        psychonetrics models for panel data
duplicationMatrix       Model matrices used in derivatives
emergencystart          Reset starting values to simple defaults
equalityScoreTest       Score (Lagrange Multiplier) test for
                        cross-group equality constraints
esa                     Ergodic Subspace Analysis
factorscores            Compute factor scores
find_penalized_lambda   Automated Lambda Selection for Penalized
                        Estimation
fit                     Print fit indices
fixpar                  Parameters modification
fixstart                Attempt to Fix Starting Values
fromlavaan              Convert a lavaan model to a psychonetrics lvm
generate                Generate data from a fitted psychonetrics
                        object
getmatrix               Extract an estimated matrix
getVCOV                 Obtain the asymptotic covariance matrix
groupequal              Group equality constraints
Ising                   Ising model
Jonas                   Jonas dataset
latentgrowth            Latent growth curve model
logbook                 Retrieve the psychonetrics logbook
loop_psychonetrics      Parallel loop for psychonetrics
lvm                     Continuous latent variable family of
                        psychonetrics models
meta_lvm                Meta-analytic latent variable model
meta_var1               Meta-analytic VAR(1) model
meta_varcov             Variance-covariance and GGM meta analysis
MIs                     Print modification indices
ml_lvm                  Multi-level latent variable model family
ml_tsdlvm1              Multi-level Lag-1 dynamic latent variable model
                        family of psychonetrics models for time-series
                        data
modelsearch             Stepwise model search
NA2020                  Network Analysis 2020 Self-Report Data
parameters              Print parameter estimates
parequal                Set equality constraints across parameters
partialprune            Partial pruning of multi-group models
penalize                Penalized Maximum Likelihood Functions
prune                   Stepdown model search by pruning
                        non-significant parameters
psychonetrics_bootstrap-class
                        Class '"psychonetrics_bootstrap"'
psychonetrics_log-class
                        Class '"psychonetrics_log"'
psychonetrics-class     Class '"psychonetrics"'
psychonetrics-package   Structural Equation Modeling and Confirmatory
                        Network Analysis
ri_clpm                 Random intercept cross-lagged panel models
runmodel                Run a psychonetrics model
setestimator            Convenience functions
setverbose              Should messages of computation progress be
                        printed?
simplestructure         Generate factor loadings matrix with simple
                        structure
StarWars                Star Wars dataset
stepup                  Stepup model search along modification indices
tolavaan                Convert a psychonetrics lvm to a lavaan model
transmod                Transform between model types
tsdlvm1                 Lag-1 dynamic latent variable model family of
                        psychonetrics models for time-series data
unionmodel              Unify models across groups
update_baseline         Set a custom baseline or saturated reference
                        model
var1                    Lag-1 vector autoregression family of
                        psychonetrics models
varcov                  Variance-covariance family of psychonetrics
                        models
write_psychonetrics     Write comprehensive model output to a text file

This package can be used to perform Structural Equation Modeling and confirmatory network modeling. Current implemented families of models are (1) the variance–covariance matrix (varcov), (2) the latent variable model (lvm), (3) the lag-1 vector autoregression model (var1), (4) the dynamical lag-1 latent variable model for panel data (dlvm1) and for time-series data (tsdlvm1), (5) the Ising model (Ising) and its generalization the Blume-Capel model (BlumeCapel), (6) the multi-level latent variable model for two-level data (ml_lvm) and the multi-level dynamical model for multi-subject time-series data (ml_tsdlvm1), (7) the meta-analytic variance–covariance model (meta_varcov, with wrappers meta_lvm and meta_var1), and (8) the random-intercept cross-lagged panel model (ri_clpm).

Author(s)

Sacha Epskamp [aut, cre]

Maintainer: Sacha Epskamp <[email protected]>

References

More information: psychonetrics.org


Aggregate Bootstrapped Models

Description

Aggregates bootstrap results into a psychonetrics_bootstrap object

Usage

aggregate_bootstraps(sample, bootstraps, remove_problematic = TRUE)

Arguments

sample

The original psychonetrics object (not bootstrapped)

bootstraps

A list of bootstrapped psychonetrics objects (i.e., using bootstrap = TRUE)

remove_problematic

Remove bootstraps that did not converge (sum of absolute gradient > 1)

Details

After running this function, the helper functions parameters, fit, and CIplot can be used to investigate bootstrap results.

Value

An object of the class psychonetrics_bootstrap

Author(s)

Sacha Epskamp


Constrain all elements of a matrix equal within groups

Description

The allequal function constrains all free elements of a model matrix to be equal to one another within each group (a single shared parameter per group). In contrast to groupequal, which constrains corresponding elements equal across groups, allequal shares one parameter across the elements of the matrix and does so separately for each group, so the constraint is not imposed across groups. This is convenient for, for example, constraining all thresholds (tau) or all Blume-Capel quadratic potentials (delta) to a common value, or fitting an equal-edge-weight network (omega).

Usage

allequal(x, matrix, row, col, group, verbose, log = TRUE,
         runmodel = FALSE, identify = TRUE, ...)

Arguments

x

A psychonetrics model.

matrix

String indicating the matrix whose elements should be constrained equal.

row

Optional integer or string vector indicating which rows of the matrix to include. Defaults to all rows.

col

Optional integer or string vector indicating which columns of the matrix to include. Defaults to all columns.

group

Optional vector of group ids to which the constraint is applied. Defaults to all groups (each constrained separately).

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

runmodel

Logical, should the model be updated?

identify

Logical, should the model be identified?

...

Arguments sent to runmodel

Details

Only free parameters are affected; elements that are fixed (e.g. fixed to zero) are left unchanged. For symmetric matrices all free elements, including a free diagonal, are constrained equal; if this is not desired (for example to keep the diagonal separate from the off-diagonal elements), use the row and col arguments to restrict the constraint to the relevant elements. Within each group the selected free elements are given the same parameter number and a common starting value (the mean of their current values).

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

See Also

groupequal, parequal, fixpar

Examples

## Not run: 
library("dplyr")

# Simulate a small Blume-Capel data set (requires the development version of
# IsingSampler that supports the 'delta' argument):
library("IsingSampler")
nNode  <- 5
graph  <- 0.4 * (matrix(1, nNode, nNode) - diag(nNode)) *
            (matrix(c(0,1,0,0,1, 1,0,1,0,0, 0,1,0,1,0, 0,0,1,0,1, 1,0,0,1,0), 5, 5))
data <- IsingSampler(1000, graph = graph, thresholds = rep(0, nNode),
                     beta = 1, delta = 1, responses = c(-1, 0, 1))

# Blume-Capel model with all quadratic (delta) potentials constrained equal,
# and all thresholds (tau) constrained equal, within the group:
mod <- BlumeCapel(data, responses = c(-1, 0, 1)) %>%
  allequal("delta") %>%
  allequal("tau") %>%
  runmodel

## End(Not run)

Bi-factor models

Description

Wrapper to lvm to specify a bi-factor model.

Usage

bifactor(data, lambda, latents, bifactor = "g", ...)

Arguments

data

The data as used by lvm

lambda

The factor loadings matrix *without* the bifactor, as used by by lvm

latents

A vector of names of the latent variables, as used by lvm

bifactor

Name of the bifactor

...

Arguments sent to lvm

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Blume-Capel model

Description

The Blume-Capel model is the full Spin distribution model. In addition to the linear node potentials (tau) and pairwise interactions (omega) of the Ising model, it estimates a quadratic node potential delta (the Blume-Capel single-ion / crystal-field term). The Ising model is the special case obtained by fixing all delta parameters to zero, so the two models are nested. By convention the Blume-Capel model is defined for the ternary c(-1, 0, 1) response coding (a warning is raised for any other response set), but any number of ordered numeric response options is allowed (the same set for every variable, and not necessarily integers).

Usage

BlumeCapel(data, omega = "full", tau, delta, beta, beta_model =
                 c("beta", "log_beta"), vars, groups, covs, means,
                 nobs, covtype = c("choose", "ML", "UB"), responses,
                 missing = "listwise", equal = "none",
                 baseline_saturated = TRUE, estimator = "default",
                 optimizer, storedata = FALSE, WLS.W, sampleStats,
                 identify = TRUE, verbose = FALSE, maxNodes = 20,
                 maxStates = 2^maxNodes, min_sum = -Inf,
                 bootstrap = FALSE, boot_sub,
                 boot_resample, penalty_lambda = NA,
                penalty_alpha = 1, penalize_matrices)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

omega

The network structure. Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions nNode x nNode with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

tau

Optional vector encoding the threshold/intercept (linear node potential) structure. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

delta

Optional vector encoding the quadratic node potential (Blume-Capel) structure. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free parameters, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector. When missing, every delta parameter is freely estimated (fixing all of them to zero would instead yield the Ising model).

beta

Optional scalar encoding the inverse temperature. 1 indicate free beta parameters, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such scalars.

beta_model

How should beta be modeled? Set beta_model = "log_beta" to model the log of beta rather than beta directly.

vars

An optional character vector encoding the variables used in the analysis. Must equal names of the dataset in data.

groups

An optional string indicating the name of the group variable in the data.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure covtype argument is set correctly to the type of covariances used.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

responses

A vector of the response options used, encoded identically across all variables. Defaults to (and is conventionally) c(-1, 0, 1); a warning is raised for any other set. Automatically detected from the data when not supplied; required when covs is used. Any number of distinct response options is allowed, and the values need not be integers.

missing

How should missingness be handled when data is used. Only "listwise" (listwise deletion) is currently supported for the Blume-Capel model; other options (e.g. "pairwise") are rejected at construction because they produce undefined sufficient statistics.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Only "ML" (maximum likelihood) estimation is currently supported for the Blume-Capel model.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

WLS.W

Optional WLS weights matrix. CURRENTLY NOT USED.

sampleStats

An optional sample statistics object. Mostly used internally.

identify

Logical, should the model be identified?

verbose

Logical, should messages be printed?

maxNodes

The maximum number of nodes allowed in the analysis. Used to set the default of maxStates (2^maxNodes); for binary data this reproduces the historical node limit. It is not recommended to set this higher.

maxStates

The maximum number of response patterns the exact ML estimator may enumerate. Exact ML estimation sums over every possible response pattern when computing the partition function, expected values and (expected) Hessian, so the cost grows as length(responses)^nNode. The function stops with an error when length(responses)^nNode exceeds maxStates. The default 2^maxNodes reproduces the historical binary node limit while accounting for more than two response options. Raise this only if the computation is feasible (note that the number of states—and hence the run time—grows very quickly with both the number of nodes and the number of response options).

min_sum

The minimum sum score that is artificially possible in the dataset. Defaults to -Inf. Set this only if you know a lower sum score is not possible in the data, for example due to selection bias.

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). NA (default) triggers automatic selection via EBIC-based grid search when a penalized estimator is used; set to a specific numeric value to use a fixed penalty strength (0 = no penalty). See find_penalized_lambda and penalize.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type (the network omega).

Details

The Blume-Capel model is built on the Spin distribution:

Pr(Y=y)=exp(βH(y;τ,δ,Ω))Z(τ,δ,Ω)\Pr(\boldsymbol{Y} = \boldsymbol{y}) = \frac{\exp\left( -\beta H\left(\boldsymbol{y}; \boldsymbol{\tau}, \boldsymbol{\delta}, \boldsymbol{\Omega}\right)\right)}{Z(\boldsymbol{\tau}, \boldsymbol{\delta}, \boldsymbol{\Omega})}

With Hamiltonian:

H(y;τ,δ,Ω)=i=1mτiyi+i=1mδiyi2i=2mj=1i1ωijyiyj.H\left(\boldsymbol{y}; \boldsymbol{\tau}, \boldsymbol{\delta}, \boldsymbol{\Omega}\right) = -\sum_{i=1}^{m} \tau_i y_{i} + \sum_{i=1}^{m} \delta_i y_{i}^2 - \sum_{i=2}^{m} \sum_{j=1}^{i-1} \omega_{ij} y_i y_j.

and Z representing the partition function or normalizing constant. Equivalently,

Pr(Y=y)exp(iτiyiiδiyi2+i<jωijyiyj).\Pr(\boldsymbol{Y} = \boldsymbol{y}) \propto \exp\left( \sum_i \tau_i y_i - \sum_i \delta_i y_i^2 + \sum_{i<j} \omega_{ij} y_i y_j \right).

For the ternary states c(-1, 0, 1) this is the usual Blume-Capel parameterization: tau controls the tendency toward the positive versus the negative state, delta controls the tendency toward the zero/middle state versus the active/extreme states (positive delta favours the middle category), and omega controls pairwise alignment. For more general ordered numeric states the same parameterization defines an ordinal spin model.

The Ising model is nested within the Blume-Capel model by fixing all delta parameters to zero. Exact ML estimation enumerates every response pattern, so the cost grows as length(responses)^nNode (see maxStates); the model is therefore limited to relatively small networks.

Value

An object of the class psychonetrics

Author(s)

Sacha Epskamp <[email protected]>

References

Epskamp, S., Maris, G., Waldorp, L. J., & Borsboom, D. (2018). Network Psychometrics. In: Irwing, P., Hughes, D., & Booth, T. (Eds.), The Wiley Handbook of Psychometric Testing, 2 Volume Set: A Multidisciplinary Reference on Survey, Scale and Test Development. New York: Wiley.

See Also

Ising

Examples

library("dplyr")

# Simulate a small Blume-Capel data set (requires the development version of
# IsingSampler that supports the 'delta' argument):
## Not run: 
library("IsingSampler")
nNode  <- 5
graph  <- 0.4 * (matrix(1, nNode, nNode) - diag(nNode)) *
            (matrix(c(0,1,0,0,1, 1,0,1,0,0, 0,1,0,1,0, 0,0,1,0,1, 1,0,0,1,0), 5, 5))
data <- IsingSampler(1000, graph = graph, thresholds = rep(0, nNode),
                     beta = 1, delta = 1, responses = c(-1, 0, 1))

# Fit the Blume-Capel model:
mod <- BlumeCapel(data, responses = c(-1, 0, 1)) %>% runmodel

# Estimated network:
getmatrix(mod, "omega")

# Estimated quadratic node potentials:
getmatrix(mod, "delta")

## End(Not run)

Bootstrap a psychonetrics model

Description

This function will bootstrap the data (once) and return a new unevaluated psychonetrics object. It requres storedata = TRUE to be used when forming a model.

Usage

bootstrap(x, replacement = TRUE, proportion = 1, verbose = TRUE, storedata = FALSE, 
          baseline_saturated = TRUE)

Arguments

x

A psychonetrics model.

replacement

Logical, should new samples be drawn with replacement?

proportion

Proportion of sample to be drawn. Set to lower than $1$ for subsampling.

verbose

Logical, should messages be printed?

storedata

Logical, should the bootstrapped data also be stored?

baseline_saturated

Logical, should the baseline and saturated models be included?

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Change the data of a psychonetrics object

Description

This function can be used to change the data in a psychonetrics object.

Usage

changedata(x, data, covs, nobs, means, groups, missing = "listwise")

Arguments

x

A psychonetrics model.

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. IMPORTANT NOTE: psychonetrics expects the maximum likelihood (ML) covariance matrix, which is NOT obtained from cov directly. Manually rescale the result of cov with (nobs - 1)/nobs to obtain the ML covariance matrix.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

groups

An optional string indicating the name of the group variable in data.

missing

How should missingness be handled in computing the sample covariances and number of observations when data is used. Can be "listwise" for listwise deletion, or "pairwise" for pairwise deletion.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Plot Analytic Confidence Intervals

Description

Function to plot analytic confidence intervals (CI) of matrix elements estimated in psychonetrics.

Usage

CIplot(x, matrices, alpha_ci = 0.05, alpha_color = c(0.05,
                   0.01, 0.001, 1e-04), labels, labels2, labelstart,
                   print = TRUE, major_break = 0.2, minor_break = 0.1,
                   split0, prop0, prop0_cex = 1, prop0_alpha = 0.95,
                   prop0_minAlpha = 0.25)

Arguments

x

A psychonetrics model.

matrices

Vector of strings indicating the matrices to plot CIs for

alpha_ci

The alpha level used for the CIs

alpha_color

A vector of alphas used for coloring the CIs

labels

The labels for the variables associated with the rows of a matrix.

labels2

The labels for the variables associated with the columns of a matrix. Defaults to the value of labels for square matrices.

labelstart

The value to determine if labels are printed to the right or to the left of the CI

print

Logical, should the plots also be printed? Only works when one matrix is used in 'matrices'

major_break

Numeric indicating the step size between major breaks

minor_break

Numeric indicating the step size between minor breaks

split0

Logical only used for results of aggregate_bootstraps. When set to TRUE, the displayed intervals are based on occasions when the parameter was not estimated to be zero, and an extra box is added indicating the number of times a parameter is estimated to be zero. Defaults to TRUE when model selection is used and FALSE otherwise.

prop0

Logical only used for results of aggregate_bootstraps, should boxes indicating the proportion of times parameters were estimated to be zero be added to the plot? Defaults to the value of split0.

prop0_cex

Only used for results of aggregate_bootstraps. Size of the boxes indicating number of times a parameter was set to zero.

prop0_alpha

Only used for results of aggregate_bootstraps. Transparency of the boxes indicating number of times a parameter was set to zero.

prop0_minAlpha

Only used for results of aggregate_bootstraps. Minimal transparency of the *lines* of plotted intervals as the proportion of times an edge was not included goes to 0.

Value

A single ggplot2 object, or a list of ggplot2 objects for each matrix requested.

Author(s)

Sacha Epskamp

Examples

### Example from ?ggm ###
# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit an empty GGM:
mod0 <- ggm(ConsData, vars = vars)

# Run the model:
mod0 <- mod0 %>% runmodel

# Labels:
labels <- c(
  "indifferent to the feelings of others",
  "inquire about others' well-being",
  "comfort others",
  "love children",
  "make people feel at ease")

# Plot the CIs:
CIplot(mod0,  "omega", labels = labels, labelstart = 0.2)

### Example from ?gvar ###
library("dplyr")
library("graphicalVAR")

beta <- matrix(c(
  0,0.5,
  0.5,0
),2,2,byrow=TRUE)
kappa <- diag(2)
simData <- graphicalVARsim(50, beta, kappa)

# Form model:
model <- gvar(simData)

# Evaluate model:
model <- model %>% runmodel

# Plot the CIs:
CIplot(model,  "beta")

Model comparison

Description

This function will print a table comparing multiple models on chi-square, AIC and BIC. When all compared models are fitted with a robust estimator, a Satorra-Bentler-family scaled chi-square difference test is added.

Usage

compare(..., scaled.test.method = c("satorra.bentler.2001",
        "satorra.bentler.2010", "satorra.2000"))

## S3 method for class 'psychonetrics_compare'
print(x, ...)

Arguments

...

Any number of psychonetrics models. Can be named to change the rownames of the output.

scaled.test.method

The scaled chi-square difference test to use when all compared models carry a robust scaling factor (see Details). One of "satorra.bentler.2001" (the default; a mean-scaled test that always works), "satorra.bentler.2010" (a strictly positive mean-scaled variant), or "satorra.2000" (an exact, scaled-and-shifted test, appropriate for the scaled-shifted estimators such as MLMV and WLSMV).

x

Output of the compare function.

Details

When every compared model is fitted with a robust estimator (MLM, MLMV, MLMVS or MLR, or one of the least-squares estimators DWLS, WLS and ULS), two additional columns are added: Chisq_diff_scaled and p_value_scaled. These contain the Satorra-Bentler-family scaled chi-square difference test for each adjacent (nested) pair of models, sorted by degrees of freedom. The ordinary (unscaled) Chisq_diff, DF_diff and p_value columns are always present and unchanged. When the models are not fitted with a robust estimator (e.g. ordinary ML or FIML), the scaled columns are omitted entirely.

For an adjacent nested pair with the more constrained model M0M_0 (degrees of freedom r0r_0, unscaled chi-square T0T_0, scaling factor c0c_0) nested in the less constrained model M1M_1 (r1r_1, T1T_1, c1c_1), and m=r0r1m = r_0 - r_1:

  • "satorra.bentler.2001" computes cd=(r0c0r1c1)/mc_d = (r_0 c_0 - r_1 c_1)/m and Td=(T0T1)/cdT_d = (T_0 - T_1)/c_d (Satorra & Bentler, 2001).

  • "satorra.bentler.2010" replaces c1c_1 by the scaling factor of M1M_1 evaluated at M0M_0's estimates, guaranteeing a positive statistic (Satorra & Bentler, 2010).

  • "satorra.2000" computes an exact, scaled-and-shifted statistic from the asymptotic covariance of the sample statistics (Satorra, 2000; Asparouhov & Muthen, 2010); this is the appropriate difference test for the scaled-shifted estimators MLMV and WLSMV.

The statistic is set to NA (with a warning) when the implied scaling factor is non-positive or a required building block cannot be computed.

Value

A data frame with chi-square values, degrees of freedoms, RMSEAs, AICs, and BICs, and—when all models are fitted with a robust estimator—scaled chi-square difference columns.

Author(s)

Sacha Epskamp

References

Satorra, A. (2000). Scaled and adjusted restricted tests in multi-sample analysis of moment structures. In R. D. H. Heijmans, D. S. G. Pollock, & A. Satorra (Eds.), Innovations in multivariate statistical analysis (pp. 233-247). Kluwer Academic Publishers.

Satorra, A., & Bentler, P. M. (2001). A scaled difference chi-square test statistic for moment structure analysis. Psychometrika, 66(4), 507-514.

Satorra, A., & Bentler, P. M. (2010). Ensuring positiveness of the scaled difference chi-square test statistic. Psychometrika, 75(2), 243-248.

Asparouhov, T., & Muthen, B. (2010). Simple second order chi-square correction. Mplus technical appendix.

Examples

## Not run: 
library("dplyr")

# Load data:
data(StarWars)

# Originally a partial measurement invariance model in
# https://psychonetrics.org/files/Epskampetal2017.pdf:
mod1 <- lvm(StarWars, lambda = matrix(1, 10), vars = paste0("Q", 1:10),
            identification = "variance", latents = "Force",
            estimator = "MLM") %>% runmodel

# A model fixing two prequel loadings to zero:
mod2 <- mod1 %>% fixpar("lambda", row = "Q4", col = "Force") %>%
  fixpar("lambda", row = "Q5", col = "Force") %>% runmodel

# Compare with the scaled (Satorra-Bentler 2001) difference test:
compare(full = mod1, restricted = mod2)

## End(Not run)

Maximum likelihood covariance estimate

Description

These functions complement the base R cov function by simplifying obtaining maximum likelihood (ML) covariance estimates (denominator n) instead of unbiased (UB) covariance estimates (denominator n-1). The function covML can be used to obtain ML estimates, the function covUBtoML transforms from UB to ML estimates, and the function covMLtoUB transforms from ML to UB estimates.

Usage

covML(x, ...)
covUBtoML(x, n, ...)
covMLtoUB(x, n, ...)

Arguments

x

A dataset

n

The sample size

...

Arguments sent to the cov function.

Value

A covariance matrix: the maximum likelihood (ML) or unbiased (UB) variance–covariance matrix of x, depending on the function used.

Author(s)

Sacha Epskamp <[email protected]>

Examples

data("StarWars")
Y <- StarWars[,1:10]

# Unbiased estimate:
UB <- cov(Y)

# ML Estimate:
ML <- covML(Y)

# Check:
all(abs(UB - covMLtoUB(ML, nrow(Y))) < sqrt(.Machine$double.eps))
all(abs(ML - covUBtoML(UB, nrow(Y))) < sqrt(.Machine$double.eps))

Diagnostic functions

Description

The 'checkJacobian' function can be used to check if the analytic gradient / Jacobian is aligned with the numerically approximated gradient / Jacobian, and the 'checkFisher' function can be used to check if the analytic Hessian is aligned with the numerically approximated Hessian.

Usage

checkJacobian(x, f = "default", jac = "default", transpose = FALSE, 
          plot = TRUE, perturbStart = FALSE, method = "Richardson")

checkFisher(x, f = "default", fis = "default", transpose = FALSE, 
          plot = TRUE,  perturbStart = FALSE)

Arguments

x

A 'psychonetrics' object

f

A custom fit function or the psychonetrics default fit function (default).

jac

A custom Jacobian function or the psychonetrics default Jacobian function (default).

fis

A custom Fisher information function or the psychonetrics default Fisher information function (default).

transpose

Should the numeric Jacobian be transposed?

plot

Should a diagnostic plot be produced?

perturbStart

Should start values be perturbed (only used in development)

method

Numeric derivative method (default: Richardson)

Value

Invisibly returns a list with two elements, analytic and numeric, containing the analytic and the numerically approximated gradient/Jacobian (checkJacobian) or Hessian/Fisher information (checkFisher) values being compared. A scatter plot of the two is drawn when plot = TRUE.

Author(s)

Sacha Epskamp


Lag-1 dynamic latent variable model family of psychonetrics models for panel data

Description

This is the family of models that models a dynamic factor model on panel data. All functions accept both wide-format data (with a design matrix for vars) and long-format data (with a character vector for vars plus idvar and optionally beepvar). The format is auto-detected from the type of vars. There are four covariance structures that can be modeled in different ways: within_latent, between_latent for the within-person and between-person latent (contemporaneous) models respectively, and within_residual, between_residual for the within-person and between-person residual models respectively. The panelgvar wrapper function sets the lambda to an identity matrix, all residual variances to zero, and models within-person and between-person latent (contemporaneous) models as GGMs. The panelvar wrapper does the same but models contemporaneous relations as a variance-covariance matrix. Finally, the panellvgvar wrapper automatically models all latent networks as GGMs. The old name panel_lvgvar is deprecated in favor of panellvgvar. For long-format data, pass the idvar (and optionally beepvar) arguments to panelgvar or panelvar via ...; see the examples below.

Usage

dlvm1(data, vars, datatype = c("auto", "wide", "long"),
                   idvar, beepvar,
                   standardize = c("none", "z", "quantile", "z_per_wave"),
                   lambda, within_latent = c("cov", "chol",
                   "prec", "ggm"), within_residual = c("cov", "chol",
                   "prec", "ggm"), between_latent = c("cov", "chol",
                   "prec", "ggm"), between_residual = c("cov", "chol",
                   "prec", "ggm"), beta = "full", omega_zeta_within =
                   "full", delta_zeta_within = "diag", kappa_zeta_within
                   = "full", sigma_zeta_within = "full",
                   lowertri_zeta_within = "full", omega_epsilon_within =
                   "zero", delta_epsilon_within = "diag",
                   kappa_epsilon_within = "diag", sigma_epsilon_within =
                   "diag", lowertri_epsilon_within = "diag",
                   omega_zeta_between = "full", delta_zeta_between =
                   "diag", kappa_zeta_between = "full",
                   sigma_zeta_between = "full", lowertri_zeta_between =
                   "full", omega_epsilon_between = "zero",
                   delta_epsilon_between = "diag", kappa_epsilon_between
                   = "diag", sigma_epsilon_between = "diag",
                   lowertri_epsilon_between = "diag", nu, mu_eta,
                   identify = TRUE, identification = c("loadings",
                   "variance"), latents, groups, groupvar, covs,
                   cors, means, nobs, corinput, start
                   = "version2", covtype = c("choose", "ML", "UB"),
                   missing = "auto", equal = "none",
                   baseline_saturated = TRUE, estimator = "ML",
                   optimizer, storedata = FALSE, verbose = FALSE,
                   sampleStats, baseline =
                   c("stationary_random_intercept", "stationary",
                   "independence", "none"), bootstrap = FALSE, boot_sub,
                   boot_resample, within, between,
                   penalty_lambda = NA, penalty_alpha = 1,
                   penalize_matrices)

panelgvar(data, vars, within_latent = c("ggm","chol","cov","prec"), 
          between_latent = c("ggm","chol","cov","prec"), ...)

panelvar(data, vars, within_latent = c("cov","chol","prec","ggm"), 
          between_latent = c("cov","chol","prec","ggm"), ...)

panellvgvar(...)

panel_lvgvar(...)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

vars

Required argument. For wide-format data, this must be a *matrix* with each row indicating a variable and each column indicating a measurement. The matrix must be filled with names of the variables in the dataset corresponding to variable i at wave j. NAs can be used to indicate missing waves. The rownames of this matrix will be used as variable names. For long-format data, this should be a character vector of variable names in the dataset.

datatype

Data format: "auto" (default) auto-detects based on whether vars is a matrix (wide) or character vector (long). "wide" forces wide-format interpretation. "long" forces long-format interpretation with automatic reshape to wide.

idvar

Optional string indicating the subject/cluster ID variable in data. Required when datatype = "long" or when vars is a character vector.

beepvar

Optional string indicating the time point / measurement occasion variable. If missing when datatype = "long", a sequential measurement variable is created per subject.

standardize

Standardization method: "none" (default), "z" for global z-scores per variable across all waves (uses the overall mean and standard deviation for each variable computed across all waves of data), "quantile" for quantile normalization across all waves, "z_per_wave" for independent z-scores per wave column (note: this imposes stationarity as means become 0 and variances become 1 at each wave).

lambda

Required argument. A model matrix encoding the factor loading structure. Each row indicates an indicator and each column a latent. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

within_latent

The type of within-person latent contemporaneous model to be used.

within_residual

The type of within-person residual model to be used.

between_latent

The type of between-person latent model to be used.

between_residual

The type of between-person residual model to be used.

beta

A model matrix encoding the temporal relationships (transpose of temporal network). A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix. Can also be "full" for a full temporal network or "zero" for an empty temporal network.

omega_zeta_within

Only used when within_latent = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta_within

Only used when within_latent = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta_within

Only used when within_latent = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_zeta_within

Only used when within_latent = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta_within

Only used when within_latent = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_epsilon_within

Only used when within_residual = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_epsilon_within

Only used when within_residual = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_epsilon_within

Only used when within_residual = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_epsilon_within

Only used when within_residual = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_epsilon_within

Only used when within_residual = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_zeta_between

Only used when between_latent = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta_between

Only used when between_latent = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta_between

Only used when between_latent = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_zeta_between

Only used when between_latent = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta_between

Only used when between_latent = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_epsilon_between

Only used when between_residual = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_epsilon_between

Only used when between_residual = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_epsilon_between

Only used when between_residual = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_epsilon_between

Only used when between_residual = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_epsilon_between

Only used when between_residual = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

nu

Optional vector encoding the intercepts of the observed variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

mu_eta

Optional vector encoding the means of the latent variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

identify

Logical, should the model be automatically identified?

identification

Type of identification used. "loadings" to fix the first factor loadings to 1, and "variance" to fix the diagonal of the latent variable model matrix (sigma_zeta, lowertri_zeta, delta_zeta or kappa_zeta) to 1.

latents

An optional character vector with names of the latent variables.

groups

Deprecated. Use groupvar instead. An optional string indicating the name of the group variable in data.

groupvar

An optional string indicating the name of the group variable in data. Replaces the deprecated groups argument; if both are supplied, groupvar takes precedence with a warning.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure the covtype argument is set correctly to the type of covariances used.

cors

A sample correlation matrix, or a list/array of such matrices for multiple groups. When supplied, the matrix is treated as a covariance matrix with a warning (appropriate for standardized data). Requires nobs. Note: corinput = TRUE is not supported in dlvm1.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

corinput

Logical. Not supported in dlvm1() and will produce an error if set to TRUE.

start

Start value specification. Can be either a string or a psychonetrics model. If it is a string, "version2" indicates the latest version of start value computation, "version1" indicates start values as they were computed up to version 0.11, and "simple" indicate simple starting values. If this is a psychonetrics model the starting values will be based on the output. This can be useful, for example, if you first estimate a model with matrices set to a Cholesky decomposition, then use those values as start values for estimating Gaussian graphical models.

missing

How should missingness be handled in computing the sample covariances and number of observations when data is used. Can be "auto" (default) for automatic detection, "listwise" for listwise deletion, or "pairwise" for pairwise deletion. When "auto", the function checks for missing data and switches ML to FIML, PML to PFIML, or defaults to listwise for LS estimators.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Currently implemented are "ML" for maximum likelihood estimation, "FIML" for full-information maximum likelihood estimation, "PML" for penalized maximum likelihood estimation, "PFIML" for penalized full-information maximum likelihood estimation, "ULS" for unweighted least squares estimation, "WLS" for weighted least squares estimation, and "DWLS" for diagonally weighted least squares estimation. When missing = "auto" (default), "ML" is automatically switched to "FIML" and "PML" to "PFIML" if missing data is detected.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

verbose

Logical, should progress be printed to the console?

sampleStats

An optional sample statistics object. Mostly used internally.

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

baseline

What baseline model should be used? "stationary_random_intercept" includes both within- and between person variances constrained equal across time (default), "stationary" only includes within-person variances constrained equal across time, "independence" (default up to version 0.11) includes a variance for every variable at every time point (not constrained equal across time), and "none" includes no baseline model.

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

within

Optional alias for within_latent. If both within and within_latent are explicitly specified, within_latent takes precedence and a warning is issued.

between

Optional alias for between_latent. If both between and between_latent are explicitly specified, between_latent takes precedence and a warning is issued.

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). NA (default) triggers automatic selection via EBIC-based grid search when a penalized estimator is used; set to a specific numeric value to use a fixed penalty strength (0 = no penalty). See find_penalized_lambda and penalize.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type.

...

Arguments sent to dlvm1.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

Examples

library("dplyr")

# Smoke data cov matrix, based on LISS data panel https://www.dataarchive.lissdata.nl
smoke <- structure(c(47.2361758611759, 43.5366809116809, 41.0057465682466, 
                     43.5366809116809, 57.9789886039886, 47.6992521367521, 
                     41.0057465682466, 
                     47.6992521367521, 53.0669434731935), .Dim = c(3L, 3L), 
                   .Dimnames = list(
                       c("smoke2008", "smoke2009", "smoke2010"), c("smoke2008", 
                   "smoke2009", "smoke2010")))

# Design matrix:
design <- matrix(rownames(smoke),1,3)

# Form model:
mod <- panelvar(vars = design, 
                covs = smoke, nobs = 352
)


# Run model:
mod <- mod %>% runmodel

# Evaluate fit:
mod %>% fit


# panelgvar and panelvar also accept long-format data.
# For long-format data, pass vars as a character vector
# and provide idvar (and optionally beepvar) via ...:

# Simulate some long-format panel data:
longdata <- data.frame(
  id = rep(1:50, each = 3),
  time = rep(1:3, 50),
  x = rnorm(150),
  y = rnorm(150)
)

# Use panelgvar with long-format data:
mod_long <- panelgvar(data = longdata,
                      vars = c("x", "y"),
                      idvar = "id",
                      beepvar = "time")

Model matrices used in derivatives

Description

These matrices are used in the analytic gradients

Usage

duplicationMatrix(n, diag = TRUE)

eliminationMatrix(n, diag = TRUE)

diagonalizationMatrix(n)

Arguments

n

Number of rows and columns in the original matrix

diag

Logical indicating if the diagonal should be included (set to FALSE for derivative of vech(x))

Value

A sparse matrix

Author(s)

Sacha Epskamp

Examples

# Duplication matrix for 10 variables:
duplicationMatrix(10)

# Elimination matrix for 10 variables:
eliminationMatrix(10)

# Diagonalization matrix for 10 variables:
diagonalizationMatrix(10)

Reset starting values to simple defaults

Description

This function overwrites the starting values to simple defaults. This can help in cases where optimization fails.

Usage

emergencystart(x)

Arguments

x

A psychonetrics model.

Value

A psychonetrics model.

Author(s)

Sacha Epskamp


Score (Lagrange Multiplier) test for cross-group equality constraints

Description

Computes the score test (also known as the Lagrange Multiplier test) for releasing cross-group equality constraints in a multi-group psychonetrics model. Both the per-group univariate score statistics and the joint multivariate score statistic (one statistic per equality-constrained parameter, with df = G - 1) are returned.

The algorithm used by method = "jacobian" (the default) is a direct port of the score-test logic in lavaan::lavTestScore (Rosseel, 2012) and reproduces lavaan's output to numerical precision. The derivation closely follows the implementation in R/lav_test_score.R of the lavaan source code (https://github.com/yrosseel/lavaan), reused here with thanks to Yves Rosseel under the GPL (\geq 2) license shared by both packages. The underlying gradient and Fisher-information machinery is provided by psychonetrics, so no refitting and no run-time dependence on lavaan is required.

With the default method = "jacobian" the algorithm reproduces lavaan::lavTestScore exactly: the model is augmented with G-1 extra parameters per equality-constrained tuple (one per non-reference group), the gradient and expected information are computed at the constrained MLE, and for each constraint the test statistic

T=NsJ~1sT = N \cdot s' \cdot \tilde{J}^{-1} \cdot s

is formed, where ss is the gradient of the log-likelihood and J~1\tilde{J}^{-1} is the upper-left block of the generalised inverse of the bordered information matrix [J RT; R 0][J\ R'^T;\ R\ 0], with RR the rows of the constraint Jacobian for the constraints that are NOT being tested. This is the same construction used by lavaan::lavTestScore.

method = "schur" uses a faster Schur-complement construction (the same used by psychonetrics for ordinary modification indices). It is much faster for complex models because it inverts only the (smaller) block of the information matrix corresponding to the currently free parameters, but it is not exactly equivalent to lavaan in unbalanced multi-group samples (it agrees in balanced samples). Both methods follow the same asymptotic chi-square reference distribution.

Usage

equalityScoreTest(x, matrices, top = 10, verbose = TRUE,
                  method = c("jacobian","schur"))

Arguments

x

A fitted (run) multi-group psychonetrics model.

matrices

Optional vector of matrix names to restrict the test to. By default all matrices are considered.

top

How many rows to print in each table.

verbose

Logical, should the formatted tables be printed?

method

Construction of the score test. "jacobian" (default) reproduces lavaan::lavTestScore exactly. "schur" uses a Schur-complement construction that is faster for complex models but only matches lavaan for balanced multi-group samples.

Details

For two groups (G=2G = 2) the joint test reduces to the univariate test (both have df = 1). The two tests differ for G3G \ge 3, where the joint test correctly accounts for the covariance between the released parameters via the (Schur-complemented) Fisher information, instead of summing or otherwise aggregating univariate statistics.

Value

Invisibly returns a list with two data frames:

uni

Univariate score tests, one row per released parameter (i.e. one row per group beyond the reference group), sorted from largest to smallest X2X^2.

total

Joint multivariate score tests, one row per equality-constrained parameter (i.e. one row per (matrix, row, column) triple), sorted from largest to smallest X2X^2. The joint test has df = G - 1 when the parameter is constrained equal across all GG groups.

Author(s)

Sacha Epskamp <[email protected]>. The method = "jacobian" implementation is a port of the score-test machinery in lavaan::lavTestScore by Yves Rosseel.

References

Rosseel, Y. (2012). lavaan: An R Package for Structural Equation Modeling. Journal of Statistical Software, 48(2), 1-36. doi:10.18637/jss.v048.i02

lavaan source code: https://github.com/yrosseel/lavaan (in particular R/lav_test_score.R).

See Also

MIs, partialprune

Examples

library("dplyr")
library("psychTools")
data(bfi)

ExData <- bfi %>% select(E1:E5, gender) %>% na.omit
vars <- names(ExData)[1:5]

mod <- ggm(ExData, vars = vars, groups = "gender") %>%
  runmodel %>%
  groupequal("omega") %>%
  runmodel

equalityScoreTest(mod)

Ergodic Subspace Analysis

Description

These functions implement Ergodic Subspace Analysis by von Oertzen, Schmiedek and Voelkle (2020). The functions can be used on the output of a dlvm1 model, or manually by supplying a within persons and between persons variance-covariance matrix.

Usage

esa(x, cutoff = 0.1,
    between = c("crosssection", "between"))
esa_manual(sigma_wp, sigma_bp, cutoff = 0.1)
## S3 method for class 'esa'
print(x, printref = TRUE, ...)
## S3 method for class 'esa_manual'
print(x, printref = TRUE, ...)
## S3 method for class 'esa'
plot(x, plot = c("observed", "latent"), ...)
## S3 method for class 'esa_manual'
plot(x,  ...)

Arguments

x

Output of a dlvm1 model

sigma_wp

Manual within-person variance-covariance matrix

sigma_bp

Manual between-person variance-covariance matrix

cutoff

Cutoff used to determine ergodicity

printref

Logical, should the reference be printed?

plot

Should ergodicity of observed or latent variables be plotted?

between

Should the between-persons variance-covariance matrix be based on expected cross-sectional or between-person relations

...

Not used

Value

For each group a esa_manual object with the following elements:

ergodicity

Ergodicity values of each component

Q_esa

Component loadings

V_bp

Between persons subspace

V_ergodic

Ergodic subspace

V_wp

Within person subspace

cutoff

Cutoff value used

Author(s)

Sacha Epskamp <[email protected]>

References

von Oertzen, T., Schmiedek, F., and Voelkle, M. C. (2020). Ergodic Subspace Analysis. Journal of Intelligence, 8(1), 3.


Compute factor scores

Description

Currently, only the lvm framework with no missing data is supported.

Usage

factorscores(data, model, method = c("bartlett", "regression"))

Arguments

data

Dataset to compute factor scores for

model

A psychonetrics model

method

The method to use: "regression" or "bartlett"

Value

A data frame of factor scores (one column per latent variable). For multi-group models a group column is appended.

Author(s)

Sacha Epskamp <[email protected]>


Automated Lambda Selection for Penalized Estimation

Description

Selects the optimal penalty strength (lambda) for penalized maximum likelihood (PML) or penalized full-information maximum likelihood (PFIML) models via EBIC-based grid search. A log-spaced grid of lambda values is searched from lambda_max (the smallest lambda for which all penalized parameters are exactly zero, derived from KKT conditions) down to lambda_max * lambda_min_ratio. Each lambda is optimized using ISTA (Iterative Shrinkage-Thresholding Algorithm) with warm starts from the previous solution, and the model with the best EBIC is selected. After selection, a beta_min threshold is applied to set near-zero penalized parameters exactly to zero.

This function is called automatically by runmodel when the model contains auto-select penalty parameters (i.e., penalty_lambda = NA in the parameter table, which is the default when using estimator = "PML" or estimator = "PFIML"). It can also be called directly for more control over the search.

Usage

find_penalized_lambda(model, criterion = "ebic.5", nLambda = 50,
                      lambda_min_ratio = 1e-4,
                      beta_min = c("numerical", "theoretical"),
                      verbose)

Arguments

model

A psychonetrics model with estimator = "PML" or estimator = "PFIML". The model should contain parameters with penalty_lambda = NA (auto-select), which is the default when specifying estimator = "PML" or "PFIML" in model constructors such as ggm, lvm, etc.

criterion

Character string specifying the information criterion used to select the best lambda. One of:

"bic"

BIC (equivalent to EBIC with gamma = 0)

"ebic.25"

EBIC with gamma = 0.25

"ebic.5"

EBIC with gamma = 0.5 (default; recommended for network models)

"ebic.75"

EBIC with gamma = 0.75

"ebic1"

EBIC with gamma = 1.0

Higher gamma values penalize model complexity more strongly and tend to produce sparser solutions. Gamma = 0.5 is widely recommended for network models (Foygel & Drton, 2010).

nLambda

Integer, the number of lambda values in the search grid. Default is 50. The grid is log-spaced between lambda_max and lambda_max * lambda_min_ratio.

lambda_min_ratio

Numeric, the ratio of the smallest to the largest lambda in the grid. Default is 1e-4, so that lambda_min = lambda_max * 1e-4.

beta_min

Threshold for zeroing out small penalized parameter estimates. Parameters with absolute value below beta_min are set to zero, both during EBIC evaluation (for parameter counting) and in the final model. Can be:

"numerical"

Uses a fixed threshold of 1e-05 (default).

"theoretical"

Uses sqrt(log(p) / n) where p is the number of penalized parameters and n is the total sample size.

numeric value

Uses the provided value directly as the threshold.

verbose

Logical, should progress messages be printed? Defaults to the model's verbose setting.

Details

The search proceeds as follows:

  1. Compute lambda_max: The analytical upper bound is derived from KKT (Karush-Kuhn-Tucker) conditions at the null-penalized model (all penalized parameters fixed at zero). Specifically, lambda_max = max(|grad_j|) / alpha where grad_j are the gradient elements for penalized parameters at the null solution and alpha is the elastic net mixing parameter.

  2. Build lambda grid: A log-spaced sequence of nLambda values from lambda_max down to lambda_max * lambda_min_ratio.

  3. Grid search with warm starts: For each lambda (from largest to smallest), the model is optimized using ISTA. The solution from the previous lambda serves as the starting point (warm start), which substantially reduces computation time. The EBIC (Extended Bayesian Information Criterion) is computed using the unpenalized log-likelihood (Convention A), counting only parameters with |estimate| >= beta_min as non-zero.

  4. Beta-min thresholding: Penalized parameters with |estimate| < beta_min are set exactly to zero in the final model.

The EBIC is computed as:

EBIC=2LL+klog(n)+4kγlog(pv)EBIC = -2 \cdot LL + k \cdot \log(n) + 4 \cdot k \cdot \gamma \cdot \log(p_v)

where LLLL is the unpenalized log-likelihood, kk is the effective number of parameters (unpenalized free parameters plus non-zero penalized parameters), nn is the sample size, γ\gamma is the EBIC tuning parameter, and pvp_v is the number of observed variables.

The returned model stores metadata about the search in model@optim$lambda_search, a list containing: criterion, gamma, best_lambda, best_criterion, beta_min, lambda_max, nLambda, and n_thresholded.

Value

An object of class psychonetrics (psychonetrics-class) with:

  • The selected lambda assigned to all auto-select penalty parameters

  • Parameters optimized at the best lambda

  • Near-zero penalized parameters set to exactly zero (via beta_min)

  • Search metadata stored in model@optim$lambda_search

After running find_penalized_lambda, use refit to obtain valid standard errors and fit indices via post-selection inference.

Author(s)

Sacha Epskamp

References

Foygel, R., & Drton, M. (2010). Extended Bayesian Information Criteria for Gaussian Graphical Models. In Advances in Neural Information Processing Systems (Vol. 23).

See Also

penalize for manually setting penalty parameters, runmodel for running models (calls find_penalized_lambda automatically when auto-select penalties are present), refit for post-selection inference after penalized estimation.

Examples

# Load bfi data from psych package:
library("psychTools")
library("dplyr")
data(bfi)

ConsData <- bfi %>%
  select(A1:A5) %>%
  na.omit

vars <- names(ConsData)

# Automatic lambda selection (called implicitly by runmodel):
mod <- ggm(ConsData, vars = vars, estimator = "PML")
mod <- mod %>% runmodel  # automatically searches for best lambda

# Check lambda search results:
mod@optim$lambda_search

# Post-selection refit for standard errors:
mod_refit <- mod %>% refit
mod_refit %>% parameters

# Direct call with custom criterion:
mod2 <- ggm(ConsData, vars = vars, estimator = "PML")
mod2 <- find_penalized_lambda(mod2, criterion = "ebic1",
                              nLambda = 100)

Print fit indices

Description

This function will print all fit indices of the model. For the least-squares estimators with a mean-and-variance adjusted test ("DWLS"/"WLSMV") and for the robust maximum likelihood estimators ("MLM", "MLMV", "MLMVS", "MLR"; see setestimator), the printed measures additionally include the scaled test statistic (chisq.scaled, chisq.scaling.factor, df.scaled, and chisq.shift.parameters for the scaled-and-shifted variant) and, for robust ML, the robust fit indices (rmsea.robust, cfi.robust, tli.robust).

Usage

fit(x)

Arguments

x

A psychonetrics model.

Value

Invisibly returns a data frame with fit measure estimates.

Author(s)

Sacha Epskamp

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit an empty GGM:
mod0 <- ggm(ConsData, vars = vars, omega = "zero")

# Run model:
mod0 <- mod0 %>% runmodel

# Inspect fit:
mod0 %>% fit # Pretty bad fit...

Parameters modification

Description

The fixpar function can be used to fix a parameter to some value (Typically zero), and the freepar function can be used to free a parameter from being fixed to a value.

Usage

fixpar(x, matrix, row, col, value = 0, group, verbose, 
        log = TRUE, runmodel = FALSE, ...)

freepar(x, matrix, row, col, start, group, verbose, log =
        TRUE, runmodel = FALSE, startEPC = TRUE, ...)

Arguments

x

A psychonetrics model.

matrix

String indicating the matrix of the parameter

row

Integer or string indicating the row of the matrix of the parameter

col

Integer or string indicating the column of the matrix of the parameter

value

Used in fixpar to indicate the value to which a parameters is constrained

start

Used in freepar to indicate the starting value of the parameter

group

Integer indicating the group of the parameter to be constrained

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

runmodel

Logical, should the model be updated?

startEPC

Logical, should the starting value be set at the expected parameter change?

...

Arguments sent to runmodel

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Attempt to Fix Starting Values

Description

This function attempts to fix starting values by comparing the analytic gradient to a numerically approximated gradient. Parameters with a difference between the analytic and numeric gradient that exceeds 'maxdiff' will be reduced by a factor of 'reduce' in each iteration until the average absolute difference between analytic and numeric gradients is lower than 'tol'. Only off-diagonal elements in omega, sigma, kappa, lowertri or rho matrices or any element in beta matrices are adjusted.

Usage

fixstart(x, reduce = 0.5, maxdiff = 0.1, tol = 0.01, maxtry = 25)

Arguments

x

A 'psychonetrics' model

reduce

The factor with which problematic parameters are reduced in each iteration.

maxdiff

Maximum difference between analytic and numeric gradient to be considered problematic.

tol

Average absolute difference between analytic and numeric gradient that is considered acceptable.

maxtry

Maximum number of iterations to attempt to fix starting values.

Value

An object of the class psychonetrics (psychonetrics-class) with adjusted starting values.

Author(s)

Sacha Epskamp


Convert a lavaan model to a psychonetrics lvm

Description

Converts a lavaan model into an equivalent psychonetrics latent variable model (lvm) with latent = "cov" and residual = "cov". The input can be a fitted lavaan object (e.g., from lavaan::cfa or lavaan::sem), or lavaan model syntax together with a data frame. Only the public lavaan API is used; no lavaan source code is reused.

Usage

fromlavaan(x, data = NULL, run = FALSE, estimator = "default",
           baseline_saturated = TRUE, verbose = FALSE, ...)

Arguments

x

A fitted lavaan object, or a character string with lavaan model syntax. When syntax is supplied, the model is set up internally with lavaan::sem(model = x, data = data, meanstructure = TRUE, fixed.x = FALSE, do.fit = FALSE).

data

A data frame. Required when x is model syntax; ignored when x is a fitted lavaan object.

run

Logical. If TRUE, the resulting psychonetrics model is estimated with runmodel before being returned.

estimator

The estimator passed to lvm. The default ("default") uses "ML", or "FIML" when lavaan was fitted with full-information maximum likelihood for missing data.

baseline_saturated

Logical, passed to lvm; should the baseline and saturated models be included? Mostly used internally.

verbose

Logical. If TRUE, an experimental-feature note is shown and progress is printed.

...

Further arguments passed to lvm.

Details

The converted model reproduces the lavaan specification using the LISREL-style model matrices that lavaan exposes through lavInspect(fit, "free") and lavInspect(fit, "est"): factor loadings (lambda), the latent variance–covariance matrix (sigma_zeta, lavaan's psi), the residual variance–covariance matrix (sigma_epsilon, lavaan's theta), structural regressions (beta), observed intercepts (nu) and latent intercepts (nu_eta, lavaan's alpha). Observed variables that appear as structural (regression) variables are carried as phantom latent columns; any latent whose name clashes with an observed variable is renamed to eta_<name>. Equality constraints are detected via shared parameter labels and simple == rows and mapped onto shared psychonetrics parameter (par) indices.

The following are guaranteed to match lavaan (for a standard ML fit, see the caveats below): the parameter estimates, the (expected-information) standard errors, the chi-square test statistic and degrees of freedom, the number of free parameters, and the log-likelihood.

Caveats. (1) If the lavaan model has no meanstructure, psychonetrics adds a saturated mean structure (free nu, nu_eta fixed to 0): estimates, standard errors, chi-square and df still match, but the log-likelihood differs by a constant; a warning is issued. (2) With fixed.x = TRUE and exogenous covariates, psychonetrics treats the covariates as random (endogenous): estimates, standard errors and chi-square match, but df-based fit measures and the log-likelihood do not (lavaan conditions on the covariates); a warning is issued. (3) If lavaan used likelihood = "wishart" (the n1n-1 normalization), psychonetrics uses the normal (nn) likelihood, so the log-likelihood differs; a warning is issued. (4) Robust standard errors and robust/scaled test statistics are not transferred; the model is converted as plain ML, with a warning. (5) For FIML, psychonetrics uses expected information for standard errors, whereas lavaan defaults to observed information, so FIML standard errors may differ slightly even though the log-likelihood matches.

Unsupported. The following lavaan features cannot be converted and raise an informative error: two-level / multilevel models (cluster=, level:), defined parameters (:=), inequality constraints (<, >), general (non-simple) equality constraints, formative indicators (<~), conditional.x = TRUE, and categorical (ordinal) endogenous variables.

Value

An object of class psychonetrics (see psychonetrics-class).

Author(s)

Sacha Epskamp

References

Rosseel, Y. (2012). lavaan: An R Package for Structural Equation Modeling. Journal of Statistical Software, 48(2), 1-36. doi:10.18637/jss.v048.i02

See Also

tolavaan, lvm

Examples

if (requireNamespace("lavaan", quietly = TRUE)){
  library("lavaan")

  # A confirmatory factor analysis fitted in lavaan:
  data(HolzingerSwineford1939)
  HS <- HolzingerSwineford1939
  fit <- cfa(' visual  =~ x1 + x2 + x3
               textual =~ x4 + x5 + x6
               speed   =~ x7 + x8 + x9 ',
             data = HS, meanstructure = TRUE)

  # Convert to a psychonetrics lvm and run it:
  mod <- fromlavaan(fit, run = TRUE)
  fit(mod)

  # The log-likelihood matches lavaan:
  c(lavaan = as.numeric(logLik(fit)), psychonetrics = mod@fitmeasures$logl)

  # Equivalent starting from syntax + data (without fitting in lavaan first):
  mod2 <- fromlavaan(' visual  =~ x1 + x2 + x3
                       textual =~ x4 + x5 + x6
                       speed   =~ x7 + x8 + x9 ',
                     data = HS, run = TRUE)
}

Generate data from a fitted psychonetrics object

Description

This function will generate new data from the estimated mean and variance-covariance structure of a psychonetrics model.

Usage

generate(x, n = 500)

Arguments

x

A psychonetrics model.

n

Number of cases to sample per group.

Value

A data frame with simulated data

Author(s)

Sacha Epskamp


Extract an estimated matrix

Description

This function will extract an estimated matrix, and will either return a single matrix for single group models or a list of such matrices for multiple group models.

Usage

getmatrix(x, matrix, group, threshold = FALSE, alpha = 0.01,
           adjust = c("none", "holm", "hochberg", "hommel",
           "bonferroni", "BH", "BY", "fdr"), mode = c("tested",
           "all"), diag = TRUE)

Arguments

x

A psychonetrics model.

matrix

String indicating the matrix to be extracted.

group

Integer indicating the group for the matrix to be extracted.

threshold

Logical. Should the matrix be thresholded (non-significant values set to zero? Can also be a value with an absolute threshold below which parameters are set to zero.)

alpha

Significance level to use.

adjust

p-value adjustment method to use. See p.adjust.

mode

Mode for adjusting for multiple comparisons. Should all parameters be considered as the total number of tests or only the tested parameters (parameters of interest)?

diag

Set to FALSE to set diagonal elements to zero.

Value

A matrix of parameter estimates, or a list of such matrices for multiple group models.

Author(s)

Sacha Epskamp

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars, omega = "full")

# Run model:
mod <- mod %>% runmodel

# Obtain network:
mod %>% getmatrix("omega")

Obtain the asymptotic covariance matrix

Description

This function can be used to obtain the estimated asymptotic covariance matrix from a psychonetrics object.

Usage

getVCOV(model, approximate_SEs = FALSE)

Arguments

model

A psychonetrics model.

approximate_SEs

Logical, should standard errors be approximated? If true, an approximate matrix inverse of the Fisher information is used to obtain the standard errors.

Value

This function returns a matrix.

Author(s)

Sacha Epskamp


Group equality constraints

Description

The groupequal function constrains parameters equal across groups, and the groupfree function frees equality constraints across groups.

Usage

groupequal(x, matrix, row, col, verbose, log = TRUE, runmodel =
                    FALSE, identify = TRUE, ...)

groupfree(x, matrix, row, col, verbose, log = TRUE, runmodel =
                    FALSE, identify = TRUE, ...)

Arguments

x

A psychonetrics model.

matrix

String indicating the matrix of the parameter

row

Integer or string indicating the row of the matrix of the parameter

col

Integer or string indicating the column of the matrix of the parameter

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

runmodel

Logical, should the model be updated?

identify

Logical, should the model be identified?

...

Arguments sent to runmodel

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Ising model

Description

This is the family of Ising models fit to datasets with two or more ordered integer response options. The classical case is a dichotomous dataset (e.g., encoded with -1 and 1 or with 0 and 1), but the same parameterization—one threshold (tau) per variable and a pairwise network (omega)—is also used for any number of ordered response options (e.g., c(-1,0,1) or seq(-5,5); the values need not be integers), encoded identically across all variables. Only the partition function changes: it sums over all length(responses)^nNode response patterns rather than only 2^nNode. Note that the input matters (see also https://arxiv.org/abs/1811.02916) in this model! Models based on a dataset that is encoded with -1 and 1 are not entirely equivalent to models based on datasets encoded with 0 and 1 (non-equivalences occur in multi-group settings with equality constraints).

Usage

Ising(data, omega = "full", tau, beta, beta_model =
                 c("beta", "log_beta"), vars, groups, covs, means,
                 nobs, covtype = c("choose", "ML", "UB"), responses,
                 missing = "listwise", equal = "none",
                 baseline_saturated = TRUE, estimator = "default",
                 optimizer, storedata = FALSE, WLS.W, sampleStats,
                 identify = TRUE, verbose = FALSE, maxNodes = 20,
                 maxStates = 2^maxNodes, min_sum = -Inf,
                 bootstrap = FALSE, boot_sub,
                 boot_resample, penalty_lambda = NA,
                penalty_alpha = 1, penalize_matrices)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

omega

The network structure. Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions nNode x nNode with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

tau

Optional vector encoding the threshold/intercept structure. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

beta

Optional scalar encoding the inverse temperature. 1 indicate free beta parameters, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such scalars.

beta_model

How should beta be modeled? Set beta_model = "log_beta" to model the log of beta rather than beta directly.

vars

An optional character vector encoding the variables used in the analysis. Must equal names of the dataset in data.

groups

An optional string indicating the name of the group variable in the data.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure covtype argument is set correctly to the type of covariances used.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

responses

A vector of the response options used, encoded identically across all variables (e.g., c(-1,1), c(0,1), c(-1,0,1) or seq(-5,5)). Automatically detected from the data when not supplied; required when covs is used. Any number of distinct response options is allowed, and the values need not be integers.

missing

How should missingness be handled when data is used. Only "listwise" (listwise deletion) is currently supported for the Ising model; other options (e.g. "pairwise") are rejected at construction because they produce undefined sufficient statistics.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Currently implemented are "ML" for (exact) maximum likelihood estimation and "PML" for penalized maximum likelihood estimation; no other estimators are supported for the Ising model.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

WLS.W

Optional WLS weights matrix. CURRENTLY NOT USED.

sampleStats

An optional sample statistics object. Mostly used internally.

identify

Logical, should the model be identified?

verbose

Logical, should messages be printed?

maxNodes

The maximum number of nodes allowed in the analysis. Used to set the default of maxStates (2^maxNodes); for binary data this reproduces the historical node limit. It is not recommended to set this higher.

maxStates

The maximum number of response patterns the exact ML estimator may enumerate. Exact ML estimation of the Ising model sums over every possible response pattern when computing the partition function, expected values and (expected) Hessian, so the cost grows as length(responses)^nNode. The function stops with an error when length(responses)^nNode exceeds maxStates. The default 2^maxNodes reproduces the historical binary node limit while accounting for more than two response options. Raise this only if the computation is feasible (note that the number of states—and hence the run time—grows very quickly with both the number of nodes and the number of response options).

min_sum

The minimum sum score that is artificially possible in the dataset. Defaults to -Inf. Set this only if you know a lower sum score is not possible in the data, for example due to selection bias.

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). NA (default) triggers automatic selection via EBIC-based grid search when a penalized estimator is used; set to a specific numeric value to use a fixed penalty strength (0 = no penalty). See find_penalized_lambda and penalize.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type.

Details

The Ising Model takes the following form:

Pr(Y=y)=exp(βH(y;τ,Ω))Z(τ,Ω)\Pr(\boldsymbol{Y} = \boldsymbol{y}) = \frac{\exp\left( -\beta H\left(\boldsymbol{y}; \boldsymbol{\tau}, \boldsymbol{\Omega}\right)\right)}{Z(\boldsymbol{\tau}, \boldsymbol{\Omega})}

With Hamiltonian:

H(y;τ,Ω)=i=1mτiyii=2mj=1i1ωijyiyj.H\left(\boldsymbol{y}; \boldsymbol{\tau}, \boldsymbol{\Omega}\right) = -\sum_{i=1}^{m} \tau_i y_{i} - \sum_{i=2}^{m} \sum_{j=1}^{i-1} \omega_{ij} y_i y_j.

And Z representing the partition function or normalizing constant.

The responses yiy_i need not be dichotomous: they may take any number of ordered values (the same set for every variable, and not necessarily integers), supplied through responses or detected automatically from the data. The Hamiltonian above is unchanged; only the partition function ZZ (and the expected values and Hessian derived from it) sums over all length(responses)^nNode response patterns instead of only 2^nNode. With two response options the model is the usual Ising model and reproduces the same estimates as before. With more than two response options the model remains a maximum-entropy distribution matching the means (via tau) and the pairwise products (via omega); it does not model higher-order interactions or the within-variable second moments, and the enumeration cost grows steeply with the number of nodes and response options (see maxStates).

Value

An object of the class psychonetrics

Author(s)

Sacha Epskamp <[email protected]>

References

Epskamp, S., Maris, G., Waldorp, L. J., & Borsboom, D. (2018). Network Psychometrics. In: Irwing, P., Hughes, D., & Booth, T. (Eds.), The Wiley Handbook of Psychometric Testing, 2 Volume Set: A Multidisciplinary Reference on Survey, Scale and Test Development. New York: Wiley.

See Also

BlumeCapel for the more general Blume-Capel model, which adds a quadratic node potential (delta) and reduces to the Ising model when all delta are fixed to zero.

Examples

library("dplyr")
data("Jonas")

# Variables to use:
vars <- names(Jonas)[1:10]

# Arranged groups to put unfamiliar group first (beta constrained to 1):
Jonas <- Jonas[order(Jonas$group),]

# Form saturated model:
model1 <- Ising(Jonas, vars = vars, groups = "group")

# Run model:
model1 <- model1 %>% runmodel
# Note: SEs are approximated automatically because there are zeroes
# in the crosstables of the "Knows Jonas" group, which makes the
# Fisher information matrix singular. A warning is shown when
# this fallback occurs.

# Prune-stepup to find a sparse model:
model1b <- model1 %>% prune(alpha = 0.05) %>%  stepup(alpha = 0.05)

# Equal networks:
model2 <- model1 %>% groupequal("omega") %>% runmodel

# Prune-stepup to find a sparse model:
model2b <- model2 %>% prune(alpha = 0.05) %>% stepup(mi = "mi_equal", alpha = 0.05)

# Equal thresholds:
model3 <- model2 %>% groupequal("tau") %>% runmodel

# Prune-stepup to find a sparse model:
model3b <- model3 %>% prune(alpha = 0.05) %>% stepup(mi = "mi_equal", alpha = 0.05)

# Equal beta:
model4 <- model3 %>% groupequal("beta") %>% runmodel

# Prune-stepup to find a sparse model:
model4b <- model4 %>% prune(alpha = 0.05) %>% stepup(mi = "mi_equal", alpha = 0.05)

# Compare all models:
compare(
  `1. all parameters free (dense)` = model1,
  `2. all parameters free (sparse)` = model1b,
  `3. equal networks (dense)` = model2,
  `4. equal networks (sparse)` = model2b,
  `5. equal networks and thresholds (dense)` = model3,
  `6. equal networks and thresholds (sparse)` = model3b,
  `7. all parameters equal (dense)` = model4,
  `8. all parameters equal (sparse)` = model4b
) %>% arrange(BIC)

Jonas dataset

Description

Responses of 10 attitude items towards a researcher named Jonas. Participants were shown three photos of Jonas with the text: "This is Jonas, a researcher from Germany who is now becoming a PhD in Psychology". Subsequently, the participants had to answer 10 yes / no questions starting with "I believe that Jonas...", as well as rate their familiarity with Jonas. The sample consists of people familiar with Jonas and not familiar with Jonas, and allows for testing Attitudinal Entropy Framework <doi:10.1080/1047840X.2018.1537246>.

Usage

data("Jonas")

Format

A data frame with 215 observations on the following 12 variables.

scientist

... is a good scientist

jeans

... Is a person that wears beautiful jeans

cares

... really cares about people like you

economics

... would solve our economic problems

hardworking

... is hardworking

honest

... is honest

intouch

... is in touch with ordinary people

knowledgeable

... is knowledgeable

makeupmind

... can't make up his mind

getsthingsdone

... gets things done

familiar

Answers to the question "How familiar are you with Jonas?" (three responses possible)

group

The question 'familiar' categorized in two groups ("Knows Jonas" and "Doesn't know Jonas")

Source

Data collected by the package author via social media, among people familiar and unfamiliar with the researcher Jonas.

Examples

data(Jonas)

Latent growth curve model

Description

Wrapper to lvm to specify a latent growth curve model.

Usage

latentgrowth(vars, time = seq_len(ncol(vars)) - 1, covariates =
                   character(0), covariates_as = c("regression",
                   "covariance"), ...)

Arguments

vars

Different from in other psychonetrics models, this must be a *matrix* with each row indicating a variable and each column indicating a measurement. The matrix must be filled with names of the variables in the dataset corresponding to variable i at wave j. NAs can be used to indicate missing waves. The rownames of this matrix will be used as variable names.

time

A vector with the encoding of each measurement (e.g., 0, 1, 2, 3).

covariates

A vector with strings indicating names of between-person covariate variables in the data

covariates_as

Should covariates be included as regressions or actual covariates?

...

Arguments sent to lvm

Details

See https://github.com/SachaEpskamp/SEM-code-examples/tree/master/Latent_growth_examples/psychonetrics for examples

Value

An object of the class psychonetrics (psychonetrics-class). See for an example https://github.com/SachaEpskamp/SEM-code-examples/tree/master/Latent_growth_examples/psychonetrics.

Author(s)

Sacha Epskamp

Examples

library("dplyr")

# Smoke data cov matrix, based on LISS data panel https://www.dataarchive.lissdata.nl
smoke <- structure(c(47.2361758611759, 43.5366809116809, 41.0057465682466, 
                     43.5366809116809, 57.9789886039886, 47.6992521367521, 
                     41.0057465682466, 
                     47.6992521367521, 53.0669434731935), .Dim = c(3L, 3L), 
                   .Dimnames = list(
                       c("smoke2008", "smoke2009", "smoke2010"), c("smoke2008", 
                   "smoke2009", "smoke2010")))

# Design matrix:
design <- matrix(rownames(smoke),1,3)

# Form model:
mod <- latentgrowth(vars = design, 
                covs = smoke, nobs = 352
)

## Not run: 
# Run model:
mod <- mod %>% runmodel

# Evaluate fit:
mod %>% fit

# Look at parameters:
mod %>% parameters

## End(Not run)

Retrieve the psychonetrics logbook

Description

This function can be used to retrieve the logbook of a 'psychonetrics' object.

Usage

logbook(x, log = TRUE)

Arguments

x

A 'psychonetrics' object.

log

Logical, should the entry that the logbook is accessed be added?

Value

A list of log entries (objects of class psychonetrics_log) stored in the model.

Author(s)

Sacha Epskamp


Parallel loop for psychonetrics

Description

A convenience wrapper for running repeated psychonetrics analyses in parallel. Replaces the typical boilerplate of makeCluster / clusterExport / parLapply / stopCluster with a single function call. Particularly useful for bootstrapping, simulation studies, and cross-validation.

Variables referenced in the expression that exist in the calling environment are automatically exported to parallel workers, so explicit clusterExport calls are not needed in most cases.

Usage

loop_psychonetrics(expr, reps = 1000, nCores = 1,
                   export = character(0),
                   packages = c("psychonetrics", "dplyr"),
                   verbose = TRUE, envir = parent.frame(),
                   seed = NULL)

Arguments

expr

An expression (code block) to evaluate on each iteration. Typically enclosed in curly braces {...}. The expression should return a single object (e.g., a psychonetrics model).

reps

Number of replications (default: 1000).

nCores

Number of CPU cores to use. Set to 1 for sequential execution (default), or higher for parallel execution via makePSOCKcluster.

export

Character vector of additional variable names to export to parallel workers. Usually not needed because variables referenced in expr are auto-detected and exported.

packages

Character vector of packages to load on parallel workers (default: c("psychonetrics", "dplyr")).

verbose

Logical; if TRUE (default), shows a progress bar via pbapply.

envir

The environment in which to look up variables for auto-export and to evaluate the expression in sequential mode. Defaults to the calling environment.

seed

Optional integer seed for reproducible random number generation. In parallel mode this calls clusterSetRNGStream so that repeated runs with the same seed and number of cores give identical results; in sequential mode set.seed is used. The default NULL leaves the random number generator untouched (previous behavior).

Details

When nCores > 1, a PSOCK cluster is created and automatically cleaned up when the function exits (even on error). The specified packages are loaded on each worker, and variables (as well as functions defined in the calling environment) referenced in expr are automatically detected and exported.

The replication index i (running from 1 to reps) is visible inside expr, in both sequential and parallel mode.

For bootstrapping, use this function together with bootstrap = "nonparametric" in the model constructor and aggregate_bootstraps to summarize the results.

Value

A list of length reps, where each element is the result of evaluating expr once.

See Also

aggregate_bootstraps, bootstrap, CIplot

Examples

library(dplyr)
data(NA2020)

# Fit the original model:
model <- ggm(NA2020, estimator = "FIML") %>% runmodel

# Bootstrap with pruning (parallel, 100 reps):
bootstraps <- loop_psychonetrics({
  ggm(NA2020, bootstrap = "nonparametric",
      estimator = "FIML") %>%
    runmodel %>%
    prune(alpha = 0.05)
}, reps = 100, nCores = 2)

# Aggregate and inspect:
boot_agg <- aggregate_bootstraps(
  sample = model %>% prune(alpha = 0.05),
  bootstraps = bootstraps
)

# View results:
parameters(boot_agg)
CIplot(boot_agg, "omega", split0 = TRUE)

Continuous latent variable family of psychonetrics models

Description

This is the family of models that models the data as a structural equation model (SEM), allowing the latent and residual variance-covariance matrices to be further modeled as networks. The latent and residual arguments can be used to define what latent and residual models are used respectively: "cov" (default) models a variance-covariance matrix directly, "chol" models a Cholesky decomposition, "prec" models a precision matrix, and "ggm" models a Gaussian graphical model (Epskamp, Rhemtulla and Borsboom, 2017). The wrapper lnm() sets latent = "ggm" for the latent network model (LNM), the wrapper rnm() sets residual = "ggm" for the residual network model (RNM), and the wrapper lrnm() combines the LNM and RNM.

Usage

lvm(data, lambda, latent = c("cov", "chol", "prec",
                   "ggm"), residual = c("cov", "chol", "prec", "ggm"),
                   sigma_zeta = "full", kappa_zeta = "full", omega_zeta =
                   "full", lowertri_zeta = "full", delta_zeta = "full",
                   sigma_epsilon = "diag", kappa_epsilon = "diag",
                   omega_epsilon = "zero", lowertri_epsilon = "diag",
                   delta_epsilon = "diag", beta = "zero", nu, nu_eta, tau,
                   identify = TRUE, identification = c("loadings",
                   "variance"), vars, ordered = character(0), latents,
                   groups, groupvar, covs, cors, means, nobs,
                   missing = "auto", equal = "none",
                   baseline_saturated = TRUE, estimator = "default",
                   likelihood = c("normal", "wishart"),
                   fixed_x = character(0),
                   optimizer, storedata = FALSE, WLS.W, covtype =
                   c("choose", "ML", "UB"), corinput, standardize = c("none", "z",
                   "quantile"), sampleStats, verbose = FALSE,
                   simplelambdastart = FALSE, start = "default",
                   bootstrap = FALSE,
                   boot_sub, boot_resample, penalty_lambda = NA,
                   penalty_alpha = 1, penalize_matrices)

lnm(...)
rnm(...)
lrnm(...)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

lambda

A model matrix encoding the factor loading structure. Each row indicates an indicator and each column a latent. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. Can also be set to "full" to freely estimate all factor loadings, including all cross-loadings (this requires the latents to be named through the latents argument). For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

latent

The type of latent model used. See description.

residual

The type of residual model used. See description.

sigma_zeta

Only used when latent = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta

Only used when latent = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_zeta

Only used when latent = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta

Only used when latent = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta

Only used when latent = "ggm". Either "diag" or "zero", or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_epsilon

Only used when residual = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_epsilon

Only used when residual = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_epsilon

Only used when residual = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_epsilon

Only used when residual = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_epsilon

Only used when residual = "ggm". Either "diag" or "zero", or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

beta

A model matrix encoding the structural relations between latent variables. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

nu

Optional vector encoding the intercepts of the observed variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

nu_eta

Optional vector encoding the intercepts of the latent variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

tau

Optional matrix encoding the threshold parameters for ordinal variables. Each column corresponds to an observed variable and each row to a threshold. Use 0 for fixed elements, 1 for free elements, and higher integers for equality constraints. Typically set up automatically when ordered is specified.

identify

Logical, should the model be automatically identified?

identification

Type of identification used. "loadings" to fix the first factor loadings to 1, and "variance" to fix the diagonal of the latent variable model matrix (sigma_zeta, lowertri_zeta, delta_zeta or kappa_zeta) to 1.

vars

An optional character vector encoding the variables used in the analysis. Must equal names of the dataset in data.

ordered

Character vector of variable names to treat as ordinal, or TRUE to treat all variables as ordinal. When ordinal variables are specified, polychoric correlations and thresholds are estimated from the data and the model is fit using the Muthen (1984) three-stage estimator. The estimator defaults to "DWLS" for ordinal models; "WLS" and "ULS" are also supported. Identification is automatically set to "variance".

latents

An optional character vector with names of the latent variables.

groups

Deprecated. Use groupvar instead. An optional string indicating the name of the group variable in data.

groupvar

An optional string indicating the name of the group variable in data. Replaces the deprecated groups argument; if both are supplied, groupvar takes precedence with a warning.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure covtype argument is set correctly to the type of covariances used.

cors

A sample correlation matrix, or a list/array of such matrices for multiple groups. When supplied, the matrix is treated as a covariance matrix with a warning (appropriate for standardized data). Requires nobs. Note: corinput = TRUE is not supported in lvm; use varcov with type = "cor" for correlation-based models.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

corinput

Logical. Only supported for ordinal data in lvm(); defaults to FALSE for continuous data. Setting corinput = TRUE is not supported for lvm() and will produce an error; use varcov with type = "cor" instead.

missing

How should missingness be handled in computing the sample covariances and number of observations when data is used. Can be "auto" (default) for automatic detection, "listwise" for listwise deletion, or "pairwise" for pairwise deletion. When "auto", the function checks for missing data and switches ML to FIML, PML to PFIML, or defaults to listwise for LS estimators.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Currently implemented are "ML" for maximum likelihood estimation, "FIML" for full-information maximum likelihood estimation, "PML" for penalized maximum likelihood estimation, "PFIML" for penalized full-information maximum likelihood estimation, "ULS" for unweighted least squares estimation, "WLS" for weighted least squares estimation, and "DWLS" for diagonally weighted least squares estimation. "WLSMV" is accepted as a synonym for "DWLS" (both use DWLS estimation with a mean-and-variance adjusted scaled test statistic). When missing = "auto" (default), "ML" is automatically switched to "FIML" and "PML" to "PFIML" if missing data is detected. Defaults to "ML" for continuous data and "DWLS" when ordinal variables are specified via ordered.

likelihood

The Gaussian likelihood scaling for maximum-likelihood estimation. "normal" (the default) uses the nn (biased) sample-covariance denominator; "wishart" uses the n1n-1 (unbiased) sample covariance per group, so the chi-square uses (ng1)(n_g - 1) multipliers and the standard errors are inflated by ng/(ng1)\sqrt{n_g/(n_g-1)}, matching lavaan's likelihood = "wishart" (Rosseel, 2012). Only available for complete-data maximum likelihood (estimator = "ML"); it errors for FIML, least-squares and ordinal estimators and for raw time-series input. Default "normal" reproduces previous behaviour exactly.

fixed_x

Character vector of exogenous latent variable names whose means and mutual (co)variances are fixed to their sample values and excluded from the free-parameter count and the degrees-of-freedom statistic count, matching lavaan's sem(..., fixed.x = TRUE) (Rosseel, 2012). This is the way to enter observed exogenous covariates into a psychonetrics SEM: model each observed covariate as a single-indicator latent (loading 1, residual variance 0) and pass that latent's name. Fixing conditions the model on these covariates and relaxes the multivariate-normality assumption on them; regression paths from the fixed-x latents (xηx \rightarrow \eta) remain free. Only supported for complete-data estimator = "ML". The reported log-likelihood is the conditional log-likelihood. Default character(0) (behaviour unchanged). Note: as in varcov, the incremental fit indices use the unconditional baseline and may differ from lavaan; the absolute fit measures (chi-square, df, RMSEA, AIC, BIC, log-likelihood) and all estimates and standard errors match.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

verbose

Logical, should progress be printed to the console?

WLS.W

The weights matrix used in WLS estimation (experimental)

sampleStats

An optional sample statistics object. Mostly used internally.

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

standardize

Which standardization method should be used? "none" (default) for no standardization, "z" for z-scores, and "quantile" for a non-parametric transformation to the quantiles of the marginal standard normal distribution.

simplelambdastart

Logical, should simple start values be used for lambda? Setting this to TRUE can avoid some estimation problems.

start

Controls the starting values for the beta (structural regression) matrix. Can be "default" (default) for OLS-based starting values derived from the factor-analysis-implied latent covariance matrix, "simple" for the previous behavior (all free elements set to 0.001), or a fitted psychonetrics object to extract beta estimates as starting values. The OLS-based starts compute regression coefficients between latent variables using the FA-derived covariance matrix, which typically leads to faster convergence for models with structural paths. Guard rails automatically fall back to simple starts if numerical issues are detected (e.g., near-singular matrices, extreme coefficients).

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). NA (default) triggers automatic selection via EBIC-based grid search when a penalized estimator is used; set to a specific numeric value to use a fixed penalty strength (0 = no penalty). See find_penalized_lambda and penalize.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type.

...

Arguments sent to lvm

Details

The model used in this family is:

var(y)=Λ(IB)1Σζ(IB)1Λ+Σε\mathrm{var}( \boldsymbol{y} ) = \boldsymbol{\Lambda} (\boldsymbol{I} - \boldsymbol{B})^{-1} \boldsymbol{\Sigma}_{\zeta} (\boldsymbol{I} - \boldsymbol{B})^{-1\top} \boldsymbol{\Lambda}^{\top} + \boldsymbol{\Sigma}_{\varepsilon}

E(y)=ν+Λ(IB)1νeta\mathcal{E}( \boldsymbol{y} ) = \boldsymbol{\nu} + \boldsymbol{\Lambda} (\boldsymbol{I} - \boldsymbol{B})^{-1} \boldsymbol{\nu}_eta

in which the latent covariance matrix can further be modeled in three ways. With latent = "chol" as Cholesky decomposition:

Σζ=LζLζ\boldsymbol{\Sigma}_{\zeta} = \boldsymbol{L}_{\zeta}\boldsymbol{L}_{\zeta}^{\top},

with latent = "prec" as Precision matrix:

Σζ=Kζ1\boldsymbol{\Sigma}_{\zeta} = \boldsymbol{K}_{\zeta}^{-1},

and finally with latent = "ggm" as Gaussian graphical model:

Σζ=Δζ(IΩζ)(1)Δζ\boldsymbol{\Sigma}_{\zeta} = \boldsymbol{\Delta}_{\zeta}(\boldsymbol{I} - \boldsymbol{\Omega}_{\zeta})^(-1) \boldsymbol{\Delta}_{\zeta}.

Likewise, the residual covariance matrix can also further be modeled in three ways. With residual = "chol" as Cholesky decomposition:

Σε=LεLε\boldsymbol{\Sigma}_{\varepsilon} = \boldsymbol{L}_{\varepsilon}\boldsymbol{L}_{\varepsilon}^{\top},

with residual = "prec" as Precision matrix:

Σε=Kε1\boldsymbol{\Sigma}_{\varepsilon} = \boldsymbol{K}_{\varepsilon}^{-1},

and finally with residual = "ggm" as Gaussian graphical model:

Σε=Δε(IΩε)(1)Δε\boldsymbol{\Sigma}_{\varepsilon} = \boldsymbol{\Delta}_{\varepsilon}(\boldsymbol{I} - \boldsymbol{\Omega}_{\varepsilon})^(-1) \boldsymbol{\Delta}_{\varepsilon}.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

References

Epskamp, S., Rhemtulla, M., & Borsboom, D. (2017). Generalized network psychometrics: Combining network and latent variable models. Psychometrika, 82(4), 904-927.

Muthen, B. (1984). A general structural equation model with dichotomous, ordered categorical, and continuous latent variable indicators. Psychometrika, 49(1), 115-132.

Rosseel, Y. (2012). lavaan: An R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. doi:10.18637/jss.v048.i02

Examples

library("dplyr")

### Confirmatory Factor Analysis ###

# Example also shown in https://youtu.be/Hdu5z-fwuk8

# Load data:
data(StarWars)

# Originals only:
Lambda <- matrix(1,4)

# Model:
mod0 <- lvm(StarWars, lambda = Lambda, vars = c("Q1","Q5","Q6","Q7"), 
            identification = "variance", latents = "Originals")
            
# Run model:
mod0 <- mod0 %>% runmodel

# Evaluate fit:
mod0 %>% fit


# Full analysis
# Factor loadings matrix:
Lambda <- matrix(0, 10, 3)
Lambda[1:4,1] <- 1
Lambda[c(1,5:7),2] <- 1
Lambda[c(1,8:10),3] <- 1

# Observed variables:
obsvars <- paste0("Q",1:10)

# Latents:
latents <- c("Prequels","Original","Sequels")

# Make model:
mod1 <- lvm(StarWars, lambda = Lambda, vars = obsvars, 
            identification = "variance", latents = latents)

# Run model:
mod1 <- mod1 %>% runmodel

# Look at fit:
mod1

# Look at parameter estimates:
mod1 %>% parameters

# Completely standardized (std.all) solution with standard errors:
mod1 %>% parameters(standardized = TRUE)

# Look at modification indices:
mod1 %>% MIs

# Add and refit:
mod2 <- mod1 %>% freepar("sigma_epsilon","Q10","Q4") %>% runmodel

# Compare:
compare(original = mod1, adjusted = mod2)

# Fit measures:
mod2 %>% fit

### Path diagrams ###
# semPlot is not (yet) supported by default, but can be used as follows:
# Load packages:
if (requireNamespace("semPlot", quietly = TRUE)){
library("semPlot")

# Estimates:
lambdaEst <- getmatrix(mod2, "lambda")
psiEst <- getmatrix(mod2, "sigma_zeta")
thetaEst <- getmatrix(mod2, "sigma_epsilon")

# LISREL Model: LY = Lambda (lambda-y), TE = Theta (theta-epsilon), PS = Psi
mod <- lisrelModel(LY =  lambdaEst, PS = psiEst, TE = thetaEst)

# Plot with semPlot:
semPaths(mod, "std", "est", as.expression = "nodes")


# We can make this nicer (set whatLabels = "none" to hide labels):
semPaths(mod,

# this argument controls what the color of edges represent. In this case, 
# standardized parameters:
    what = "std", 
    
# This argument controls what the edge labels represent. In this case, parameter 
# estimates:
    whatLabels = "est", 
    
# This argument draws the node and edge labels as mathematical expressions:    
    as.expression = "nodes", 
  
# This will plot residuals as arrows, closer to what we use in class:
    style = "lisrel",
    
# This makes the residuals larger:
    residScale = 10, 
    
# qgraph colorblind friendly theme:
    theme = "colorblind",
    
# tree layout options are "tree", "tree2", and "tree3":
    layout = "tree2", 

# This makes the latent covariances connect at a cardinal center point:
    cardinal = "lat cov",

# Changes curve into rounded straight lines:
    curvePivot = TRUE, 
    
# Size of manifest variables:
    sizeMan = 4, 
    
# Size of latent variables:
    sizeLat = 10, 
    
# Size of edge labels:
    edge.label.cex = 1,
    
# Sets the margins:
    mar = c(9,1,8,1), 
    
# Prevents re-ordering of observed variables:
    reorder = FALSE, 
    
# Width of the plot:
    width = 8, 
    
# Height of plot:
    height = 5, 

# Colors according to latents:
    groups = "latents",
    
# Pastel colors:
    pastel = TRUE, 
    
# Disable borders:
    borders = FALSE 
    )
    
# Use arguments filetype = "pdf" and filename = "semPlotExample1" to store PDF
} # end semPlot block

### Latent Network Modeling ###

# Latent network model:
lnm <- lvm(StarWars, lambda = Lambda, vars = obsvars,
           latents = latents, identification = "variance",
           latent = "ggm")

# Run model:
lnm <- lnm %>% runmodel

# Look at parameters:
lnm %>% parameters

# Remove non-sig latent edge:
lnm <- lnm %>% prune(alpha = 0.05)

# Compare to the original CFA model:
compare(cfa = mod1, lnm = lnm)

# Plot network:
library("qgraph")
qgraph(lnm@modelmatrices[[1]]$omega_zeta, labels = latents,
       theme = "colorblind", vsize = 10)

# A wrapper for the latent network model is the lnm function:
lnm2 <- lnm(StarWars, lambda = Lambda, vars = obsvars,
            latents = latents, identification = "variance")
lnm2 <- lnm2 %>% runmodel %>% prune(alpha = 0.05)
compare(lnm, lnm2) # Is the same as the model before.

# I could also estimate a "residual network model", which adds partial correlations to 
# the residual level:
# This can be done using lvm(..., residual = "ggm") or with rnm(...)
rnm <- rnm(StarWars, lambda = Lambda, vars = obsvars,
           latents = latents, identification = "variance")
# Stepup search:
rnm <- rnm %>% stepup

# It will estimate the same model (with link Q10 - Q4) as above. In the case of only one 
# partial correlation, There is no difference between residual covariances (SEM) or 
# residual partial correlations (RNM).


# For more information on latent and residual network models, see:
# Epskamp, S., Rhemtulla, M.T., & Borsboom, D. Generalized Network Psychometrics: 
# Combining Network and Latent Variable Models 
# (2017). Psychometrika. doi:10.1007/s11336-017-9557-x

### Gaussian graphical models ###

# All psychonetrics functions (e.g., lvm, lnm, rnm...) allow input via a covariance 
# matrix, with the "covs" and "nobs" arguments.
# The following fits a baseline GGM network with no edges:
S <- (nrow(StarWars) - 1)/ (nrow(StarWars)) * cov(StarWars[,1:10])
ggmmod <- ggm(covs = S, nobs = nrow(StarWars))

# Run model with stepup search and pruning:
ggmmod <- ggmmod%>% prune  %>% modelsearch

# Fit measures:
ggmmod %>% fit

# Plot network:
nodeNames <- c(
"I am a huge Star Wars\nfan! (star what?)",
"I would trust this person\nwith my democracy.",
"I enjoyed the story of\nAnakin's early life.",
"The special effects in\nthis scene are awful (Battle of\nGeonosis).",
"I would trust this person\nwith my life.",
"I found Darth Vader's big\nreveal in 'Empire' one of the greatest
moments in movie history.",
"The special effects in\nthis scene are amazing (Death Star\nExplosion).",
"If possible, I would\ndefinitely buy this\ndroid.",
"The story in the Star\nWars sequels is an improvement to\nthe previous movies.",
"The special effects in\nthis scene are marvellous (Starkiller\nBase Firing)."
)
library("qgraph")
qgraph(as.matrix(ggmmod@modelmatrices[[1]]$omega), nodeNames = nodeNames, 
    legend.cex = 0.25,  theme = "colorblind", layout = "spring")

# We can actually compare this model statistically (note they are not nested) to the 
# latent variable model:
compare(original_cfa = mod1, adjusted_cfa = mod2, exploratory_ggm = ggmmod)


### Measurement invariance ###
# Let's say we are interested in seeing if people >= 30 like the original trilogy better 
# than people < 30.
# First we can make a grouping variable:
StarWars$agegroup <- ifelse(StarWars$Q12 < 30, "young", "less young")

# Let's look at the distribution:
table(StarWars$agegroup) # Pretty even...

# Observed variables:
obsvars <- paste0("Q",1:10)

# Let's look at the mean scores:
StarWars %>% group_by(agegroup) %>% summarize(across(all_of(obsvars), mean))
# Less young people seem to score higher on prequel questions and lower on other 
# questions

# Factor loadings matrix:
Lambda <- matrix(0, 10, 3)
Lambda[1:4,1] <- 1
Lambda[c(1,5:7),2] <- 1
Lambda[c(1,8:10),3] <- 1

# Residual covariances:
Theta <- diag(1, 10)
Theta[4,10] <- Theta[10,4] <- 1

# Latents:
latents <- c("Prequels","Original","Sequels")

# Make model:
mod_configural <- lvm(StarWars, lambda = Lambda, vars = obsvars,
            latents = latents, sigma_epsilon = Theta,
            identification = "variance",
            groups =  "agegroup")

# Run model:
mod_configural <- mod_configural %>% runmodel

# Look at fit:
mod_configural
mod_configural %>% fit

# Looks good, let's try weak invariance:
mod_weak <- mod_configural %>% groupequal("lambda") %>% runmodel

# Compare models:
compare(configural = mod_configural, weak = mod_weak)

# weak invariance can be accepted, let's try strong:
mod_strong <- mod_weak %>% groupequal("nu") %>% runmodel
# Means are automatically identified

# Compare models:
compare(configural = mod_configural, weak = mod_weak, strong = mod_strong)

# Questionable p-value and AIC difference, but ok BIC difference. This is quite good, but 
# let's take a look. I have not yet implemented LM tests for equality constraints, but we 
# can look at something called "equality-free" MIs:
mod_strong %>% MIs(matrices = "nu", type = "free")

# Indicates that Q10 would improve fit. We can also look at residuals:
residuals(mod_strong)

# Let's try freeing intercept 10:
mod_strong_partial <- mod_strong %>% groupfree("nu",10) %>% runmodel

# Compare all models:
compare(configural = mod_configural,
        weak = mod_weak,
        strong = mod_strong,
        strong_partial = mod_strong_partial)

# This seems worth it and lead to an acceptable model! It seems that older people find 
# the latest special effects more marvellous!
mod_strong_partial %>% getmatrix("nu")

# Now let's investigate strict invariance:
mod_strict <- mod_strong_partial %>% groupequal("sigma_epsilon") %>% runmodel

# Compare all models:
compare(configural = mod_configural,
        weak = mod_weak,
        strong_partial = mod_strong_partial,
        strict = mod_strict)
# Strict invariance can be accepted!

#  Now we can test for homogeneity!
# Are the latent variances equal?
mod_eqvar <- mod_strict %>% groupequal("sigma_zeta") %>% runmodel

# Compare:
compare(strict = mod_strict, eqvar = mod_eqvar) 

# This is acceptable. What about the means? (alpha = nu_eta)
mod_eqmeans <- mod_eqvar %>% groupequal("nu_eta") %>% runmodel

# Compare:
compare(eqvar = mod_eqvar, eqmeans = mod_eqmeans)

# Rejected! We could look at MIs again:
mod_eqmeans %>% MIs(matrices = "nu_eta", type = "free")

# Indicates the strongest effect for prequels. Let's see what happens:
eqmeans2 <- mod_eqvar %>% 
  groupequal("nu_eta",row = c("Original","Sequels")) %>% runmodel

# Compare:
compare(eqvar = mod_eqvar, eqmeans = eqmeans2)
# Questionable, what about the sequels as well?

eqmeans3 <- mod_eqvar %>% groupequal("nu_eta", row = "Original") %>% runmodel

# Compare:
compare(eqvar = mod_eqvar, eqmeans = eqmeans3)

# Still questionable.. Let's look at the mean differences:
mod_eqvar %>% getmatrix("nu_eta")

# Looks like people over 30 like the prequels better and the other two trilogies less!

Meta-analytic latent variable model

Description

Single-stage meta-analytic latent variable model (LVM) for covariance or correlation matrices. Combines a latent variable model (CFA/SEM) for the mean structure with a random-effects model for between-study heterogeneity. Based on the MAGNA framework (Epskamp, Isvoranu, & Cheung, 2022).

Usage

meta_lvm(covs, nobs, data, cors, studyvar, groups, groupvar,
                   corinput, Vmats, Vmethod = c("individual", "pooled",
                   "metaSEM_individual", "metaSEM_weighted"), Vestimation
                   = c("averaged", "per_study"),
                   lambda, beta = "zero",
                   latent = c("cov", "chol", "prec", "ggm"),
                   sigma_zeta = "full", kappa_zeta = "full",
                   omega_zeta = "full", lowertri_zeta = "full",
                   delta_zeta = "full",
                   residual = c("cov", "chol", "prec", "ggm"),
                   sigma_epsilon = "diag", kappa_epsilon = "diag",
                   omega_epsilon = "zero", lowertri_epsilon = "diag",
                   delta_epsilon = "diag",
                   identify = TRUE,
                   identification = c("loadings", "variance"),
                   randomEffects = c("chol", "cov", "prec", "ggm", "cor"),
                   sigma_randomEffects = "full",
                   kappa_randomEffects = "full",
                   omega_randomEffects = "full",
                   lowertri_randomEffects = "full",
                   delta_randomEffects = "full",
                   rho_randomEffects = "full",
                   SD_randomEffects = "full",
                   vars, latents,
                   baseline_saturated = TRUE, optimizer,
                   estimator = c("FIML", "ML"),
                   sampleStats, verbose = FALSE,
                   bootstrap = FALSE, boot_sub, boot_resample)

Arguments

covs

A list of covariance or correlation matrices. Must contain rows and columns with NAs for variables not included in a study.

nobs

A vector with the number of observations per study.

data

Optional data frame. When supplied together with studyvar, covariance matrices and sample sizes are computed internally per study. Cannot be used together with covs, cors, or nobs.

cors

A list of correlation matrices. When supplied, the matrices are treated as covariance matrices with a warning (appropriate for standardized data). Requires nobs.

studyvar

A string indicating the column name in data that identifies the study. Required when data is supplied.

groups

Deprecated. Use groupvar instead. Multi-group support is not yet included for meta-analytic models.

groupvar

Not yet supported for meta-analytic models. Supplying this argument will produce an error.

corinput

Logical. Defaults to FALSE. Controls whether the input is treated as correlation matrices.

Vmats

Optional list with 'V' matrices (sampling error variance approximations).

Vmethod

Which method should be used to approximate the sampling error variance? The "metaSEM_individual" and "metaSEM_weighted" options compute the sampling-error covariances via metaSEM::asyCov and therefore require the Suggests package metaSEM to be installed.

Vestimation

How should the sampling error estimates be evaluated?

lambda

A matrix encoding the factor loading structure. Can be a pattern matrix with TRUE/FALSE or 0/1 entries, or a matrix with starting values and higher integer codes for equality constraints.

beta

Structural (regression) matrix among latent variables. Defaults to "zero".

latent

Parameterization of the latent covariance structure. One of "cov", "chol", "prec", or "ggm".

sigma_zeta

Latent covariance matrix specification (used when latent = "cov").

kappa_zeta

Latent precision matrix specification (used when latent = "prec").

omega_zeta

Latent partial correlation matrix specification (used when latent = "ggm").

lowertri_zeta

Latent Cholesky factor specification (used when latent = "chol").

delta_zeta

Latent scaling matrix specification (used when latent = "ggm").

residual

Parameterization of the residual covariance structure. One of "cov", "chol", "prec", or "ggm".

sigma_epsilon

Residual covariance matrix specification (used when residual = "cov"). Defaults to "diag". Diagonal elements are always fixed (derived from the correlation constraint).

kappa_epsilon

Residual precision matrix specification (used when residual = "prec").

omega_epsilon

Residual partial correlation matrix specification (used when residual = "ggm").

lowertri_epsilon

Residual Cholesky factor specification (used when residual = "chol").

delta_epsilon

Residual scaling matrix specification (used when residual = "ggm").

identify

Logical, should the model be identified? Defaults to TRUE.

identification

How to identify the model. "loadings" or "variance".

randomEffects

Parameterization of the random effects covariance structure.

sigma_randomEffects

Random effects covariance matrix specification (used when randomEffects = "cov").

kappa_randomEffects

Random effects precision matrix specification (used when randomEffects = "prec").

omega_randomEffects

Random effects partial correlation matrix specification (used when randomEffects = "ggm").

lowertri_randomEffects

Random effects Cholesky factor specification (used when randomEffects = "chol").

delta_randomEffects

Random effects scaling matrix specification (used when randomEffects = "ggm").

rho_randomEffects

Random effects correlation matrix specification (used when randomEffects = "cor").

SD_randomEffects

Random effects standard deviation matrix specification (used when randomEffects = "cor").

vars

Character vector of observed variable names. If missing, names are taken from the correlation matrices.

latents

Character vector of latent variable names.

baseline_saturated

Logical indicating if baseline and saturated models should be included.

optimizer

The optimizer to be used. Defaults to "nlminb".

estimator

The estimator to be used. "ML" or "FIML" (default).

sampleStats

Optional sample statistics object.

verbose

Logical, should progress be printed?

bootstrap

Should the data be bootstrapped?

boot_sub

Proportion of cases to subsample for bootstrap.

boot_resample

Logical, should bootstrap be with replacement?

Details

This function implements a single-stage meta-analytic latent variable model. The model specifies that the mean of the vectorized correlation matrices follows an LVM-implied correlation structure:

μ=vechs(Λ(IB)1Σζ(IB)Λ+Σε)\mu = \textrm{vechs}(\Lambda (I-B)^{-1} \Sigma_\zeta (I-B)^{-\top} \Lambda' + \Sigma_\varepsilon)

where diagonal elements of Σε\Sigma_\varepsilon are derived from the constraint that μ\mu represents correlations (diagonal of implied covariance = 1).

Between-study heterogeneity is modeled as:

Σ=Σ(ran)+V\Sigma = \Sigma^{(\textrm{ran})} + V

where VV is the known sampling error covariance and Σ(ran)\Sigma^{(\textrm{ran})} captures true between-study variation.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp <[email protected]>

References

Epskamp, S., Isvoranu, A. M., & Cheung, M. W. L. (2022). Meta-Analytic Gaussian Network Aggregation. Psychometrika, 87(1), 12-46.

Jak, S., and Cheung, M. W. L. (2019). Meta-analytic structural equation modeling with moderating effects on SEM parameters. Psychological Methods.

See Also

meta_varcov, lvm

Examples

## Not run: 
library("dplyr")

# Generate simulated data
set.seed(42)
nStudies <- 10
nvar <- 6
nlat <- 2

# True factor loading matrix
lambda_true <- matrix(0, nvar, nlat)
lambda_true[1:3, 1] <- c(0.7, 0.8, 0.6)
lambda_true[4:6, 2] <- c(0.7, 0.8, 0.6)

# Generate correlation matrices per study
cors <- list()
nobs <- sample(100:400, nStudies)
for (i in 1:nStudies) {
  sigma <- lambda_true %*% t(lambda_true) + diag(1 - rowSums(lambda_true^2))
  dat <- MASS::mvrnorm(nobs[i], rep(0, nvar), sigma)
  cors[[i]] <- cor(dat)
  colnames(cors[[i]]) <- rownames(cors[[i]]) <- paste0("V", 1:nvar)
}

# Fit meta-analytic CFA
mod <- meta_lvm(covs = cors, nobs = nobs, lambda = lambda_true != 0)
mod <- mod %>% runmodel

# Inspect results
print(mod)
parameters(mod)
getmatrix(mod, "lambda")

## End(Not run)

Meta-analytic VAR(1) model

Description

Single-stage meta-analytic vector autoregressive model (VAR(1)) for time-series data collected across multiple studies. Pools temporal (lag-1) and contemporaneous network structures across studies using a random-effects framework. The meta_gvar wrapper sets contemporaneous = "ggm" for graphical VAR estimation.

Usage

meta_var1(data, covs, nobs,
          vars, studyvar, idvar, dayvar, beepvar,
          contemporaneous = c("cov", "chol", "prec", "ggm"),
          beta = "full",
          omega_zeta = "full", delta_zeta = "full",
          kappa_zeta = "full", sigma_zeta = "full",
          lowertri_zeta = "full",
          randomEffects = c("chol", "cov", "prec", "ggm", "cor"),
          sigma_randomEffects = "full",
          kappa_randomEffects = "full",
          omega_randomEffects = "full",
          lowertri_randomEffects = "full",
          delta_randomEffects = "full",
          rho_randomEffects = "full",
          SD_randomEffects = "full",
          Vmats,
          Vmethod = c("individual", "pooled"),
          Vestimation = c("averaged", "per_study"),
          baseline_saturated = TRUE, optimizer,
          estimator = c("FIML", "ML"),
          sampleStats, verbose = FALSE,
          bootstrap = FALSE, boot_sub, boot_resample)

meta_gvar(...)

Arguments

data

A data frame containing time-series data for multiple studies. Use together with studyvar to identify studies.

covs

A list of pre-computed Toeplitz covariance matrices (one per study). Each matrix should have dimension 2p x 2p where p is the number of variables, with the first p rows/columns being lagged variables and the second p being current variables. Alternative to data.

nobs

A vector with the number of observations per study. Required when covs is supplied.

vars

Character vector of observed variable names. If missing, inferred from data.

studyvar

A string indicating the column name in data that identifies the study. Required when data is supplied. If not supplied but idvar is, idvar is used as studyvar with a warning.

idvar

Optional string indicating the subject ID column within each study. When both studyvar and idvar are supplied, data is first split by studyvar, then idvar is used within each study to collate time series (as in var1).

dayvar

Optional string indicating the day variable (passed to tsData per study).

beepvar

Optional string indicating the beep variable within day (passed to tsData per study).

contemporaneous

Parameterization of the contemporaneous (residual innovation) covariance structure. One of "cov", "chol", "prec", or "ggm".

beta

Temporal lag-1 regression matrix specification. Defaults to "full" (all elements free, including diagonal autoregressive effects).

omega_zeta

Contemporaneous partial correlation matrix specification (used when contemporaneous = "ggm").

delta_zeta

Contemporaneous scaling matrix specification (used when contemporaneous = "ggm").

kappa_zeta

Contemporaneous precision matrix specification (used when contemporaneous = "prec").

sigma_zeta

Contemporaneous covariance matrix specification (used when contemporaneous = "cov").

lowertri_zeta

Contemporaneous Cholesky factor specification (used when contemporaneous = "chol").

randomEffects

Parameterization of the random effects covariance structure.

sigma_randomEffects

Random effects covariance matrix specification (used when randomEffects = "cov").

kappa_randomEffects

Random effects precision matrix specification (used when randomEffects = "prec").

omega_randomEffects

Random effects partial correlation matrix specification (used when randomEffects = "ggm").

lowertri_randomEffects

Random effects Cholesky factor specification (used when randomEffects = "chol").

delta_randomEffects

Random effects scaling matrix specification (used when randomEffects = "ggm").

rho_randomEffects

Random effects correlation matrix specification (used when randomEffects = "cor").

SD_randomEffects

Random effects standard deviation matrix specification (used when randomEffects = "cor").

Vmats

Optional list with 'V' matrices (sampling error variance approximations).

Vmethod

Which method should be used to approximate the sampling error variance? "individual" or "pooled".

Vestimation

How should the sampling error estimates be evaluated? "averaged" or "per_study".

baseline_saturated

Logical indicating if baseline and saturated models should be included.

optimizer

The optimizer to be used. Defaults to "nlminb".

estimator

The estimator to be used. "ML" or "FIML" (default).

sampleStats

Optional sample statistics object.

verbose

Logical, should progress be printed?

bootstrap

Should the data be bootstrapped?

boot_sub

Proportion of cases to subsample for bootstrap.

boot_resample

Logical, should bootstrap be with replacement?

...

Arguments sent to meta_var1.

Details

This function implements a single-stage meta-analytic VAR(1) model. For p observed variables, each study's time-series data is transformed into a Toeplitz covariance structure from which two blocks are extracted:

  • Sigma_0: the p x p stationary covariance (symmetric, p(p+1)/2 unique elements)

  • Sigma_1: the p x p lag-1 cross-covariance (non-symmetric, p^2 elements)

The VAR(1) structural model implies:

vec(Σ0)=(Iββ)1vec(Σζ)\textrm{vec}(\Sigma_0) = (I - \beta \otimes \beta)^{-1} \textrm{vec}(\Sigma_\zeta)

Σ1=βΣ0\Sigma_1 = \beta \Sigma_0

The meta-level mean is μ=[vech(Σ0),vec(Σ1)]\mu = [\textrm{vech}(\Sigma_0), \textrm{vec}(\Sigma_1)] and heterogeneity is modeled as Σ=Σ(ran)+V\Sigma = \Sigma^{(\textrm{ran})} + V.

Note: the exogenous (lagged) covariance block from the full Toeplitz matrix is not modeled, as it is a nuisance parameter at the meta-analytic level.

Sample size convention. When raw data is supplied, the per-study sample size used in the sampling-error approximation (the 'V' matrices) is the number of rows of the lag-augmented data set, including rows in which the lagged block is missing (e.g., the first measurement of each day or subject). The covariances themselves are computed using pairwise-complete observations. For studies consisting of many short segments (e.g., few beeps per day), this convention slightly overstates the effective number of (current, lagged) pairs for the lagged-covariance elements, and hence slightly understates their sampling variance. When this is a concern, the 'V' matrices can be supplied manually via Vmats.

Fit indices. The saturated meta-analytic model (fully free Σ0\Sigma_0, Σ1\Sigma_1 and random effects) has zero degrees of freedom, in which case chi-square based fit indices are not informative and are left blank.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp <[email protected]>

See Also

var1, meta_varcov, meta_lvm

Examples

## Not run: 
library("dplyr")
set.seed(42)

# Simulate stationary VAR(1) time-series data for several subjects/studies
# directly in base R (no extra packages needed):
nNode  <- 3
nTime  <- 50
nStudy <- 20

# Fixed lag-1 (temporal) coefficient matrix:
beta <- matrix(c( 0.4,  0.1,  0.0,
                  0.0,  0.4,  0.1,
                  0.1,  0.0,  0.4), nNode, nNode, byrow = TRUE)

# Innovation (contemporaneous) covariance:
Sigma <- diag(nNode)

varNames <- paste0("V", 1:nNode)

simVAR1 <- function(id, nTime, beta, Sigma){
  p <- nrow(beta)
  L <- chol(Sigma)
  Y <- matrix(0, nTime, p)
  for (t in 2:nTime){
    Y[t, ] <- beta %*% Y[t - 1, ] + as.vector(t(L) %*% rnorm(p))
  }
  out <- as.data.frame(Y)
  names(out) <- paste0("V", 1:p)
  out$study <- id
  out
}

Data <- do.call(rbind, lapply(seq_len(nStudy), simVAR1,
                              nTime = nTime, beta = beta, Sigma = Sigma))

# Fit meta-analytic VAR(1):
mod <- meta_var1(Data,
                 vars = varNames,
                 studyvar = "study",
                 estimator = "ML")
mod <- mod %>% runmodel

# Inspect results:
print(mod)
getmatrix(mod, "beta")

# Fit meta-analytic GVAR (with GGM contemporaneous):
mod_gvar <- meta_gvar(Data,
                      vars = varNames,
                      studyvar = "study",
                      estimator = "ML")
mod_gvar <- mod_gvar %>% runmodel
getmatrix(mod_gvar, "omega_zeta")

## End(Not run)

Variance-covariance and GGM meta analysis

Description

Meta analysis of correlation matrices to fit a homogenous correlation matrix or Gaussian graphical model. Based on meta-analytic SEM (Jak and Cheung, 2019).

Usage

meta_varcov(cors, nobs, data, covs, studyvar, groups, groupvar,
                   corinput, Vmats, Vmethod = c("individual", "pooled",
                   "OS_individual", "OS_pooled",
                   "metaSEM_individual", "metaSEM_weighted"), Vestimation
                   = c("averaged", "per_study"), type = c("cor", "ggm"),
                   sigma_y = "full", kappa_y = "full", omega_y = "full",
                   lowertri_y = "full", delta_y = "full", rho_y = "full",
                   SD_y = "full", randomEffects = c("chol", "cov",
                   "prec", "ggm", "cor"), sigma_randomEffects = "full",
                   kappa_randomEffects = "full", omega_randomEffects =
                   "full", lowertri_randomEffects = "full",
                   delta_randomEffects = "full", rho_randomEffects =
                   "full", SD_randomEffects = "full", vars,
                   baseline_saturated = TRUE, optimizer, estimator =
                   c("FIML", "ML"), sampleStats, verbose = FALSE,
                   bootstrap = FALSE, boot_sub, boot_resample)
  
meta_ggm(...)

Arguments

cors

A list of correlation matrices. Must contain rows and columns with NAs for variables not included in a study.

nobs

A vector with the number of observations per study.

data

Optional data frame. When supplied together with studyvar, correlation matrices and sample sizes are computed internally per study. Cannot be used together with cors, covs, or nobs.

covs

A list of covariance matrices. Alternative to cors; when supplied, corinput defaults to FALSE.

studyvar

A string indicating the column name in data that identifies the study. Required when data is supplied.

groups

Deprecated. Use groupvar instead. Multi-group support is not yet included for meta-analytic models.

groupvar

Not yet supported for meta-analytic models. Supplying this argument will produce an error.

corinput

Logical. Defaults to TRUE when cors is used, FALSE when covs is used. Controls whether the input is treated as correlation matrices.

Vmats

Optional list with 'V' matrices (sampling error variance approximations). May not be combined with an explicitly supplied Vmethod (which would otherwise silently be ignored).

Vmethod

Which method should be used to approximate the sampling error variance? One of "individual" (the default; the sampling-error covariance matrix is approximated separately for each study), "pooled" (a single pooled approximation is used for all studies), "OS_individual" or "OS_pooled" (the asymptotic sampling covariance matrix of the sample correlations following Olkin and Siotani, 1976, evaluated per study or at the sample-size-weighted pooled correlation matrix; for covariance input the corresponding Wishart expression is used), "metaSEM_individual", or "metaSEM_weighted". The two metaSEM_* options compute the sampling-error covariances via metaSEM::asyCov and therefore require the Suggests package metaSEM to be installed (per study or using sample-size weighting, respectively). See Details for the difference between the default methods and the OS_* methods.

Vestimation

How should the sampling error estimates be evaluated? Either "averaged" (the default; a single sampling-error covariance matrix is averaged over the studies) or "per_study" (a separate sampling-error covariance matrix is retained for each study).

type

What to model? Currently only "cor" and "ggm" are supported.

sigma_y

Reserved covariance-matrix specification. Not used for the currently supported values of type ("cor" and "ggm"); retained for internal use and forward compatibility.

kappa_y

Reserved precision-matrix specification. Not used for the currently supported values of type ("cor" and "ggm"); retained for internal use and forward compatibility.

omega_y

Only used when type = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_y

Reserved Cholesky-factor specification. Not used for the currently supported values of type ("cor" and "ggm"); retained for internal use and forward compatibility.

delta_y

Only used when type = "ggm". Either "diag" or "zero" (not recommended), or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

rho_y

Only used when type = "cor". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

SD_y

Only used when type = "cor". Either "diag" or "zero", or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

randomEffects

What to model for the random effects?

sigma_randomEffects

Only used when type = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_randomEffects

Only used when randomEffects = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_randomEffects

Only used when randomEffects = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_randomEffects

Only used when randomEffects = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_randomEffects

Only used when randomEffects = "ggm". Either "diag" or "zero", or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

rho_randomEffects

Only used when randomEffects = "cor". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

SD_randomEffects

Only used when randomEffects = "cor". Either "diag" or "zero", or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

vars

Variables to be included.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

estimator

The estimator to be used. Currently implemented are "ML" for maximum likelihood estimation or "FIML" for full-information maximum likelihood estimation.

sampleStats

An optional sample statistics object. Mostly used internally.

verbose

Logical, should progress be printed to the console?

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

...

Arguments sent to meta_varcov

Details

The default sampling-error approximations Vmethod = "individual" and "pooled" invert the Fisher information of a saturated correlation model (with unit diagonal constraint). This is the asymptotic covariance matrix of the maximum-likelihood estimates of a constrained correlation model, which is smaller than the sampling covariance of the raw sample correlations that enter the meta-level data (for a single correlation: (1 - rho^2)^2 / ((1 + rho^2) n) instead of (1 - rho^2)^2 / n). The alternative options Vmethod = "OS_individual" and "OS_pooled" instead use the asymptotic sampling covariance matrix of the sample correlations themselves (Olkin and Siotani, 1976), which matches metaSEM::asyCov and may be preferred when the absolute size of the random-effects (heterogeneity) variances is of interest: with the default methods part of the sampling variability can be absorbed into the random-effects variances, inflating them somewhat. The pooled correlation estimates themselves are typically nearly identical between these choices. The default is kept at "individual" for backward compatibility with published results.

Note that the saturated meta-analytic model (a fully free pooled correlation structure with fully free random effects) has zero degrees of freedom, in which case chi-square based fit indices (e.g., RMSEA, CFI) are not informative and are left blank.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp <[email protected]>

References

Jak, S., and Cheung, M. W. L. (2019). Meta-analytic structural equation modeling with moderating effects on SEM parameters. Psychological methods.

Olkin, I., and Siotani, M. (1976). Asymptotic distribution of functions of a correlation matrix. In S. Ikeda (Ed.), Essays in probability and statistics (pp. 235-251). Shinko Tsusho.

Examples

# Simulate a list of correlation matrices for several studies:
set.seed(123)
nStudy <- 8
nNode  <- 4
trueRho <- diag(nNode)
trueRho[lower.tri(trueRho)] <- trueRho[upper.tri(trueRho)] <- 0.3
nobs <- sample(100:300, nStudy)
cors <- lapply(seq_len(nStudy), function(i){
  X <- MASS::mvrnorm(nobs[i], rep(0, nNode), trueRho)
  R <- cor(X)
  colnames(R) <- rownames(R) <- paste0("V", 1:nNode)
  R
})

# Meta-analytic GGM using the list of correlation matrices and sample sizes:
mod <- meta_varcov(cors = cors, nobs = nobs, type = "ggm")
mod <- runmodel(mod)

# Pooled network:
getmatrix(mod, "omega_y")

Print modification indices

Description

This function prints a list of modification indices (MIs)

Usage

MIs(x, all = FALSE, matrices, type = c("normal", "equal", "free"), top = 10, 
    verbose = TRUE, nonZero = FALSE)

Arguments

x

A psychonetrics model.

all

Logical, should all MIs be printed or only the highest?

matrices

Optional vector of matrices to include in the output.

type

String (or vector of strings) indicating which kind of modification index should be printed. "normal" (the default) is the typical modification index for freeing a single parameter. "free" is the modification index for freeing the parameter in all groups (for multi-group models this is accompanied by a joint multivariate score test table). "equal" is the modification index for freeing the parameter constrained equal across all groups.

top

Number of MIs to include in output if all = FALSE

verbose

Logical, should messages be printed?

nonZero

Logical, should only MIs be printed of non-zero parameters? Useful to explore violations of group equality.

Value

Invisibly returns a relevant subset of the data frame containing all information on the parameters, or a list of such data frames if multiple types of MIs are requested.

Author(s)

Sacha Epskamp

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars, omega = "zero")

# Run model:
mod <- mod %>% runmodel

# Modification indices:
mod %>% MIs

Multi-level latent variable model family

Description

This family is the two-level random intercept variant of the lvm model family. It is mostly a special case of the dlvm1 family, with the addition of structural effects rather than temporal effects in the beta matrix.

Usage

ml_lnm(...)
ml_rnm(...)
ml_lrnm(...)
ml_lvm(data, lambda, clusters, within_latent = c("cov",
                   "chol", "prec", "ggm"), within_residual = c("cov",
                   "chol", "prec", "ggm"), between_latent = c("cov",
                   "chol", "prec", "ggm"), between_residual = c("cov",
                   "chol", "prec", "ggm"), beta_within = "zero",
                   beta_between = "zero", omega_zeta_within = "full",
                   delta_zeta_within = "full", kappa_zeta_within =
                   "full", sigma_zeta_within = "full",
                   lowertri_zeta_within = "full", omega_epsilon_within =
                   "zero", delta_epsilon_within = "diag",
                   kappa_epsilon_within = "diag", sigma_epsilon_within =
                   "diag", lowertri_epsilon_within = "diag",
                   omega_zeta_between = "full", delta_zeta_between =
                   "full", kappa_zeta_between = "full",
                   sigma_zeta_between = "full", lowertri_zeta_between =
                   "full", omega_epsilon_between = "zero",
                   delta_epsilon_between = "diag", kappa_epsilon_between
                   = "diag", sigma_epsilon_between = "diag",
                   lowertri_epsilon_between = "diag", nu, nu_eta,
                   identify = TRUE, identification = c("loadings",
                   "variance"), vars, latents, groups, equal = "none",
                   baseline_saturated = TRUE, estimator = c("default",
                   "FIML", "ML"),
                   optimizer, storedata = FALSE, verbose =
                   FALSE, standardize = c("none", "z", "quantile"),
                   sampleStats, bootstrap = FALSE, boot_sub,
                   boot_resample)

Arguments

data

A data frame encoding the data used in the analysis. Must be a raw dataset.

lambda

A model matrix encoding the factor loading structure. Each row indicates an indicator and each column a latent. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix. Could also be the result of simplestructure.

clusters

A string indicating the variable in the dataset that describes group membership.

within_latent

The type of within-person latent contemporaneous model to be used.

within_residual

The type of within-person residual model to be used.

between_latent

The type of between-person latent model to be used.

between_residual

The type of between-person residual model to be used.

beta_within

A model matrix encoding the within-cluster structural. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix. Defaults to "zero".

beta_between

A model matrix encoding the between-cluster structural. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix. Defaults to "zero".

omega_zeta_within

Only used when within_latent = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta_within

Only used when within_latent = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta_within

Only used when within_latent = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_zeta_within

Only used when within_latent = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta_within

Only used when within_latent = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_epsilon_within

Only used when within_residual = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_epsilon_within

Only used when within_residual = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_epsilon_within

Only used when within_residual = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_epsilon_within

Only used when within_residual = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_epsilon_within

Only used when within_residual = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_zeta_between

Only used when between_latent = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta_between

Only used when between_latent = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta_between

Only used when between_latent = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_zeta_between

Only used when between_latent = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta_between

Only used when between_latent = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_epsilon_between

Only used when between_residual = "ggm". Can be "full", "zero", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_epsilon_between

Only used when between_residual = "ggm". Can be "diag", "zero" (not recommended), or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_epsilon_between

Only used when between_residual = "prec". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_epsilon_between

Only used when between_residual = "cov". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_epsilon_between

Only used when between_residual = "chol". Can be "full", "diag", or a typical model matrix with 0s indicating parameters constrained to zero, 1s indicating free parameters, and higher integers indicating equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

nu

Optional vector encoding the intercepts of the observed variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

nu_eta

Optional vector encoding the intercepts of the latent variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

identify

Logical, should the model be automatically identified?

identification

Type of identification used. "loadings" to fix the first factor loadings to 1, and "variance" to fix the diagonal of the latent variable model matrix (sigma_zeta, lowertri_zeta, delta_zeta or kappa_zeta) to 1.

vars

An optional character vector with names of the variables used.

latents

An optional character vector with names of the latent variables.

groups

An optional string indicating the name of the group variable in data.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. "ML" and "FIML" maximize the same (exact) two-level maximum-likelihood objective and converge to the same solution; they differ only in how that likelihood is computed, exactly as for the single-level model families in this package, where "ML" fits the model to summary statistics and "FIML" fits it row by row to the raw data. "ML" (experimental) evaluates the likelihood from two-level sufficient statistics (pooled within-cluster covariance and per-cluster-size between moments; McDonald & Goldstein, 1989), which for complete data is much faster and does not slow down as clusters grow. "FIML" (wide-format full-information maximum likelihood) stacks each cluster's members into one wide observation; it was the only estimator before version 0.15.31. Both handle within-cluster missing data ("ML" through a per-pattern, per-cluster likelihood; see Details). This is NOT the approximate "MUML" / pseudo-balanced estimator: the sufficient-statistics evaluation is exact for unbalanced designs, and the two estimators' fit-function values coincide to numerical precision (verified to ~1e-13). "default" selects "ML" when the data are complete and the largest cluster contains more than 5 units, and "FIML" otherwise; with missing data the default stays on the long-standing "FIML" path, so the (R-only) missing-data "ML" estimator is used only when estimator = "ML" is requested explicitly.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

verbose

Logical, should progress be printed to the console?

standardize

Which standardization method should be used? "none" (default) for no standardization, "z" for z-scores, and "quantile" for a non-parametric transformation to the quantiles of the marginal standard normal distribution.

sampleStats

An optional sample statistics object. Mostly used internally.

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

...

Arguments sent to 'ml_lvm'

Details

The "ML" and "FIML" estimators are two computational routes to the same exact two-level maximum-likelihood estimate, not two different statistical methods and not an exact-versus-approximate pair: they maximize the same log-likelihood and (up to optimizer tolerance) return identical estimates, standard errors and fit. The naming follows the convention used throughout psychonetrics – "ML" fits to summary statistics while "FIML" fits row by row to the raw data – and does not by itself indicate complete versus missing data, since both routes can accommodate within-cluster missingness. Choose "ML" for speed on (near-)complete data with non-trivial cluster sizes and "FIML" (or "default") otherwise.

With estimator = "FIML", every cluster is treated as one wide-format observation (members stacked side by side) and the model is estimated with full-information maximum likelihood over the missingness patterns. This handles missing data, but its cost grows quickly with the cluster size.

With estimator = "ML" (experimental), the same two-level random-intercept likelihood is instead evaluated from sufficient statistics (McDonald & Goldstein, 1989; Muthen, 1990) when the data are complete. Writing ΣW\Sigma_W and ΣB\Sigma_B for the implied within- and between-cluster covariance matrices and μ\mu for the implied mean vector, minus twice the log-likelihood equals

(NJ)[lnΣW+tr(ΣW1SPW)]+sms[lnΣs+nstr(Σs1As)]+Npln(2π),(N - J)\left[\ln|\Sigma_W| + \mathrm{tr}(\Sigma_W^{-1} S_{PW})\right] + \sum_s m_s \left[\ln|\Sigma_s| + n_s \mathrm{tr}(\Sigma_s^{-1} A_s)\right] + N p \ln(2\pi),

in which NN is the number of units, JJ the number of clusters, SPWS_{PW} the pooled within-cluster covariance matrix, and, per distinct cluster size nsn_s with msm_s clusters, Σs=ΣW+nsΣB\Sigma_s = \Sigma_W + n_s \Sigma_B and AsA_s the second-moment matrix of the corresponding cluster means around μ\mu. The two estimators optimize numerically identical objectives (the fit function values coincide at identical parameter values), so they converge to the same solution; the same likelihood is also used by lavaan for two-level models (Rosseel, 2012). The sufficient statistics are computed once, making "ML" much faster than "FIML" when clusters are large, and its cost does not depend on the cluster sizes. For complete data, standard errors and modification indices for "ML" use the analytic EXPECTED Fisher information. Note that lavaan uses the OBSERVED information by default for multilevel models, so standard errors reported by lavaan typically differ by a few percent; with lavaan::sem(..., information = "expected") the standard errors agree.

When the data contain within-cluster missing values (assumed missing at random), estimator = "ML" switches to a per-pattern, per-cluster evaluation of the same two-level likelihood: for each missingness pattern the within-cluster precision and log-determinant are obtained by a symmetric (Schur) inverse update of ΣW1\Sigma_W^{-1}, and these are accumulated per cluster into the quantities entering minus twice the log-likelihood,

PfPlnΣW(P)+jlnI+ΣBAj+i(yiμ)ΣW(Pi)1(yiμ)jpj(I+ΣBAj)1ΣBpj+nobsln(2π),\sum_P f_P \ln|\Sigma_W^{(P)}| + \sum_j \ln|I + \Sigma_B A_j| + \sum_i (y_i - \mu)'\Sigma_W^{(P_i)-1}(y_i - \mu) - \sum_j p_j'(I + \Sigma_B A_j)^{-1}\Sigma_B\, p_j + n_{\mathrm{obs}} \ln(2\pi),

with Aj=ijΣW(Pi)1A_j = \sum_{i \in j}\Sigma_W^{(P_i)-1}, pj=ijΣW(Pi)1(yiμ)p_j = \sum_{i \in j}\Sigma_W^{(P_i)-1}(y_i - \mu) (observed coordinates only), fPf_P the number of units in pattern PP, and nobsn_{\mathrm{obs}} the number of observed values. This is the same two-level missing-data likelihood that lavaan::sem(..., cluster = , missing = "ml") maximizes (Rosseel, 2012), and the two agree to optimizer tolerance. The missing-data path is evaluated in R (no C++ acceleration) and reduces exactly to the sufficient-statistics likelihood above when no values are missing; its standard errors use the numeric (observed-information-based) Fisher information.

The saturated (unrestricted) and baseline (independence) reference models used by runmodel for the fit measures are themselves estimated as two-level models: the saturated model freely estimates the means and the full within- and between-cluster covariance matrices, and the baseline model only estimates means and the variances at both levels. These are the same reference models lavaan uses for two-level SEM, so the saturated and baseline log-likelihoods, the model and baseline chi-square, the degrees of freedom, the CFI and the TLI agree with lavaan (up to optimization tolerances), provided the lavaan model uses the same parameterization (ml_lvm shares the factor loadings across the within and between levels, so the matching lavaan model must constrain its level-1 and level-2 loadings to be equal). One convention difference remains: psychonetrics evaluates sample-size-dependent fit measures, such as the RMSEA (with its confidence interval) and the BIC, using the number of independent observations, which in these models is the number of clusters JJ, whereas lavaan uses the total number of level-1 units NN. Because the RMSEA equals max((χ2/n)/df1/n,0)\sqrt{\max((\chi^2/n)/\mathit{df} - 1/n,\, 0)} with nn the number of independent observations, and the chi-square and degrees of freedom otherwise agree, the RMSEA reported by psychonetrics is larger than the value reported by lavaan by exactly a factor N/J\sqrt{N/J}. This applies to both estimators of the ml_lvm family.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp <[email protected]>

References

McDonald, R. P., & Goldstein, H. (1989). Balanced versus unbalanced designs for linear structural relations in two-level data. British Journal of Mathematical and Statistical Psychology, 42(2), 215-232.

Muthen, B. O. (1990). Mean and covariance structure analysis of hierarchical data. UCLA Statistics Series #62.

Rosseel, Y. (2012). lavaan: An R Package for Structural Equation Modeling. Journal of Statistical Software, 48(2), 1-36. doi:10.18637/jss.v048.i02

Examples

# Simulate two-level data with 2 latent variables on both levels:
set.seed(1)
J <- 50 # clusters
nj <- 10 # units per cluster
p <- 6
Lambda <- matrix(0, p, 2)
Lambda[1:3,1] <- c(1, 0.8, 0.7)
Lambda[4:6,2] <- c(1, 0.9, 0.6)
PsiW <- matrix(c(1,0.3,0.3,1), 2)
PsiB <- matrix(c(0.5,0.2,0.2,0.4), 2)
data <- do.call(rbind, lapply(seq_len(J), function(j){
  bj <- MASS::mvrnorm(1, rep(0,2), PsiB)
  ej <- rnorm(p, sd = 0.4) # between-level residuals
  t(replicate(nj, as.vector(Lambda %*% (bj + MASS::mvrnorm(1, rep(0,2), PsiW))) +
      ej + rnorm(p, sd = 0.7)))
}))
data <- as.data.frame(data)
names(data) <- paste0("y", 1:p)
data$cluster <- rep(seq_len(J), each = nj)

# Lambda model matrix (shared across levels):
lambda <- matrix(0, p, 2)
lambda[1:3,1] <- lambda[4:6,2] <- 1

# Two-level ML estimator (fast, complete data):
mod <- ml_lvm(data, lambda = lambda, clusters = "cluster", estimator = "ML")
mod <- runmodel(mod)
mod

# The FIML estimator (slower; supports missing data) converges to the
# same solution:
mod_fiml <- ml_lvm(data, lambda = lambda, clusters = "cluster",
                   estimator = "FIML")
mod_fiml <- runmodel(mod_fiml)

Multi-level Lag-1 dynamic latent variable model family of psychonetrics models for time-series data

Description

Deprecated. Use dlvm1 directly with long-format data instead (set vars to a character vector and provide idvar).

This function is a deprecated wrapper around dlvm1 that allows for specifying the model using a long format data and similar input as the mlVAR package. The ml_ts_lvgvar simply sets within_latent = "ggm" and between_latent = "ggm" by default. The ml_gvar and ml_var are simple wrappers with different named defaults for contemporaneous and between-person effects. All these functions now call dlvm1() directly and emit deprecation warnings.

Usage

ml_tsdlvm1(data, beepvar, idvar, vars, groups, estimator = "FIML", 
  standardize = c("none", "z", "quantile"), ...)

ml_ts_lvgvar(...)

ml_gvar(..., contemporaneous = c("ggm", "cov", "chol", "prec"), 
        between = c("ggm", "cov", "chol", "prec"))
             
ml_var(..., contemporaneous = c("cov", "chol", "prec", "ggm"), 
        between = c("cov", "chol", "prec", "ggm"))

Arguments

data

The data to be used. Must be raw data in long format (each row indicates one person at one time point).

beepvar

Optional string indicating assessment beep per day. Adding this argument will cause non-consecutive beeps to be treated as missing!

idvar

String indicating the subject ID

vars

Vectors of variables to include in the analysis

groups

An optional string indicating the name of the group variable in data.

estimator

Estimator to be used. Must be "FIML".

standardize

Which standardization method should be used? "none" (default) for no standardization, "z" for z-scores, and "quantile" for a non-parametric transformation to the quantiles of the marginal standard normal distribution.

contemporaneous

The type of within-person latent contemporaneous model to be used.

between

The type of between-person latent model to be used.

...

Arguments sent to dlvm1

Value

An object of the class psychonetrics (psychonetrics-class).

Author(s)

Sacha Epskamp <[email protected]>


Stepwise model search

Description

This function performs stepwise model search to find an optimal model that (locally) minimizes some criterion (by default, the BIC).

Usage

modelsearch(x, criterion = "bic", matrices, prunealpha = 0.01,
                    addalpha = 0.01, verbose, ...)

Arguments

x

A psychonetrics model.

criterion

String indicating the criterion to minimize. Any criterion from fit can be used.

matrices

Vector of strings indicating which matrices should be searched. Will default to network structures and factor loadings.

prunealpha

Minimal alpha used to consider edges to be removed

addalpha

Maximum alpha used to consider edges to be added

verbose

Logical, should messages be printed?

...

Arguments sent to runmodel

Details

The full algorithm is as follows:

1. Evaluate all models in which an edge is removed that has p > prunealpha, or an edge is added that has a modification index with p < addalpha

2. If none of these models improve the criterion, return the previous model and stop the algorithm

3. Update the model to the model that improved the criterion the most

4. Evaluate all other considered models that improved the criterion

5. If none of these models improve the criterion, go to 1, else go to 3

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

See Also

prune, stepup

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars)

# Run model:
mod <- mod %>% runmodel

# Model search
mod <- mod %>% prune(alpha= 0.01) %>% modelsearch

Network Analysis 2020 Self-Report Data

Description

A subset of self-report data collected in 2020 by Adela-Maria Isvoranu as part of a graduate-level course on network analysis at the University of Amsterdam. Students in the course collected the data from a convenience sample. The full dataset contains responses to 87 items covering topics such as sleep, well-being, and social functioning. This subset contains 8 items used in Chapter 6 of the textbook Network Psychometrics with R (Epskamp, Isvoranu, & Haslbeck, 2022) to demonstrate Gaussian Graphical Model estimation with psychonetrics. All items are rated on a 1–7 Likert scale. The dataset contains some missing values, making it suitable for demonstrating FIML estimation.

Usage

data("NA2020")

Format

A data frame with 501 observations on 8 variables.

regular_sleep

I try to keep a regular sleep pattern (Q10)

worried_sleep

I am worried about my current sleeping behavior (Q13)

sleep_interfere

My sleep interferes with my daily functioning (Q14)

happy_health

I am happy with my physical health (Q68)

optimistic_future

I feel optimistic about the future (Q70)

very_happy

I am very happy (Q75)

feel_alone

I often feel alone (Q77)

happy_love_life

I am happy with my love life (Q80)

Source

The full dataset is available at https://osf.io/45n6d/. Data collected by Adela-Maria Isvoranu as part of a graduate course on network analysis at the University of Amsterdam (2020).

References

Epskamp, S., Haslbeck, J. M. B., Isvoranu, A. M., & Van Borkulo, C. D. (2022). Pairwise Markov random fields. In A. M. Isvoranu, S. Epskamp, L. J. Waldorp, & D. Borsboom (Eds.), Network psychometrics with R: A guide for behavioral and social scientists (pp. 95–118). Routledge.

Examples

data(NA2020)


# Estimate a GGM using FIML (as in Chapter 6):
library(dplyr)
mod <- ggm(NA2020, estimator = "FIML") %>% runmodel

# Prune non-significant edges:
mod_pruned <- mod %>% prune(alpha = 0.05)

# Inspect parameters:
mod_pruned %>% parameters

Print parameter estimates

Description

This function will print a list of parameters of the model

Usage

parameters(x, standardized = FALSE)

Arguments

x

A psychonetrics model.

standardized

Logical. If TRUE, the completely standardized (std.all) solution is computed and two extra columns are added next to the unstandardized estimate: std (the standardized point estimate) and se_std (its standard error, obtained by the delta method). Standardization rescales every variable to unit variance using the model-implied standard deviations, so that loadings, regression coefficients and (co)variances are expressed on a standardized scale (covariances become correlations; residual/disturbance variances become proportions of variance; residual/disturbance covariances become residual correlations), matching lavaan::standardizedSolution(type = "std.all") (Rosseel, 2012). Currently implemented for the lvm and varcov model families only; for all other families the std/se_std columns are returned as NA (with a warning). Default FALSE (unstandardized estimates only, exactly as before).

Details

The standardized standard errors are obtained post-fit by differentiating the standardization map with respect to the free parameters (numDeriv::jacobian) and applying the delta method to the parameter covariance matrix; a fixed parameter (e.g. a marker loading) has se_std = NA because it has no sampling variance.

Value

Invisibly returns a data frame containing information on all parameters (including the std and se_std columns when standardized = TRUE).

Author(s)

Sacha Epskamp

References

Rosseel, Y. (2012). lavaan: An R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. doi:10.18637/jss.v048.i02

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars, omega = "zero")

# Run model:
mod <- mod %>% runmodel

# Parameter estimates:
mod %>% parameters

# Standardized (std.all) solution with standard errors:
mod %>% parameters(standardized = TRUE)

Set equality constraints across parameters

Description

This function can be used to set parameters equal

Usage

parequal(x, ..., inds = integer(0), verbose, log = TRUE,
                    runmodel = FALSE)

Arguments

x

A psychonetrics model.

...

Vectors of parameter numbers to constrain equal (combined with inds)

inds

Parameter indices of parameters to be constrained equal

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

runmodel

Logical, should the model be updated?

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Partial pruning of multi-group models

Description

This function will search for a multi-group model with equality constraints on some but not all parameters. This is called partial pruning (Epskamp, Isvoranu, & Cheung, 2020; Haslbeck, 2020). The algorithm is as follows: 1. remove all parameters not significant at alpha in all groups (without equality constraints), 2. create a union model with all parameters included in any group included in all groups and constrained equal. 3. Stepwise free equality constraints of the parameter that features the largest sum of modification indices until BIC can no longer be improved. 4. Select and return (by default) the best model according to BIC (original model, pruned model, union model and partially pruned model).

Usage

partialprune(x, alpha = 0.01, matrices, verbose,
             combinefun = c("unionmodel", "intersectionmodel", "identity"),
             return = c("partialprune","best","union_equal","prune"),
             criterion = "bic",  best = c("lowest","highest"),
             final_prune = c("saturated","partialprune"),
             useMIs = c("joint","simple"),
             release_model = c("pruned","saturated"),
             identify = TRUE, ...)

Arguments

x

A psychonetrics model.

alpha

Significance level to use.

matrices

Vector of strings indicating which matrices should be pruned. Will default to network structures.

verbose

Logical, should messages be printed?

combinefun

Function used to combine models of different groups.

return

What model to return? "best" for best fitting model (according to BIC), "partialprune" for the partialpruned model, "union_equal" for the union model with equality constraints, and "prune" for the originally pruned model without equality constraints.

best

Should the lowest or the highest index of criterion be used to select the final model?

criterion

What criterion to use for the model selection in the last step? Defaults to "bic" for BIC selection.

final_prune

Should the last prune step be based on removing edges not significant in the last model in the partialprune algorithm or the first model (saturated model) in the algorithm? Defaults to "saturated". Set to "partialprune" to mimic psychonetrics < 0.13.1 behavior.

useMIs

How to rank candidate equality constraints in the stepwise release loop. The default "joint" (introduced in 0.15.4) uses the joint multivariate score / Lagrange-multiplier test (one statistic per equality-constrained parameter, df = G - 1; see equalityScoreTest). The legacy "simple" option sums the per-group univariate modification indices instead, which reproduces the behavior of psychonetrics <= 0.15.3. For two-group models the two options are equivalent; they differ for G >= 3.

release_model

Specifies the alternative model used in the BIC comparison when deciding whether to release an equality constraint in the stepwise loop. With the default "pruned" (new in 0.15.5), the just-released parameter is immediately fixed to zero in any group where the initial per-group prune (Step 1) had already removed it, BEFORE refitting and comparing BIC. The equality-constrained model is therefore tested against the asymmetric structure suggested by the initial per-group prune, rather than against a fully saturated per-group alternative. This improves specificity at low sample sizes by penalizing the alternative less heavily for spurious cross-group differences. Set to "saturated" to reproduce the psychonetrics 0.15.4 behavior in which the released parameter is freed in all groups with no per-group zero pattern applied until the final prune step.

identify

Logical, passed to the internal prune, unionmodel, intersectionmodel, groupequal, and groupfree calls. When FALSE, identify is not invoked on the intermediate models, so user-fixed parameters (e.g. fixpar("beta", 1, 1, value = 1) in a multi-group Ising model) are not re-freed when equality constraints are introduced on matrices. Defaults to TRUE, which preserves the historical behavior.

...

Arguments sent to prune.

Value

An object of the class psychonetrics (psychonetrics-class); which model is returned is controlled by the return argument (by default the model selected via the chosen criterion).

Author(s)

Sacha Epskamp <[email protected]>

References

Epskamp, S., Isvoranu, A. M., & Cheung, M. (2020). Meta-analytic gaussian network aggregation. PsyArXiv preprint. DOI:10.31234/osf.io/236w8.

Haslbeck, J. (2020). Estimating Group Differences in Network Models using Moderation Analysis. PsyArXiv preprint. DOI:10.31234/osf.io/926pv.

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the extroversion items, and gender:
ExData <- bfi %>%
  select(E1:E5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ExData)[1:5]

# Saturated estimation:
mod_saturated <- ggm(ExData, 
                     vars = vars,
                     groups = "gender")

# Partial prune model:
mod_partial <- mod_saturated %>%
  partialprune

# Obtain the networks:
getmatrix(mod_partial, "omega")

# Differences:
getmatrix(mod_partial, "omega")[[1]] -
  getmatrix(mod_partial, "omega")[[2]]

# Difference detected in edge 4 - 5

Penalized Maximum Likelihood Functions

Description

Functions for penalized maximum likelihood (PML) and penalized full-information maximum likelihood (PFIML) estimation. penalize adds an L1 (LASSO) or elastic net penalty to specified model parameters. unpenalize removes the penalty. penaltyVector extracts the per-free-parameter penalty strengths. refit performs post-selection inference by fixing penalized zeros and re-running with standard ML (or FIML for PFIML) estimation to obtain standard errors.

Usage

penalize(x, matrix, row, col, lambda, group,
         what = c("free", "fixed"), verbose, log = TRUE)
unpenalize(x, matrix, row, col, group, verbose, log = TRUE)
penaltyVector(x)
refit(x, threshold = 1e-8, verbose, log = TRUE, ...)

Arguments

x

A psychonetrics model.

matrix

Character vector of matrix name(s) to penalize/unpenalize. If missing, defaults to the matrices returned by defaultPenalizeMatrices(x) for penalize, or all currently penalized matrices for unpenalize.

row

Integer or character indicating specific row(s) of the matrix. If missing, the entire matrix is penalized/unpenalized.

col

Integer or character indicating specific column(s) of the matrix. If missing, the entire matrix is penalized/unpenalized.

lambda

The penalty strength. Can be a scalar (applied to all selected parameters) or a matrix with dimensions matching the model matrix. When a matrix is provided: 0 means do not penalize, NA means auto-select via EBIC, and a positive number means use that fixed penalty strength. If missing, uses the global x@penalty$lambda.

group

Integer indicating specific group(s). If missing, all groups are included.

what

Character, either "free" (default) or "fixed". Controls which parameters are targeted: "free" penalizes parameters that are already free; "fixed" first frees parameters that are currently fixed to zero, then penalizes them (starting value set to 0). Parameters fixed to non-zero values (e.g., marker loadings fixed to 1) are never affected by what = "fixed". When using a matrix lambda, mismatched parameters are silently skipped. When using a scalar lambda with specific row/col, a warning is issued for mismatched parameters.

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

threshold

For refit: threshold below which penalized parameters are considered zero and fixed.

...

Additional arguments passed to runmodel in refit.

Details

Penalized ML estimation uses the "PML" estimator, which wraps the standard ML fit function and gradient with an additional penalty term. For models with missing data, the "PFIML" estimator wraps the FIML fit function and gradient with the same penalty. The ISTA (Iterative Shrinkage-Thresholding Algorithm) proximal gradient optimizer is used automatically for both PML and PFIML models.

For symmetric matrices (e.g., omega), only off-diagonal elements are penalized by default. For non-symmetric matrices (e.g., beta), all elements are penalized.

The what argument is particularly useful for regularized confirmatory factor analysis (CFA). For example, starting from a simple-structure CFA model, what = "fixed" can free and penalize all cross-loadings, allowing LASSO to select which cross-loadings to retain.

The refit function is used for post-selection inference: after a penalized model is estimated, refit fixes parameters that were shrunk to zero and re-estimates the model with standard ML (for PML) or FIML (for PFIML) to obtain valid standard errors and fit indices.

Model constructors (e.g., ggm, lvm, var1) accept penalty_lambda, penalty_alpha, and penalize_matrices arguments for convenient PML/PFIML setup. When missing = "auto" (the default), specifying estimator = "PML" with missing data will automatically switch to "PFIML".

Value

penalize, unpenalize, and refit return an object of class psychonetrics (psychonetrics-class). penaltyVector returns a numeric vector of penalty strengths per free parameter.

Author(s)

Sacha Epskamp

See Also

find_penalized_lambda for automatic lambda selection via EBIC grid search, runmodel for running models (calls find_penalized_lambda automatically when penalty_lambda = NA), ggm and other model constructors for the penalty_lambda, penalty_alpha, and penalize_matrices arguments.

Examples

# Load bfi data from psych package:
library("psychTools")
library("dplyr")
data(bfi)

ConsData <- bfi %>%
  select(A1:A5) %>%
  na.omit

vars <- names(ConsData)

# Penalized GGM estimation with manual lambda:
mod <- ggm(ConsData, vars = vars, estimator = "PML", penalty_lambda = 0.1)
mod <- mod %>% runmodel

# Post-selection refit for standard errors:
mod_refit <- mod %>% refit
mod_refit %>% parameters

# Manual unpenalize: free a specific edge from the penalty:
mod2 <- ggm(ConsData, vars = vars, estimator = "PML", penalty_lambda = 0.1)
mod2 <- unpenalize(mod2, "omega", row = 1, col = 2)
mod2 <- mod2 %>% runmodel

Stepdown model search by pruning non-significant parameters

Description

This function will (recursively) remove parameters that are not significant and refit the model.

Usage

prune(x, alpha = 0.01, adjust = c("none", "holm",
                    "hochberg", "hommel", "bonferroni", "BH", "BY",
                    "fdr"), matrices, runmodel = TRUE, recursive = FALSE,
                    verbose, log = TRUE, identify = TRUE, startreduce = 1,
                    limit = Inf, mode = c("tested","all"), ...)

Arguments

x

A psychonetrics model.

alpha

Significance level to use.

adjust

p-value adjustment method to use. See p.adjust.

matrices

Vector of strings indicating which matrices should be pruned. Will default to network structures.

runmodel

Logical, should the model be evaluated after pruning?

recursive

Logical, should the pruning process be repeated?

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

identify

Logical, should models be identified automatically?

startreduce

A numeric value indicating a factor with which the starting values should be reduced. Can be useful when encountering numeric problems.

limit

The maximum number of parameters to be pruned.

mode

Mode for adjusting for multiple comparisons. Should all parameters be considered as the total number of tests or only the tested parameters (parameters of interest)?

...

Arguments sent to runmodel

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

See Also

stepup

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars, omega = "full")

# Run model:
mod <- mod %>% runmodel

# Prune model:
mod <- mod %>% prune(adjust = "fdr", recursive = FALSE)

Class "psychonetrics_bootstrap"

Description

Class for aggregated bootstrap results.

Objects from the Class

Objects can be created by calls of the form new("psychonetrics_bootstrap", ...).

Slots

model:

Object of class "character" ~~

submodel:

Object of class "character" ~~

parameters:

Object of class "data.frame" ~~

models:

Object of class "list" ~~

matrices:

Object of class "data.frame" ~~

fitmeasures:

Object of class "data.frame" ~~

distribution:

Object of class "character" ~~

verbose:

Object of class "logical" ~~

boot_sub:

Object of class "numeric" ~~

boot_resample:

Object of class "logical" ~~

n_fail:

Object of class "numeric" ~~

n_success:

Object of class "numeric" ~~

types:

Object of class "list" ~~

Methods

show

signature(object = "psychonetrics_bootstrap"): ...

Author(s)

Sacha Epskamp

Examples

showClass("psychonetrics_bootstrap")

Class "psychonetrics_log"

Description

A logbook entry in the psychonetrics logbook

Objects from the Class

Objects can be created by calls of the form new("psychonetrics_log", ...).

Slots

event:

Object of class "character": a description of the logged event.

time:

Object of class "POSIXct": the time at which the event was logged.

sessionInfo:

Object of class "sessionInfo": the R session information at the time of the event.

Methods

show

signature(object = "psychonetrics_log"): ...

Author(s)

Sacha Epskamp

Examples

showClass("psychonetrics_log")

Model updating functions

Description

These functions update a psychonetrics model. Typically they are not required.

Usage

addMIs(x, matrices = "all", type = c("normal", "free",
                    "equal"), verbose, analyticFisher = TRUE)

addSEs(x, verbose, approximate_SEs = FALSE)

addfit(x, verbose)

identify(x)

Arguments

x

A psychonetrics model.

matrices

Optional vector of matrices to include in MIs.

type

String indicating which modification indices should be updated.

verbose

Logical, should messages be printed?

analyticFisher

Logical indicating if an analytic Fisher information matrix should be used.

approximate_SEs

Logical, should standard errors be approximated? If true, an approximate matrix inverse of the Fisher information is used to obtain the standard errors.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Class "psychonetrics"

Description

Main class for psychonetrics results.

Objects from the Class

Objects can be created by calls of the form new("psychonetrics", ...).

Slots

model:

Object of class "character": the model framework (e.g. "varcov", "lvm", "var1").

submodel:

Object of class "character": the submodel/type within the framework (e.g. "ggm").

parameters:

Object of class "data.frame": the parameter table (one row per model parameter, with estimates, standard errors, matrix/row/col indices and parameter numbers).

matrices:

Object of class "data.frame": bookkeeping table of the model matrices and their dimensions.

meanstructure:

Object of class "logical": whether a mean structure is included in the model.

computed:

Object of class "logical": whether the model has been estimated (run).

sample:

Object of class "psychonetrics_samplestats": the sample statistics used in estimation.

modelmatrices:

Object of class "list": the model-implied matrices in list form (per group).

log:

Object of class "psychonetrics_log": the logbook of actions performed on the model.

optim:

Object of class "list": the raw output of the optimizer.

fitmeasures:

Object of class "list": computed fit measures.

baseline_saturated:

Object of class "list": the baseline and saturated models used for fit computation.

equal:

Object of class "character": names of matrices constrained equal across groups (legacy representation; the parameters table is authoritative).

objective:

Object of class "numeric": the value of the fit function at the solution.

information:

Object of class "matrix": the Fisher information matrix.

identification:

Object of class "character": the identification method used (e.g. "loadings" or "variance").

optimizer:

Object of class "character": the optimizer used.

optim.args:

Object of class "list": arguments passed to the optimizer.

estimator:

Object of class "character": the estimator used (e.g. "ML", "FIML").

distribution:

Object of class "character": the assumed distribution (e.g. "Gaussian").

extramatrices:

Object of class "list": additional helper matrices used internally.

rawts:

Object of class "logical": whether raw time-series data are used.

Drawts:

Object of class "list": duplication/derivative matrices for raw time-series estimation.

types:

Object of class "list": the type of each model matrix per group.

cpp:

Object of class "logical": whether the C++ backend is used.

verbose:

Object of class "logical": whether progress messages are printed.

penalty:

Object of class "list": the penalty configuration for penalized (PML/PFIML) estimation, holding the penalty strength (lambda) and elastic-net mixing parameter (alpha).

Methods

resid

signature(object = "psychonetrics"): ...

residuals

signature(object = "psychonetrics"): ...

show

signature(object = "psychonetrics"): ...

Author(s)

Sacha Epskamp

Examples

showClass("psychonetrics")

Random intercept cross-lagged panel models

Description

The ri_clpm function sets up a random intercept cross-lagged panel model (RI-CLPM) as a special case of the latent variable model (lvm) framework. The ri_clpm_stationary function adds stationarity (equality over time) constraints to such a model, and ri_clpm_search runs a sequential search that adds these constraints one at a time, retaining each only if it does not worsen fit.

Usage

ri_clpm(data, vars,
        datatype = c("auto", "wide", "long"),
        idvar, beepvar,
        standardize = c("none", "z", "quantile", "z_per_wave"),
        lambda,
        type = c("cov", "chol", "prec", "ggm"),
        verbose = FALSE, ...)

ri_clpm_stationary(x,
        stationary = c("intercepts", "contemporaneous",
                       "innovation", "temporal"))

ri_clpm_search(x,
        criterion = c("BIC", "AIC", "Chisq"),
        alpha = 0.05,
        include_panelvar = TRUE,
        verbose = TRUE, ...)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied (via ...).

vars

Required argument. For wide-format data (the default), a matrix with each row indicating a variable and each column indicating a measurement (wave); each cell must contain the name of the variable in data corresponding to that variable at that wave. The row names of this matrix are used as variable names. For long-format data, a character vector of variable names (see datatype, idvar and beepvar).

datatype

The data format. "auto" (default) detects "wide" when vars is a matrix and "long" when vars is a character vector.

idvar

Only used for long-format data: the name of the variable encoding the subject/cluster ID.

beepvar

Optional, only used for long-format data: the name of the variable encoding the measurement occasion (wave). If omitted, observations are assumed to be ordered within each subject.

standardize

Standardization to apply to the data before estimation. "none" (default) applies none, "z" standardizes each variable to mean 0 and SD 1 pooling across all waves, "z_per_wave" standardizes each variable separately at each wave, and "quantile" applies a (pooled) nonparametric quantile transformation per variable.

lambda

A model matrix encoding the factor loading structure. Latent variables are not yet supported for the RI-CLPM; supplying lambda currently raises an error. When omitted, an observed-variable model is created.

type

The parameterization used for the latent (innovation and between-person random intercept) covariance structure: "cov" (covariances), "chol" (Cholesky), "prec" (precision), or "ggm" (Gaussian graphical model / partial correlations). Because the latent covariance matrix is block-diagonal over time, this parameterization is applied to both the within-person (innovation) blocks and the between-person (random intercept) block.

verbose

Logical, should progress be printed to the console?

x

A psychonetrics RI-CLPM model (as returned by ri_clpm).

stationary

The part of the model to constrain to be stationary (equal over time): "intercepts" (also frees the random-intercept means), "temporal" (the cross-lagged/autoregressive effects), "contemporaneous" (the innovation covariances/network, waves 2 and later), or "innovation" (the innovation variances, waves 2 and later).

criterion

The criterion used by ri_clpm_search to decide whether to retain each constraint: "BIC" (default) or "AIC" retain the constraint when the criterion does not increase; "Chisq" retains it when the likelihood-ratio test is not significant at level alpha.

alpha

Significance level used when criterion = "Chisq".

include_panelvar

Logical. If TRUE (default) and all stationarity constraints are retained, ri_clpm_search additionally tests the panelVAR model, which treats the first wave as the stationary distribution of the process (wave 1 endogenous).

...

Arguments sent to lvm (for ri_clpm) or to runmodel (for ri_clpm_search).

Details

The RI-CLPM decomposes each observed score into a stable between-person random intercept and a within-person deviation (innovation). The within-person deviations follow a lag-1 (cross-lagged) structure over time. In this implementation the innovations and the random intercepts are modeled as latent variables under the lvm framework, with the latent covariance matrix being block-diagonal over time, so that the within-person (contemporaneous) and between-person covariance structures can each be modeled as a covariance matrix, a Cholesky decomposition, a precision matrix, or a Gaussian graphical model (GGM).

ri_clpm_search formalizes the typical analysis workflow as a sequence akin to measurement-invariance testing. Starting from the unconstrained model it adds, in order, stationarity of intercepts, temporal effects, contemporaneous relations and innovation variances, and finally the panelVAR model. Each more constrained model is compared to the currently selected one and the constraint is kept only if it does not worsen fit according to criterion; the search stops at the first rejection.

Structural missing waves (NA entries in the vars design matrix, i.e. a variable not measured at a particular wave) are not yet supported. Incomplete cases (missing data for some subjects) are handled automatically through full-information maximum likelihood.

Value

ri_clpm and ri_clpm_stationary return a psychonetrics model object. ri_clpm_search returns a list of class "ri_clpm_search" with elements selected (the chosen psychonetrics model), selected_name, models (all fitted models), comparison (a compare table), path (a data frame describing each step and decision), criterion and alpha.

Author(s)

Sacha Epskamp

See Also

lvm, dlvm1, panelvar, panelgvar

Examples

# Simulate a small panel data set (3 variables, 4 waves):
set.seed(1)
nPerson <- 300; nVar <- 3; nWave <- 4

# Between-person random intercepts:
RI <- matrix(rnorm(nPerson * nVar), nPerson, nVar)

# Lag-1 temporal structure:
beta <- diag(0.3, nVar); beta[2, 1] <- 0.2; beta[3, 2] <- 0.2

# Within-person process:
within <- array(0, c(nPerson, nVar, nWave))
within[, , 1] <- matrix(rnorm(nPerson * nVar), nPerson, nVar)
for (w in 2:nWave){
  within[, , w] <- within[, , w - 1] %*% t(beta) +
                   matrix(rnorm(nPerson * nVar, sd = 0.8), nPerson, nVar)
}

# Observed scores = within-person deviation + random intercept:
data <- do.call(cbind, lapply(1:nWave, function(w) within[, , w] + RI))
colnames(data) <- as.vector(outer(paste0("V", 1:nVar), 1:nWave, paste, sep = "_"))
data <- as.data.frame(data)

# Design matrix (rows = variables, columns = waves):
design <- matrix(colnames(data), nVar, nWave)
rownames(design) <- paste0("V", 1:nVar)

# Form the unconstrained RI-CLPM with GGM innovation/between structure:
mod <- ri_clpm(data, design, type = "ggm")


# Run the unconstrained model:
mod <- runmodel(mod)

# Add stationarity constraints step by step:
mod_int  <- runmodel(ri_clpm_stationary(mod,     "intercepts"))
mod_temp <- runmodel(ri_clpm_stationary(mod_int, "temporal"))
compare(base = mod, intercepts = mod_int, temporal = mod_temp)

# Or run the whole sequential search automatically:
res <- ri_clpm_search(mod, criterion = "BIC")
res
res$selected

Run a psychonetrics model

Description

This is the main function used to run a psychonetrics model.

Usage

runmodel(x, level = c("gradient", "fitfunction"), addfit =
                   TRUE, addMIs = TRUE, addSEs = TRUE, addInformation =
                   TRUE, log = TRUE, verbose, optim.control,
                   analyticFisher = TRUE, warn_improper = FALSE,
                   warn_gradient = TRUE, warn_bounds = TRUE,
                   return_improper = TRUE, bounded = TRUE,
                   approximate_SEs = FALSE,
                   criterion = "ebic.5",
                   beta_min = c("numerical", "theoretical"),
                   saturated = c("default", "analytic", "model"))

Arguments

x

A psychonetrics model.

level

Level at which the model should be estimated. Defaults to "gradient" to indicate the analytic gradient should be used.

addfit

Logical, should fit measures be added?

addMIs

Logical, should modification indices be added?

addSEs

Logical, should standard errors be added?

addInformation

Logical, should the Fisher information be added?

log

Logical, should the log be updated?

verbose

Logical, should messages be printed?

optim.control

A list with options for optimr

analyticFisher

Logical, should the analytic Fisher information be used? If FALSE, numeric information is used instead.

return_improper

Should a result in which improper computation was used be return? Improper computation can mean that a pseudoinverse of small spectral shift was used in computing the inverse of a matrix.

warn_improper

Logical. Should a warning be given when at some point in the estimation a pseudoinverse was used?

warn_gradient

Logical. Should a warning be given when the average absolute gradient is > 1?

bounded

Logical. Should bounded estimation be used (e.g., variances should be positive)?

approximate_SEs

Logical, should standard errors be approximated? If true, an approximate matrix inverse of the Fisher information is used to obtain the standard errors.

warn_bounds

Should a warning be given when a parameter is estimated near its bounds?

criterion

Character string specifying the information criterion for automatic lambda selection in PML/PFIML models. One of "bic", "ebic.25", "ebic.5" (default), "ebic.75", or "ebic1". Only used when the model contains auto-select penalty parameters (penalty_lambda = NA). See find_penalized_lambda for details.

beta_min

Threshold for zeroing out small penalized parameters during automatic lambda selection. Can be "numerical" (default; uses 1e-05), "theoretical" (uses sqrt(log(p)/n)), or a numeric value. See find_penalized_lambda for details.

saturated

Method for computing the saturated model log-likelihood. "default" runs the saturated varcov model numerically, with automatic fallback to the analytical formula if the optimizer fails (saturated LL < model LL). "analytic" skips the saturated model optimization and uses the analytical pattern-specific formula directly (fast, useful for high-dimensional panel data where optimization is slow or fails). "model" always runs the saturated varcov model numerically with no fallback.

Details

For penalized models (PML or PFIML) with auto-select penalty parameters (penalty_lambda = NA, the default), runmodel automatically calls find_penalized_lambda to select the optimal penalty strength via EBIC grid search before fitting. The criterion and beta_min arguments control this search. After the lambda search, use refit for post-selection inference with standard errors.

For the robust maximum likelihood estimators ("MLM", "MLMV", "MLMVS", "MLR"; see setestimator), the point estimates are obtained by plain maximum likelihood, while runmodel additionally computes robust (sandwich) standard errors, a scaled test statistic (Satorra-Bentler family or Yuan-Bentler) and robust RMSEA/CFI/TLI. These are stored in the model fit measures (chisq.scaled, chisq.scaling.factor, df.scaled, chisq.shift.parameters, rmsea.robust, cfi.robust, tli.robust). The Satorra-Bentler family ("MLM"/"MLMV"/"MLMVS") requires complete (continuous) raw data. "MLR" additionally supports missing data through full-information maximum likelihood (FIML): when the raw data contain missing values, point estimation uses FIML and the robust standard errors (Huber-White), the Yuan-Bentler-Mplus scaled test statistic and the FIML-corrected robust RMSEA/CFI/TLI are computed under missingness.

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

See Also

find_penalized_lambda for manual control over the lambda search, penalize for setting penalty parameters, refit for post-selection inference after penalized estimation.

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars, omega = "full")

# Run model:
mod <- mod %>% runmodel

Convenience functions

Description

These functions can be used to change some estimator options.

Usage

setestimator(x, estimator)

setoptimizer(x, optimizer = c("default", "nlminb", "ucminf",
                 "nloptr_TNEWTON", "LBFGS++"), optim.args)


usecpp(x, use = TRUE)

Arguments

x

A psychonetrics model.

estimator

A string indicating the estimator to be used. Maximum likelihood ("ML"), full-information maximum likelihood ("FIML"), and the least-squares estimators ("WLS", "DWLS", "ULS"; "WLSMV" is a synonym for "DWLS" with a mean-and-variance adjusted scaled test) are supported. In addition, the following robust maximum likelihood estimators are available for complete continuous data (raw data required). They use plain ML for the point estimates but report robust (sandwich) standard errors, a scaled test statistic and robust RMSEA/CFI/TLI:

"MLM"

Browne (1984) "robust.sem" sandwich standard errors and the Satorra-Bentler (1994) mean-adjusted scaled chi-square.

"MLMV"

Robust.sem standard errors and the scaled-and-shifted chi-square (Satorra 2000; Asparouhov & Muthen 2010).

"MLMVS"

Robust.sem standard errors and the mean-and-variance adjusted (Satterthwaite) scaled chi-square with fractional degrees of freedom.

"MLR"

Huber-White (sandwich) standard errors and the Yuan-Bentler (2000) scaled chi-square (the Mplus variant). Requires the raw data to be stored; the model constructors set storedata = TRUE automatically when estimator = "MLR". "MLR" also supports missing data: when the raw data contain missing values it estimates the point estimates by full-information maximum likelihood (FIML) and computes the Huber-White standard errors, the Yuan-Bentler-Mplus scaled chi-square and the FIML-corrected (Savalei 2010) robust RMSEA/CFI/TLI under missingness.

These robust estimators map internally to estimator = "ML" (or, for "MLR" with missing data, estimator = "FIML") plus robust standard-error and test flags, so the point estimates are identical to plain ML (or FIML). The scaled statistics are stored in the fit measures (chisq.scaled, chisq.scaling.factor, df.scaled, chisq.shift.parameters, rmsea.robust, cfi.robust, tli.robust). The Satorra-Bentler family ("MLM"/"MLMV"/"MLMVS") requires complete data; for missing data use "MLR".

optimizer

The optimizer to be used. The following optimizers are available:

R-based optimizers:

"nlminb"

Port trust-region Newton-like optimizer from base R. Uses analytic gradients and a trust-region method that adaptively controls step sizes, making it very stable for SEM problems. This is the default and recommended optimizer for most models.

"ucminf"

Unconstrained minimization using a quasi-Newton method (via the optimr package). Does not support box constraints. Fast for unconstrained problems.

C++ based optimizer:

"LBFGS++"

L-BFGS-B optimizer from the LBFGSpp library (Yixuan Qiu). This is a pure C++ implementation that computes the objective function and gradient in a single combined call, avoiding redundant computation via internal caching. Supports box constraints. Recommended when speed is important.

NLopt-based optimizer (via nloptr):

"nloptr_TNEWTON"

Preconditioned truncated Newton with restarts from the NLopt library (via the nloptr package). Uses the NLOPT_LD_TNEWTON_PRECOND_RESTART algorithm, which builds a local quadratic model of the objective and solves the Newton system approximately using a preconditioned conjugate-gradient method. Supports box constraints and uses analytic gradients. Can handle large parameter spaces efficiently. See Dembo & Steihaug (1982) for the underlying method.

Defaults to "nlminb".

use

Logical indicating if C++ should be used (currently only used in FIML)

optim.args

List of arguments to sent to the optimizer.

Details

The default optimizer is nlminb with the following arguments:

  • eval.max=20000L

  • iter.max=10000L

  • trace=0L

  • abs.tol=sqrt(.Machine$double.eps)

  • rel.tol=sqrt(.Machine$double.eps)

  • step.min=1.0

  • step.max=1.0

  • x.tol=1.5e-8

  • xf.tol=2.2e-14

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

References

Browne, M. W. (1984). Asymptotically distribution-free methods for the analysis of covariance structures. British Journal of Mathematical and Statistical Psychology, 37(1), 62-83.

Satorra, A., & Bentler, P. M. (1994). Corrections to test statistics and standard errors in covariance structure analysis. In A. von Eye & C. C. Clogg (Eds.), Latent variables analysis: Applications for developmental research (pp. 399-419). Sage.

Yuan, K.-H., & Bentler, P. M. (2000). Three likelihood-based methods for mean and covariance structure analysis with nonnormal missing data. Sociological Methodology, 30(1), 165-200.

Savalei, V. (2010). Expected versus observed information in SEM with incomplete normal and nonnormal data. Psychological Methods, 15(4), 352-367.

Brosseau-Liard, P. E., & Savalei, V. (2014). Adjusting incremental fit indices for nonnormality. Multivariate Behavioral Research, 49(5), 460-470.

Asparouhov, T., & Muthen, B. (2010). Simple second order chi-square correction. Mplus Technical Appendix.

Examples

# Robust maximum likelihood (MLR) on the Holzinger-Swineford data:
library("lavaan")
data("HolzingerSwineford1939")
vars <- paste0("x", 1:9)

# Three-factor CFA loadings matrix:
Lambda <- matrix(0, 9, 3)
Lambda[1:3, 1] <- Lambda[4:6, 2] <- Lambda[7:9, 3] <- 1

# Robust ML (Huber-White SEs + Yuan-Bentler scaled chi-square). The point
# estimates are identical to plain ML; only the SEs, the scaled test and the
# robust fit indices differ:
mod <- lvm(HolzingerSwineford1939, lambda = Lambda, vars = vars,
           identification = "variance", estimator = "MLR")
mod <- runmodel(mod)

# Robust fit measures (chisq.scaled, rmsea.robust, cfi.robust, ...):
fit(mod)

# Equivalent via setestimator() (the model must store the raw data):
mod2 <- lvm(HolzingerSwineford1939, lambda = Lambda, vars = vars,
            identification = "variance", estimator = "ML", storedata = TRUE)
mod2 <- runmodel(setestimator(mod2, "MLM"))

# MLR also handles missing data via FIML. With missing values in the raw data,
# estimator = "MLR" estimates the point estimates by FIML and reports
# Huber-White standard errors, the Yuan-Bentler-Mplus scaled chi-square and the
# FIML-corrected robust RMSEA/CFI/TLI:
HSmis <- HolzingerSwineford1939
set.seed(1)
for (v in vars) HSmis[[v]][runif(nrow(HSmis)) < 0.1] <- NA
modM <- lvm(HSmis, lambda = Lambda, vars = vars,
            identification = "variance", estimator = "MLR")
modM <- runmodel(modM)   # estimator is "FIML" internally, with MLR robust output
fit(modM)

Should messages of computation progress be printed?

Description

This function controls if messages should be printed for a psychonetrics model.

Usage

setverbose(x, verbose = TRUE)

Arguments

x

A psychonetrics model.

verbose

Logical indicating if verbose should be enabled

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Generate factor loadings matrix with simple structure

Description

This function generates the input for lambda arguments in latent variable models using a simple structure. The input is a vector with an element for each variable indicating the factor the variable loads on.

Usage

simplestructure(x)

Arguments

x

A vector indicating which factor each indicator loads on.

Value

A binary lambda (factor loadings) matrix with one row per indicator and one column per factor, with a 1 in each cell where the indicator loads on the factor and 0 otherwise.

Author(s)

Sacha Epskamp <[email protected]>


Star Wars dataset

Description

This questionnaire was constructed by Carolin Katzera, Charlotte Tanis, Esther Niehoff, Myrthe Veenman, and Jason Nak as part of an assignment for a course on confirmatory factor analysis (http://sachaepskamp.com/SEM2018). They also collected the data among fellow psychology students as well as through social media.

Usage

data("StarWars")

Format

A data frame with 271 observations on the following 13 variables.

Q1

I am a huge Star Wars fan! (star what?)

Q2

I would trust this person with my democracy <picture of Jar Jar Binks>

Q3

I enjoyed the story of Anakin's early life

Q4

The special effects in this scene are awful <video of the Battle of Geonosis>

Q5

I would trust this person with my life <picture of Han Solo>

Q6

I found Darth Vader's big reveal in "Empire" one of the greatest moments in movie history

Q7

The special effects in this scene are amazing <video of the Death Star explosion>

Q8

If possible, I would definitely buy this droid <picture of BB-8>

Q9

The story in the Star Wars sequels is an improvement to the previous movies

Q10

The special effects in this scene are marvellous <video of the Starkiller Base firing>

Q11

What is your gender?

Q12

How old are you?

Q13

Have you seen any of the Star Wars movies?

Details

The questionnaire is online at https://github.com/SachaEpskamp/SEM-code-examples/blob/master/CFA_fit_examples/StarWars_questionnaire.pdf. The authors of the questionnaire defined a measurement model before collecting data: Q2 - Q4 are expected to load on a "prequel" factor, Q5 - Q7 are expected to load in a "originals" factor, and Q8 - Q10 are expected to load on a "sequel" factor. Finally, Q1 is expected to load on all three.

Source

https://github.com/SachaEpskamp/SEM-code-examples/blob/master/CFA_fit_examples

Examples

data(StarWars)

Stepup model search along modification indices

Description

This function automatically performs step-up search by adding the parameter with the largest modification index until some criterion is reached or no modification indices are significant at alpha.

Usage

stepup(x, alpha = 0.01, criterion = "bic", matrices, mi =
                    c("mi", "mi_free", "mi_equal"), greedyadjust =
                    c("bonferroni", "none", "holm", "hochberg", "hommel",
                    "fdr", "BH", "BY"), stopif, greedy = FALSE, verbose,
                    checkinformation = TRUE, singularinformation =
                    c("tryfix", "skip", "continue", "stop"), startEPC =
                    TRUE, ...)

Arguments

x

A psychonetrics model.

alpha

Significance level to use.

criterion

String indicating the criterion to minimize. Any criterion from fit can be used.

matrices

Vector of strings indicating which matrices should be searched. Will default to network structures and factor loadings.

mi

String indicating which kind of modification index should be used ("mi" is the typical MI, "mi_free" is the modification index free from equality constraints across groups, and "mi_equal" is the modification index if the parameter is added constrained equal across all groups).

greedyadjust

String indicating which p-value adjustment should be used in greedy start. Any method from p.adjust can be used.

stopif

An R expression, using objects from fit, which will break stepup search if it evaluates to TRUE. For example, stopif = rmsea < 0.05 will lead to search to stop if rmsea is below 0.05.

greedy

Logical, should a greedy start be used? If TRUE, the first step adds any parameter that is significant (after adjustment)

verbose

Logical, should messages be printed?

checkinformation

Logical, should the Fisher information be checked for potentially non-identified models?

singularinformation

String indicating how to proceed if the information matrix is singular. "tryfix" will adjust starting values to try to fix the proble, "skip" will lead to the algorithm to skip the current parameter, "continue" will ignore the situation, and "stop" will break the algorithm and return a list with the last two models.

startEPC

Logical, should the starting value be set at the expected parameter change?

...

Arguments sent to runmodel

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

See Also

prune

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>%
  select(A1:A5, gender) %>%
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Let's fit a full GGM:
mod <- ggm(ConsData, vars = vars, omega = "full")

# Run model:
mod <- mod %>%runmodel %>%prune(alpha = 0.05)

# Remove an edge (example):
mod <- mod %>%fixpar("omega",1,2) %>%runmodel

# Stepup search
mod <- mod %>%stepup(alpha = 0.05)

Convert a psychonetrics lvm to a lavaan model

Description

Converts a psychonetrics latent variable model (lvm) with latent = "cov" and residual = "cov" into a fitted lavaan object, or into a lavaan parameter table. Only the public lavaan API (lavaan::lavaan) is used; no lavaan source code is reused.

Usage

tolavaan(x, fit = TRUE, verbose = FALSE, ...)

Arguments

x

A psychonetrics object created with lvm (or a wrapper such as lnm) using latent = "cov" and residual = "cov".

fit

Logical. If TRUE (default), the model is fitted with lavaan::lavaan and the resulting lavaan object is returned. If FALSE, the lavaan parameter table (a data.frame) is returned without fitting.

verbose

Logical. If TRUE, an experimental-feature note is shown.

...

Further arguments passed to lavaan::lavaan. For example, pass do.fit = FALSE to obtain an unfitted lavaan object that uses the psychonetrics estimates as starting values.

Details

Only models with latent = "cov" and residual = "cov" can be converted, because network (ggm/prec) and Cholesky (chol) parameterizations have no direct lavaan equivalent. The function emits one lavaan parameter-table row for every element of the psychonetrics matrices lambda, sigma_zeta, sigma_epsilon, beta, nu and nu_eta (including elements that are fixed to zero, so that lavaan adds no default parameters). Free parameters are given sequential free indices and fixed parameters their fixed value via ustart. Equality constraints (shared psychonetrics par indices) are encoded with per-row plabels and explicit == rows, which is the only encoding lavaan honors for cross-row equality.

Warm start. When the psychonetrics model has been estimated (x@computed is TRUE), the estimates are also written as starting values (ustart) for the free parameters. lavaan then typically polishes this warm start by a few optimizer steps, so the refitted log-likelihood matches to within optimizer tolerance (about 10510^{-5}) rather than exactly.

Data. If the psychonetrics model stored its raw data (fitted with storedata = TRUE), that raw data is passed to lavaan (with the grouping variable for multi-group models, and missing = "ml" for FIML). Otherwise the sample covariance matrix (and the sample means, when a mean structure is present) is passed with sample.cov.rescale = FALSE and likelihood = "normal", since psychonetrics covariances already use the nn (maximum-likelihood) normalization. FIML conversion therefore requires the raw data: re-fit the lvm with storedata = TRUE first.

Unsupported. The following raise an informative error: non-lvm models, lvm models with latent or residual not equal to "cov", correlation-input or ordinal models, estimators other than "ML" or "FIML", and FIML models fitted without storedata = TRUE.

Value

A fitted lavaan object when fit = TRUE, or a lavaan parameter table (data.frame) when fit = FALSE.

Author(s)

Sacha Epskamp

References

Rosseel, Y. (2012). lavaan: An R Package for Structural Equation Modeling. Journal of Statistical Software, 48(2), 1-36. doi:10.18637/jss.v048.i02

See Also

fromlavaan, lvm

Examples

if (requireNamespace("lavaan", quietly = TRUE)){
  library("lavaan")
  library("dplyr")

  # A psychonetrics CFA:
  data(HolzingerSwineford1939, package = "lavaan")
  HS <- lavaan::HolzingerSwineford1939
  Lambda <- matrix(0, 9, 3)
  Lambda[1:3, 1] <- Lambda[4:6, 2] <- Lambda[7:9, 3] <- 1

  mod <- lvm(HS, lambda = Lambda, latent = "cov", residual = "cov",
             vars = paste0("x", 1:9),
             latents = c("visual", "textual", "speed"),
             identification = "loadings") %>%
    runmodel

  # Convert to a fitted lavaan object:
  lavfit <- tolavaan(mod)
  c(psychonetrics = mod@fitmeasures$logl,
    lavaan = as.numeric(logLik(lavfit)))

  # Or obtain just the parameter table:
  PT <- tolavaan(mod, fit = FALSE)
  head(PT)
}

Transform between model types

Description

This function allows to transform a model variance–covariance structure from one type to another. Its main uses are to (1) use a Cholesky decomposition to estimate a saturated covariance matrix or GGM, and (2) to transform between conditional (ggm) and marginal associations (cov).

Usage

transmod(x, ..., verbose, keep_computed = FALSE, log = TRUE,
         identify = TRUE)

Arguments

x

A psychonetrics model

...

Named arguments with the new types to use (e.g., between = "ggm" or y = "cov")

verbose

Logical, should messages be printed?

keep_computed

Logical: keep the model marked as computed after the transformation? Defaults to FALSE (the model must be re-run, although the transformed estimates are already at the ML solution). Cannot be TRUE with identification = 'variance'.

log

Logical, should a logbook entry be made?

identify

Logical, should the model be identified after transforming?

Details

Transformations are only possible if the model is diagonal (e.g., no partial correlations) or saturated (e.g., all covariances included).

Value

An object of the class psychonetrics (psychonetrics-class) with the requested variance–covariance structure(s).

Author(s)

Sacha Epskamp

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (otherwise use Estimator = "FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Model with Cholesky decompositon:
mod <- varcov(ConsData, vars = vars, type = "chol")

# Run model:
mod <- mod %>% runmodel

# Transform to GGM:
mod_trans <- transmod(mod, type = "ggm") %>% runmodel
# Note: runmodel often not needed

# Obtain thresholded GGM:
getmatrix(mod_trans, "omega", threshold = TRUE)

Lag-1 dynamic latent variable model family of psychonetrics models for time-series data

Description

This is the family of models that models a dynamic factor model on time-series. There are two covariance structures that can be modeled in different ways: contemporaneous for the contemporaneous model and residual for the residual model. These can be set to "cov" for covariances, "prec" for a precision matrix, "ggm" for a Gaussian graphical model and "chol" for a Cholesky decomposition. The ts_lvgvar wrapper function sets contemporaneous = "ggm" for the graphical VAR model.

Usage

tsdlvm1(data, lambda, contemporaneous = c("cov", "chol",
                   "prec", "ggm"), residual = c("cov", "chol", "prec",
                   "ggm"), beta = "full", omega_zeta = "full", delta_zeta
                   = "diag", kappa_zeta = "full", sigma_zeta = "full",
                   lowertri_zeta = "full", omega_epsilon = "zero",
                   delta_epsilon = "diag", kappa_epsilon = "diag",
                   sigma_epsilon = "diag", lowertri_epsilon = "diag", nu,
                   mu_eta, identify = TRUE, identification =
                   c("loadings", "variance"), latents, beepvar, dayvar,
                   idvar, vars, groups, groupvar, covs, cors,
                   means, nobs, corinput, missing =
                   "auto", equal = "none", baseline_saturated = TRUE,
                   estimator = "ML", optimizer, storedata = FALSE,
                   sampleStats, covtype = c("choose", "ML", "UB"),
                   centerWithin = FALSE, standardize = c("none", "z",
                   "quantile"), verbose = FALSE, bootstrap = FALSE,
                   boot_sub, boot_resample, penalty_lambda = NA,
                   penalty_alpha = 1, penalize_matrices)

ts_lvgvar(...)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

lambda

A model matrix encoding the factor loading structure. Each row indicates an indicator and each column a latent. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

contemporaneous

The type of contemporaneous model used. See description.

residual

The type of residual model used. See description.

beta

A model matrix encoding the temporal relationships (transpose of temporal network) between latent variables. A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix. Can also be "full" for a full temporal network or "zero" for an empty temporal network.

omega_zeta

Only used when contemporaneous = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta

Only used when contemporaneous = "ggm". Either "diag" or "zero" (not recommended), or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta

Only used when contemporaneous = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_zeta

Only used when contemporaneous = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta

Only used when contemporaneous = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega_epsilon

Only used when residual = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_epsilon

Only used when residual = "ggm". Either "diag" or "zero" (not recommended), or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_epsilon

Only used when residual = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_epsilon

Only used when residual = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_epsilon

Only used when residual = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

nu

Optional vector encoding the intercepts of the observed variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

mu_eta

Optional vector encoding the means of the latent variables. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free intercepts, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

identify

Logical, should the model be automatically identified?

identification

Type of identification used. "loadings" to fix the first factor loadings to 1, and "variance" to fix the diagonal of the latent variable model matrix (sigma_zeta, lowertri_zeta, delta_zeta or kappa_zeta) to 1.

latents

An optional character vector with names of the latent variables.

beepvar

Optional string indicating assessment beep per day. Adding this argument will cause non-consecutive beeps to be treated as missing!

dayvar

Optional string indicating assessment day. Adding this argument makes sure that the first measurement of a day is not regressed on the last measurement of the previous day. IMPORTANT: only add this if the data has multiple observations per day.

idvar

Optional string indicating the subject ID

vars

An optional character vector encoding the variables used in the analysis. Must equal names of the dataset in data.

groups

Deprecated. Use groupvar instead. An optional string indicating the name of the group variable in data.

groupvar

An optional string indicating the name of the group variable in data. Replaces the deprecated groups argument; if both are supplied, groupvar takes precedence with a warning.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure covtype argument is set correctly to the type of covariances used.

cors

A sample correlation matrix, or a list/array of such matrices for multiple groups. When supplied, the matrix is treated as a covariance matrix with a warning (appropriate for standardized data). Requires nobs. Note: corinput = TRUE is not supported in tsdlvm1.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

corinput

Logical. Not supported in tsdlvm1() and will produce an error if set to TRUE.

missing

How should missingness be handled in computing the sample covariances and number of observations when data is used. Can be "auto" (default) for automatic detection, "listwise" for listwise deletion, or "pairwise" for pairwise deletion. When "auto", the function checks for missing data and switches ML to FIML, PML to PFIML, or defaults to listwise for LS estimators.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Currently implemented are "ML" for maximum likelihood estimation, "FIML" for full-information maximum likelihood estimation, "PML" for penalized maximum likelihood estimation, "PFIML" for penalized full-information maximum likelihood estimation, "ULS" for unweighted least squares estimation, "WLS" for weighted least squares estimation, and "DWLS" for diagonally weighted least squares estimation. When missing = "auto" (default), "ML" is automatically switched to "FIML" and "PML" to "PFIML" if missing data is detected.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

standardize

Which standardization method should be used? "none" (default) for no standardization, "z" for z-scores, and "quantile" for a non-parametric transformation to the quantiles of the marginal standard normal distribution.

sampleStats

An optional sample statistics object. Mostly used internally.

centerWithin

Logical, should data be within-person centered?

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

verbose

Logical, should messages be printed?

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). NA (default) triggers automatic selection via EBIC-based grid search when a penalized estimator is used; set to a specific numeric value to use a fixed penalty strength (0 = no penalty). See find_penalized_lambda and penalize.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type.

...

Arguments sent to tsdlvm1

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp

Examples

# Note: this example is wrapped in a dontrun environment because the data is not 
# available locally.
## Not run: 
# Obtain the data from:
#
# Epskamp, S., van Borkulo, C. D., van der Veen, D. C., Servaas, M. N., Isvoranu, A. M., 
# Riese, H., & Cramer, A. O. (2018). Personalized network modeling in psychopathology: 
# The importance of contemporaneous and temporal connections. Clinical Psychological 
# Science, 6(3), 416-427.
# 
# Available here: https://osf.io/c8wjz/
tsdata <- read.csv("Supplementary2_data.csv")

# Encode time variable in a way R understands:
tsdata$time <- as.POSIXct(tsdata$time, tz = "Europe/Amsterdam")

# Extract days:
tsdata$Day <- as.Date(tsdata$time, tz = "Europe/Amsterdam")

# Variables to use:
vars <- c("relaxed", "sad", "nervous", "concentration", "tired", "rumination", 
          "bodily.discomfort")

# Create lambda matrix (in this case: one factor):
Lambda <- matrix(1,7,1)

# Estimate dynamical factor model:
model <- tsdlvm1(
  tsdata, 
  lambda = Lambda,
  vars = vars, 
  dayvar = "Day",
  estimator = "FIML"
)

# Run model:
model <- model %>% runmodel

# Look at fit:
model %>% print
model %>% fit # Pretty bad fit

## End(Not run)

Unify models across groups

Description

The unionmodel will add all parameters to all groups that are free in at least one group, and the intersectionmodel will constrain all parameters across groups to zero unless they are free to estimate in all groups.

Usage

unionmodel(x, runmodel = FALSE, verbose, log = TRUE, identify =
                    TRUE, matrices, ...)

intersectionmodel(x, runmodel = FALSE, verbose, log = TRUE, identify =
                    TRUE, matrices, ...)

Arguments

x

A psychonetrics model.

runmodel

Logical, should the model be updated?

verbose

Logical, should messages be printed?

log

Logical, should the log be updated?

identify

Logical, should the model be identified?

matrices

Which matrices should be used to form the union/intersection model?

...

Arguments sent to runmodel

Value

An object of the class psychonetrics (psychonetrics-class)

Author(s)

Sacha Epskamp


Set a custom baseline or saturated reference model

Description

Convenience setters that overwrite the $baseline or $saturated slot of a psychonetrics model's @baseline_saturated list. Together with the baseline_saturated = FALSE argument exposed by every model constructor, they make it straightforward to attach hand-built reference models before calling runmodel.

Usage

update_baseline(x, baseline)
update_saturated(x, saturated)

Arguments

x

A psychonetrics model.

baseline

A psychonetrics model to use as the baseline reference.

saturated

A psychonetrics model to use as the saturated reference.

Details

Pass baseline_saturated = FALSE to the model constructor to skip auto-construction of the default reference models, attach your own with these setters, and run the target. runmodel will run any attached baseline / saturated that is not yet @computed.

Value

An object of the class psychonetrics (psychonetrics-class) with the relevant slot overwritten.

Author(s)

Sacha Epskamp

Examples

## Not run: 
mod <- modelfun(..., baseline_saturated = FALSE)
mod <- update_baseline(mod, mod_baseline)
mod <- update_saturated(mod, mod_saturated)
mod <- runmodel(mod)

## End(Not run)

Lag-1 vector autoregression family of psychonetrics models

Description

This is the family of models that models time-series data using a lag-1 vector autoregressive model (VAR; Epskamp,Waldorp, Mottus, Borsboom, 2018). The model is fitted to the Toeplitz matrix, but unlike typical SEM software the block of covariances of the lagged variables is not used in estimating the temporal and contemporaneous relationships (the block is modeled completely separately using a cholesky decomposition, and does not enter the model otherwise). The contemporaneous argument can be used to define what contemporaneous model is used: contemporaneous = "cov" (default) models a variance-covariance matrix, contemporaneous = "chol" models a Cholesky decomposition, contemporaneous = "prec" models a precision matrix, and contemporaneous = "ggm" (alias: gvar()) models a Gaussian graphical model, also then known as a graphical VAR model.

Usage

var1(data, contemporaneous = c("cov", "chol", "prec",
                   "ggm"), beta = "full", omega_zeta = "full", delta_zeta
                   = "full", kappa_zeta = "full", sigma_zeta = "full",
                   lowertri_zeta = "full", mu, beepvar, dayvar, idvar,
                   vars, groups, groupvar, covs, cors, means,
                   nobs, corinput, missing = "auto",
                   centerWithin = FALSE,
                   equal = "none", baseline_saturated = TRUE, estimator =
                   "ML", optimizer, storedata = FALSE, covtype =
                   c("choose", "ML", "UB"), standardize = c("none", "z",
                   "quantile"), sampleStats, verbose = FALSE, bootstrap =
                   FALSE, boot_sub, boot_resample,
                   penalty_lambda = NA, penalty_alpha = 1,
                   penalize_matrices)

gvar(...)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

contemporaneous

The type of contemporaneous model used. See description.

beta

A model matrix encoding the temporal relationships (transpose of temporal network). A 0 encodes a fixed to zero element, a 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix. Can also be "full" for a full temporal network or "zero" for an empty temporal network.

omega_zeta

Only used when contemporaneous = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta_zeta

Only used when contemporaneous = "ggm". The scaling (standard deviation) matrix, which is diagonal. Either "full" (the default) or "diag" to freely estimate all diagonal scalings, "zero" (not recommended) to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa_zeta

Only used when contemporaneous = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

sigma_zeta

Only used when contemporaneous = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri_zeta

Only used when contemporaneous = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

mu

Optional vector encoding the mean structure. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free means, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

beepvar

Optional string indicating assessment beep per day. Adding this argument will cause non-consecutive beeps to be treated as missing!

dayvar

Optional string indicating assessment day. Adding this argument makes sure that the first measurement of a day is not regressed on the last measurement of the previous day. IMPORTANT: only add this if the data has multiple observations per day.

idvar

Optional string indicating the subject ID

vars

An optional character vector encoding the variables used in the analysis. Must equal names of the dataset in data.

groups

Deprecated. Use groupvar instead. An optional string indicating the name of the group variable in data.

groupvar

An optional string indicating the name of the group variable in data. Replaces the deprecated groups argument; if both are supplied, groupvar takes precedence with a warning.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure covtype argument is set correctly to the type of covariances used.

cors

A sample correlation matrix, or a list/array of such matrices for multiple groups. When supplied, the matrix is treated as a covariance matrix with a warning (appropriate for standardized data). Requires nobs. Note: corinput = TRUE is not supported in var1.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

corinput

Logical. Not supported in var1() and will produce an error if set to TRUE.

missing

How should missingness be handled in computing the sample covariances and number of observations when data is used. Can be "auto" (default) for automatic detection, "listwise" for listwise deletion, or "pairwise" for pairwise deletion. When "auto", the function checks for missing data and switches ML to FIML, PML to PFIML, or defaults to listwise for LS estimators.

centerWithin

Logical, should the data be centered within persons (per idvar) before estimation? Defaults to FALSE (the historical behavior). Only used when raw data is supplied.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Currently implemented are "ML" for maximum likelihood estimation, "FIML" for full-information maximum likelihood estimation, "PML" for penalized maximum likelihood estimation, "PFIML" for penalized full-information maximum likelihood estimation, "ULS" for unweighted least squares estimation, "WLS" for weighted least squares estimation, and "DWLS" for diagonally weighted least squares estimation. When missing = "auto" (default), "ML" is automatically switched to "FIML" and "PML" to "PFIML" if missing data is detected.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

standardize

Which standardization method should be used? "none" (default) for no standardization, "z" for z-scores, and "quantile" for a non-parametric transformation to the quantiles of the marginal standard normal distribution.

sampleStats

An optional sample statistics object. Mostly used internally.

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

verbose

Logical, should messages be printed?

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). NA (default) triggers automatic selection via EBIC-based grid search when a penalized estimator is used; set to a specific numeric value to use a fixed penalty strength (0 = no penalty). See find_penalized_lambda and penalize.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type.

...

Arguments sent to var1

Details

The lag-1 vector autoregression (VAR(1)) model describes a multivariate time series through a lag-0 (contemporaneous) and a lag-1 (temporal) structure. The temporal structure is captured by the regression matrix beta (whose transpose is the temporal network), relating each observation to the previous measurement occasion. The contemporaneous structure captures the associations among the residuals (innovations) within the same measurement occasion, and can be parameterized in several ways through the contemporaneous argument: as a covariance matrix ("cov"), a Cholesky decomposition ("chol"), a precision matrix ("prec"), or a Gaussian graphical model ("ggm"; the partial correlation network of the residuals). The gvar wrapper fixes contemporaneous = "ggm" to directly estimate a graphical VAR model. Combined, the temporal and contemporaneous networks imply the lag-0 and lag-1 (block-Toeplitz) covariance structure that is fitted to the data.

Value

An object of the class psychonetrics

Author(s)

Sacha Epskamp

References

Epskamp, S., Waldorp, L. J., Mottus, R., & Borsboom, D. (2018). The Gaussian graphical model in cross-sectional and time-series data. Multivariate Behavioral Research, 53(4), 453-480.

See Also

lvm, varcov, dlvm1

Examples

library("dplyr")
library("graphicalVAR")

beta <- matrix(c(
  0,0.5,
  0.5,0
),2,2,byrow=TRUE)
kappa <- diag(2)
simData <- graphicalVARsim(50, beta, kappa)

# Form model:
model <- gvar(simData)

# Evaluate model:
model <- model %>% runmodel

# Parameter estimates:
model %>% parameters

# Plot the CIs:
CIplot(model,  "beta")

# Note: this example is wrapped in a dontrun environment because the data is not 
# available locally.
## Not run: 
# Longer example:
#
# Obtain the data from:
#
# Epskamp, S., van Borkulo, C. D., van der Veen, D. C., Servaas, M. N., Isvoranu, A. M., 
# Riese, H., & Cramer, A. O. (2018). Personalized network modeling in psychopathology: 
# The importance of contemporaneous and temporal connections. Clinical Psychological 
# Science, 6(3), 416-427.
# 
# Available here: https://osf.io/c8wjz/

tsdata <- read.csv("Supplementary2_data.csv")

# Encode time variable in a way R understands:
tsdata$time <- as.POSIXct(tsdata$time, tz = "Europe/Amsterdam")

# Extract days:
tsdata$Day <- as.Date(tsdata$time, tz = "Europe/Amsterdam")

# Variables to use:
vars <- c("relaxed", "sad", "nervous", "concentration", "tired", "rumination", 
          "bodily.discomfort")

# Estimate, prune with FDR, and perform stepup search:
model_FDRprune <- gvar(
  tsdata, 
  vars = vars, 
  dayvar = "Day",
  estimator = "FIML"
  ) %>% 
  runmodel %>% 
  prune(adjust = "fdr", recursive = FALSE) %>% 
  stepup(criterion = "bic")

# Estimate with greedy stepup search:
model_stepup <- gvar(
  tsdata, 
  vars = vars, 
  dayvar = "Day",
  estimator = "FIML",
  omega_zeta = "zero",
  beta = "zero"
) %>% 
  runmodel %>% 
  stepup(greedy = TRUE, greedyadjust = "bonferroni", criterion = "bic")

# Compare models:
compare(
  FDRprune = model_FDRprune,
  stepup = model_stepup
)
# Very similar but not identical. Stepup is prefered here according to AIC and BIC

# Stepup results:
temporal <- getmatrix(model_stepup, "PDC") # PDC = Partial Directed Correlations
contemporaneous <- getmatrix(model_stepup, "omega_zeta")

# Average layout:
library("qgraph")
L <- averageLayout(temporal, contemporaneous)

# Labels:
labs <- gsub("\\.","\n",vars)

# Plot:
layout(t(1:2))
qgraph(temporal, layout = L, theme = "colorblind", directed=TRUE, diag=TRUE,
       title = "Temporal", vsize = 12, mar = rep(6,4), asize = 5,
       labels = labs)
qgraph(contemporaneous, layout = L, theme = "colorblind", 
       title = "Contemporaneous", vsize = 12, mar = rep(6,4), asize = 5,
       labels = labs)

## End(Not run)

Variance-covariance family of psychonetrics models

Description

This is the family of models that models only a variance-covariance matrix with mean structure. The type argument can be used to define what model is used: type = "cov" (default) models a variance-covariance matrix directly, type = "chol" (alias: cholesky()) models a Cholesky decomposition, type = "prec" (alias: precision()) models a precision matrix, type = "ggm" (alias: ggm()) models a Gaussian graphical model (Epskamp, Rhemtulla and Borsboom, 2017), and type = "cor" (alias: corr()) models a correlation matrix.

Usage

varcov(data, type = c("cov", "chol", "prec", "ggm", "cor"),
                   sigma = "full", kappa = "full", omega = "full",
                   lowertri = "full", delta = "diag", rho = "full", SD =
                   "full", mu, tau, vars, ordered = character(0), groups,
                   groupvar, covs, cors, means, nobs, missing = "auto", equal =
                   "none", baseline_saturated = TRUE, estimator =
                   "default", likelihood = c("normal", "wishart"),
                   fixed_x = character(0),
                   optimizer, storedata = FALSE, WLS.W,
                   sampleStats, meanstructure, corinput, verbose = FALSE,
                   covtype = c("choose", "ML", "UB"), standardize =
                   c("none", "z", "quantile"), fullFIML = FALSE,
                   bootstrap = FALSE, boot_sub, boot_resample,
                   penalty_lambda = NA, penalty_alpha = 1,
                   penalize_matrices)
cholesky(...)
precision(...)
prec(...)
ggm(...)
corr(...)

Arguments

data

A data frame encoding the data used in the analysis. Can be missing if covs and nobs are supplied.

type

The type of model used. See description.

sigma

Only used when type = "cov". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

kappa

Only used when type = "prec". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

omega

Only used when type = "ggm". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

lowertri

Only used when type = "chol". Either "full" to estimate every element freely, "diag" to only include diagonal elements, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

delta

Only used when type = "ggm". Either "diag" or "zero" (not recommended), or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

rho

Only used when type = "cor". Either "full" to estimate every element freely, "zero" to set all elements to zero, or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

SD

Only used when type = "cor". Either "diag" or "zero" (not recommended), or a matrix of the dimensions node x node with 0 encoding a fixed to zero element, 1 encoding a free to estimate element, and higher integers encoding equality constraints. For multiple groups, this argument can be a list or array with each element/slice encoding such a matrix.

mu

Optional vector encoding the mean structure. Set elements to 0 to indicate fixed to zero constrains, 1 to indicate free means, and higher integers to indicate equality constraints. For multiple groups, this argument can be a list or array with each element/column encoding such a vector.

tau

Optional list encoding the thresholds per variable.

vars

An optional character vector encoding the variables used in the analysis. Must equal names of the dataset in data.

groups

Deprecated. Use groupvar instead. An optional string indicating the name of the group variable in data.

groupvar

An optional string indicating the name of the group variable in data. Replaces the deprecated groups argument; if both are supplied, groupvar takes precedence with a warning.

covs

A sample variance–covariance matrix, or a list/array of such matrices for multiple groups. Make sure covtype argument is set correctly to the type of covariances used.

cors

A sample correlation matrix, or a list/array of such matrices for multiple groups. When supplied, corinput defaults to TRUE and the matrix is used in place of covs. Requires nobs.

means

A vector of sample means, or a list/matrix containing such vectors for multiple groups.

nobs

The number of observations used in covs and means, or a vector of such numbers of observations for multiple groups.

covtype

If 'covs' is used, this is the type of covariance (maximum likelihood or unbiased) the input covariance matrix represents. Set to "ML" for maximum likelihood estimates (denominator n) and "UB" to unbiased estimates (denominator n-1). The default will try to find the type used, by investigating which is most likely to result from integer valued datasets.

missing

How should missingness be handled in computing the sample covariances and number of observations when data is used. Can be "auto" (default) for automatic detection, "listwise" for listwise deletion, or "pairwise" for pairwise deletion. When "auto", the function checks for missing data and switches ML to FIML, PML to PFIML, or defaults to listwise for LS estimators.

equal

A character vector indicating which matrices should be constrained equal across groups.

baseline_saturated

A logical indicating if the baseline and saturated model should be included. Mostly used internally and NOT Recommended to be used manually.

estimator

The estimator to be used. Currently implemented are "ML" for maximum likelihood estimation, "FIML" for full-information maximum likelihood estimation, "PML" for penalized maximum likelihood estimation, "PFIML" for penalized full-information maximum likelihood estimation, "ULS" for unweighted least squares estimation, "WLS" for weighted least squares estimation, and "DWLS" for diagonally weighted least squares estimation. "WLSMV" is accepted as a synonym for "DWLS" (both use DWLS estimation with a mean-and-variance adjusted scaled test statistic). When missing = "auto" (default), "ML" is automatically switched to "FIML" and "PML" to "PFIML" if missing data is detected. Defaults to "ML" for continuous data and "DWLS" when ordinal variables are specified via ordered.

likelihood

The Gaussian likelihood scaling for maximum-likelihood estimation. "normal" (the default) uses the nn (biased) sample-covariance denominator, so the chi-square is NF^N \hat{F} and the parameter covariance is Info1/N\mathrm{Info}^{-1}/N. "wishart" uses the n1n-1 (unbiased) sample covariance per group, so the chi-square uses (ng1)(n_g - 1) multipliers and the standard errors are inflated by ng/(ng1)\sqrt{n_g/(n_g-1)}, matching lavaan's likelihood = "wishart" (Rosseel, 2012). Only available for complete-data maximum likelihood (estimator = "ML"); it errors for FIML, least-squares and ordinal estimators and for raw time-series input. Default "normal" reproduces the behaviour of previous versions exactly.

fixed_x

Character vector of exogenous variable names whose means and mutual (co)variances are fixed to their sample values and excluded from the free-parameter count and the degrees-of-freedom statistic count, matching lavaan's sem(..., fixed.x = TRUE) (Rosseel, 2012). The model is thereby conditioned on these variables, which relaxes the distributional (multivariate-normality) assumption on them; the cross-covariances between the fixed-x and the endogenous variables remain free. Only supported for type = "cov" and complete-data estimator = "ML". The reported log-likelihood is the conditional log-likelihood (of the endogenous variables given x). Default character(0) (no fixed.x; behaviour unchanged). Note: the incremental fit indices (CFI/TLI/NFI/...) use psychonetrics' unconditional independence baseline and may therefore differ from lavaan, which conditions its baseline on x; the absolute fit measures (chi-square, df, RMSEA, AIC, BIC, log-likelihood) and all estimates and standard errors match lavaan.

optimizer

The optimizer to be used. Can be one of "nlminb" (the default R nlminb function), "ucminf" (from the optimr package), "nloptr_TNEWTON" (preconditioned truncated Newton via nloptr), and "LBFGS++" (pure C++ L-BFGS-B). Defaults to "nlminb".

storedata

Logical, should the raw data be stored? Needed for bootstrapping (see bootstrap).

standardize

Which standardization method should be used? "none" (default) for no standardization, "z" for z-scores, and "quantile" for a non-parametric transformation to the quantiles of the marginal standard normal distribution.

WLS.W

Optional WLS weights matrix.

sampleStats

An optional sample statistics object. Mostly used internally.

verbose

Logical, should progress be printed to the console?

ordered

A vector with strings indicating the variables that are ordered categorical, or set to TRUE to model all variables as ordered categorical.

meanstructure

Logical, should the meanstructure be modeled explicitly?

corinput

Logical, is the input a correlation matrix?

fullFIML

Logical, should row-wise FIML be used? Not recommended!

bootstrap

Should the data be bootstrapped? If TRUE the data are resampled and a bootstrap sample is created. These must be aggregated using aggregate_bootstraps! Can be TRUE or FALSE. Can also be "nonparametric" (which sets boot_sub = 1 and boot_resample = TRUE) or "case" (which sets boot_sub = 0.75 and boot_resample = FALSE).

boot_sub

Proportion of cases to be subsampled (round(boot_sub * N)).

boot_resample

Logical, should the bootstrap be with replacement (TRUE) or without replacement (FALSE)

penalty_lambda

Numeric penalty strength for penalized ML estimation (PML/PFIML). Default is NA, which triggers automatic lambda selection via EBIC grid search when estimator = "PML" or "PFIML" (see find_penalized_lambda). Set to a specific numeric value (e.g., 0.1) for manual lambda, or 0 for no penalty.

penalty_alpha

Elastic net mixing parameter: 1 = LASSO (default), 0 = ridge.

penalize_matrices

Character vector of matrix names to penalize. If missing, defaults are selected based on the model type.

...

Arguments sent to varcov

Details

The model used in this family is:

var(y)=Σ\mathrm{var}(\boldsymbol{y} ) = \boldsymbol{\Sigma}

E(y)=μ\mathcal{E}( \boldsymbol{y} ) = \boldsymbol{\mu}

in which the covariance matrix can further be modeled in four ways. With type = "chol" as Cholesky decomposition:

Σ=LL\boldsymbol{\Sigma} = \boldsymbol{L}\boldsymbol{L}^{\top},

with type = "prec" as Precision matrix:

Σ=K1\boldsymbol{\Sigma} = \boldsymbol{K}^{-1},

with type = "ggm" as Gaussian graphical model:

Σ=Δ(IΩ)(1)Δ\boldsymbol{\Sigma} = \boldsymbol{\Delta}(\boldsymbol{I} - \boldsymbol{\Omega})^(-1) \boldsymbol{\Delta},

and finally with type = "cor" as a correlation matrix scaled by standard deviations:

Σ=DRD\boldsymbol{\Sigma} = \boldsymbol{D}\boldsymbol{R}\boldsymbol{D},

in which D\boldsymbol{D} is a diagonal matrix of standard deviations and R\boldsymbol{R} a correlation matrix.

Value

An object of the class psychonetrics

Author(s)

Sacha Epskamp

References

Epskamp, S., Rhemtulla, M., & Borsboom, D. (2017). Generalized network psychometrics: Combining network and latent variable models. Psychometrika, 82(4), 904-927.

Rosseel, Y. (2012). lavaan: An R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. doi:10.18637/jss.v048.i02

See Also

lvm, var1, dlvm1, penalize for manual penalty control, find_penalized_lambda for automatic lambda selection, refit for post-selection inference after penalized estimation.

Examples

# Load bfi data from psych package:
library("psychTools")
data(bfi)

# Also load dplyr for the pipe operator:
library("dplyr")

# Let's take the agreeableness items, and gender:
ConsData <- bfi %>% 
  select(A1:A5, gender) %>% 
  na.omit # Let's remove missingness (or use missing = "auto" default which auto-selects FIML)

# Define variables:
vars <- names(ConsData)[1:5]

# Saturated estimation:
mod_saturated <- ggm(ConsData, vars = vars)

# Run the model:
mod_saturated <- mod_saturated %>% runmodel

# We can look at the parameters:
mod_saturated %>% parameters

# Labels:
labels <- c(
  "indifferent to the feelings of others",
  "inquire about others' well-being",
  "comfort others",
  "love children",
  "make people feel at ease")
  
# Plot CIs:
CIplot(mod_saturated,  "omega", labels = labels, labelstart = 0.2)



# We can also fit an empty network:
mod0 <- ggm(ConsData, vars = vars, omega = "zero")

# Run the model:
mod0 <- mod0 %>% runmodel

# We can look at the modification indices:
mod0 %>% MIs

# To automatically add along modification indices, we can use stepup:
mod1 <- mod0 %>% stepup

# Let's also prune all non-significant edges to finish:
mod1 <- mod1 %>% prune

# Look at the fit:
mod1 %>% fit

# Compare to original (baseline) model:
compare(baseline = mod0, adjusted = mod1)

# We can also look at the parameters:
mod1 %>% parameters

# Or obtain the network as follows:
getmatrix(mod1, "omega")

# Penalized GGM estimation with automatic lambda selection:
mod_pml <- ggm(ConsData, vars = vars, estimator = "PML")
mod_pml <- mod_pml %>% runmodel

# Check selected lambda:
mod_pml@optim$lambda_search

# Obtain the sparse network:
getmatrix(mod_pml, "omega")

# Wishart likelihood (n-1 denominator), matching lavaan likelihood = "wishart":
mod_wis <- varcov(ConsData, vars = vars, type = "cov", likelihood = "wishart")
mod_wis <- mod_wis %>% runmodel

# fixed.x: condition on A1 and A2 as exogenous covariates (their means and
# mutual covariances are fixed to the sample values, excluded from npar/df):
mod_fx <- varcov(ConsData, vars = vars, type = "cov",
                 fixed_x = c("A1", "A2"))
mod_fx <- mod_fx %>% runmodel

Write comprehensive model output to a text file

Description

Writes a comprehensive plain-text output file containing all model information, similar to Mplus or LISREL output. The file includes model specification, sample information, parameter estimates, fit measures, model matrices, modification indices, and the model logbook. This file can be shared as supplementary material in publications.

Usage

write_psychonetrics(x, file = "psychonetrics_output.txt",
                    matrices = TRUE, MIs = TRUE, logbook = TRUE)

Arguments

x

A psychonetrics model.

file

Character string specifying the path to the output file. Defaults to "psychonetrics_output.txt".

matrices

Logical. Should the full estimated model matrices be included in the output? Defaults to TRUE. Set to FALSE for more compact output.

MIs

Logical. Should modification indices be included? Only included if modification indices have been computed via addMIs. Defaults to TRUE.

logbook

Logical. Should the model logbook be included? Defaults to TRUE.

Value

Invisibly returns the file path of the written output.

Author(s)

Sacha Epskamp

Examples

library("dplyr")

# Load data:
data(StarWars)

# Simple CFA:
Lambda <- matrix(1, 4)
mod <- lvm(StarWars, lambda = Lambda, vars = c("Q1","Q5","Q6","Q7"),
           identification = "variance", latents = "Originals")
mod <- mod %>% runmodel %>% addfit

# Write output:
write_psychonetrics(mod, file = tempfile(fileext = ".txt"))