Title: | Power Analyses for SEM |
---|---|
Description: | Provides a-priori, post-hoc, and compromise power-analyses for structural equation models (SEM). |
Authors: | Morten Moshagen [aut, cre] |
Maintainer: | Morten Moshagen <[email protected]> |
License: | LGPL |
Version: | 2.1.2 |
Built: | 2025-03-12 06:17:58 UTC |
Source: | https://github.com/moshagen/sempower |
Checks whether x is defined and lies within the specified bound, stop otherwise.
checkBounded(x, message = NULL, bound = c(0, 1), inclusive = FALSE)
checkBounded(x, message = NULL, bound = c(0, 1), inclusive = FALSE)
x |
x |
message |
identifier for x |
bound |
the boundaries, array of size two |
inclusive |
whether x might lie on boundary |
Checks whether comparison is one of 'restricted'
or 'saturated'
(or respective shortcuts), stop otherwise.
checkComparisonModel(comparison)
checkComparisonModel(comparison)
comparison |
comparison |
Returns cleaned comparison
Checks whether data generation type is one of 'normal'
, 'IG'
, 'mnonr'
, 'RK'
, or 'VM'
, stop otherwise.
checkDataGenerationTypes(type)
checkDataGenerationTypes(type)
type |
type |
Returns cleaned data generation type
Checks whether ...
contains arguments related to loadings and to power, stop otherwise.
checkEllipsis(...)
checkEllipsis(...)
... |
the parameters to search. |
Checks whether missing generation type is one of 'mcar'
, 'mar'
, or 'nmar'
, stop otherwise.
checkMissingTypes(type)
checkMissingTypes(type)
type |
type |
Returns cleaned data generation type
Checks whether nullEffect
is one of the valid effects, stop otherwise.
checkNullEffect(nullEffect, valid, message = NULL)
checkNullEffect(nullEffect, valid, message = NULL)
nullEffect |
nullEffect |
valid |
vector of valid effects |
message |
message |
Returns cleaned nullEffect
Checks whether x
is defined and a positive number, stop otherwise.
checkPositive(x, message = NULL)
checkPositive(x, message = NULL)
x |
x |
message |
identifier for |
Checks whether x
is positive definite, stop otherwise.
checkPositiveDefinite(x, message = NULL, stop = TRUE)
checkPositiveDefinite(x, message = NULL, stop = TRUE)
x |
x |
message |
identifier for |
stop |
whether to stop or to throw a warning |
Checks whether type is one of 'a-priori'
, 'post-hoc'
, or 'compromise'
(or respective shortcuts), stop otherwise.
checkPowerTypes(type)
checkPowerTypes(type)
type |
type |
Returns cleaned type
Checks whether x
is a square matrix, stop otherwise.
checkSquare(x, message = NULL)
checkSquare(x, message = NULL)
x |
x |
message |
identifier for |
Checks whether x
is a symmetric square matrix, stop otherwise.
checkSymmetricSquare(x, message = NULL)
checkSymmetricSquare(x, message = NULL)
x |
x |
message |
identifier for |
Generates random data from population variance-covariance matrix and population means, either from a multivariate normal distribution, or using one of various approaches to generate non-normal data.
doSim( r, simData, isMultigroup = FALSE, modelH0, modelH1, lavOptions, lavOptionsH1 )
doSim( r, simData, isMultigroup = FALSE, modelH0, modelH1, lavOptions, lavOptionsH1 )
r |
replication id |
simData |
list of datafiles |
isMultigroup |
multigroup flag |
modelH0 |
|
modelH1 |
|
lavOptions |
a list of additional options passed to |
lavOptionsH1 |
lavoptions when fitting |
list
Generates random data from population variance-covariance matrix and population means, either from a multivariate normal distribution, or using one of various approaches to generate non-normal data.
genData( N = NULL, Sigma = NULL, mu = NULL, nSets = 1, gIdx = NULL, modelH0 = NULL, simOptions = NULL )
genData( N = NULL, Sigma = NULL, mu = NULL, nSets = 1, gIdx = NULL, modelH0 = NULL, simOptions = NULL )
N |
sample size. |
Sigma |
population covariance matrix. |
mu |
population means. |
nSets |
number of data sets to generate |
gIdx |
if not |
modelH0 |
a |
simOptions |
additional arguments specifying the data generation routine |
Returns the generated data
## Not run: gen <- semPower.genSigma(Phi = .2, loadings = list(rep(.5, 3), rep(.7, 3))) data <- genData(N = 500, Sigma = gen$Sigma) ## End(Not run)
## Not run: gen <- semPower.genSigma(Phi = .2, loadings = list(rep(.5, 3), rep(.7, 3))) data <- genData(N = 500, Sigma = gen$Sigma) ## End(Not run)
Generates random data conforming to a population variance-covariance matrix using the independent generator approach (IG, Foldnes & Olsson, 2016) approach specifying third and fourth moments of the marginals.
genData.IG(N = NULL, Sigma = NULL, nSets = 1, skewness = NULL, kurtosis = NULL)
genData.IG(N = NULL, Sigma = NULL, nSets = 1, skewness = NULL, kurtosis = NULL)
N |
sample size. |
Sigma |
population covariance matrix. |
nSets |
number of data sets to generate |
skewness |
vector specifying skewness for each variable |
kurtosis |
vector specifying excess kurtosis for each variable |
This function is a wrapper for the respective function of the covsim
package.
For details, see Foldnes, N. & Olsson, U. H. (2016) A Simple Simulation Technique for Nonnormal Data with Prespecified Skewness, Kurtosis, and Covariance Matrix. Multivariate Behavioral Research, 51, 207-219. 10.1080/00273171.2015.1133274
Returns the generated data
Generates random data conforming to a population variance-covariance matrix using the approach by Qu, Liu, & Zhang (2020) specifying Mardia's multivariate skewness and kurtosis.
genData.mnonr( N = NULL, Sigma = NULL, nSets = 1, skewness = NULL, kurtosis = NULL )
genData.mnonr( N = NULL, Sigma = NULL, nSets = 1, skewness = NULL, kurtosis = NULL )
N |
sample size. |
Sigma |
population covariance matrix. |
nSets |
number of data sets to generate |
skewness |
multivariate skewness. May not be negative. |
kurtosis |
multivariate kurtosis. Must be >= 1.641 skewness + p (p + 0.774), where p is the number of variables. |
This function is a wrapper for the respective function of the mnonr
package.
For details, see Qu, W., Liu, H., & Zhang, Z. (2020). A method of generating multivariate non-normal random numbers with desired multivariate skewness and kurtosis. Behavior Research Methods, 52, 939-946. doi: 10.3758/s13428-019-01291-5
Returns the generated data
Generates multivariate normal random data conforming to a population variance-covariance matrix.
genData.normal(N = NULL, Sigma = NULL, nSets = 1)
genData.normal(N = NULL, Sigma = NULL, nSets = 1)
N |
sample size. |
Sigma |
population covariance matrix. |
nSets |
number of data sets to generate |
Returns the generated data
Generates random data conforming to a population variance-covariance matrix using the approach by Ruscio & Kaczetow (2008) specifying distributions for the marginals.
genData.RK( N = NULL, Sigma = NULL, nSets = 1, distributions = NULL, modelH0 = NULL, maxIter = 10 )
genData.RK( N = NULL, Sigma = NULL, nSets = 1, distributions = NULL, modelH0 = NULL, maxIter = 10 )
N |
sample size. |
Sigma |
population covariance matrix. |
nSets |
number of data sets to generate |
distributions |
a list specifying the population distribution and additional arguments in a list either to apply to all variables (e.g. |
modelH0 |
a |
maxIter |
maximum number of iterations, defaults to 10. |
This function is based on the implementation by Ruscio & Kaczetow (2008).
For details, see Ruscio, J., & Kaczetow, W. (2008). Simulating multivariate nonnormal data using an iterative algorithm. Multivariate Behavioral Research, 43, 355-381.
Returns the generated data
## Not run: distributions <- list( list('rchisq', list(df = 2)), list('runif', list(min = 0, max = 1)), list('rexp', list(rate = 1)) ) data <- genData.ruscio(N = 100, Sigma = diag(3), distributions = distributions, modelH0 = 'f =~ x1 + x2 + x3') distributions <- list( list('rnorm', list(mean = 0, sd = 10)), list('runif', list(min = 0, max = 1)), list('rbeta', list(shape1 = 1, shape2 = 2)), list('rexp', list(rate = 1)), list('rpois', list(lambda = 4)), list('rbinom', list(size = 1, prob = .5)) ) data <- genData.ruscio(N = 100, Sigma = diag(6), distributions = distributions, modelH0 = 'f1=~x1+x2+x3\nf2=~x4+x5+x6') ## End(Not run)
## Not run: distributions <- list( list('rchisq', list(df = 2)), list('runif', list(min = 0, max = 1)), list('rexp', list(rate = 1)) ) data <- genData.ruscio(N = 100, Sigma = diag(3), distributions = distributions, modelH0 = 'f =~ x1 + x2 + x3') distributions <- list( list('rnorm', list(mean = 0, sd = 10)), list('runif', list(min = 0, max = 1)), list('rbeta', list(shape1 = 1, shape2 = 2)), list('rexp', list(rate = 1)), list('rpois', list(lambda = 4)), list('rbinom', list(size = 1, prob = .5)) ) data <- genData.ruscio(N = 100, Sigma = diag(6), distributions = distributions, modelH0 = 'f1=~x1+x2+x3\nf2=~x4+x5+x6') ## End(Not run)
Generates random data conforming to a population variance-covariance matrix using the third-order polynomial method (Vale & Maurelli, 1983) specifying third and fourth moments of the marginals.
genData.VM(N = NULL, Sigma = NULL, nSets = 1, skewness = NULL, kurtosis = NULL)
genData.VM(N = NULL, Sigma = NULL, nSets = 1, skewness = NULL, kurtosis = NULL)
N |
sample size. |
Sigma |
population covariance matrix. |
nSets |
number of data sets to generate |
skewness |
vector specifying skewness for each variable |
kurtosis |
vector specifying excess kurtosis for each variable |
This function is a slightly adapted copy of lavaan
's ValeMaurelli1983 implementation
that avoids computing the intermediate correlation for each data sets
and uses Sigma as input.
For details, see Vale, C. & Maurelli, V. (1983). Simulating multivariate nonnormal distributions. Psychometrika, 48, 465-471.
Returns the generated data
Generate a loading matrix Lambda from various shortcuts, each assuming a simple structure.
Either define loadings
, or define nIndicator
and loadM
(and optionally loadSD
), or define
nIndicator
and loadMinMax
.
genLambda( loadings = NULL, nIndicator = NULL, loadM = NULL, loadSD = NULL, loadMinMax = NULL )
genLambda( loadings = NULL, nIndicator = NULL, loadM = NULL, loadSD = NULL, loadMinMax = NULL )
loadings |
A list providing the loadings by factor, e. g. |
nIndicator |
Vector indicating the number of indicators for each factor, e. g. |
loadM |
Either a vector giving the mean loadings for each factor or a single number to use for every loading. |
loadSD |
Either a vector giving the standard deviation of loadings for each factor or a single number, for use in conjunction with |
loadMinMax |
A list giving the minimum and maximum loading for each factor or a vector to apply to all factors. If set, loadings are sampled from a uniform distribution. |
The loading matrix Lambda.
Creates lavaan
model strings from model matrices.
genModelString( Lambda = NULL, Phi = NULL, Beta = NULL, Psi = NULL, Theta = NULL, tau = NULL, Alpha = NULL, useReferenceIndicator = !is.null(Beta), metricInvariance = NULL, nGroups = 1 )
genModelString( Lambda = NULL, Phi = NULL, Beta = NULL, Psi = NULL, Theta = NULL, tau = NULL, Alpha = NULL, useReferenceIndicator = !is.null(Beta), metricInvariance = NULL, nGroups = 1 )
Lambda |
Factor loading matrix. |
Phi |
Factor correlation (or covariance) matrix. If |
Beta |
Regression slopes between latent variables (all-y notation). |
Psi |
Variance-covariance matrix of latent residuals when |
Theta |
Variance-covariance matrix of manifest residuals. If |
tau |
Intercepts. If |
Alpha |
Factor means. If |
useReferenceIndicator |
Whether to identify factors in accompanying model strings by a reference indicator ( |
metricInvariance |
A list containing the factor indices for which the accompanying model strings should apply metric invariance labels, e.g. |
nGroups |
(defaults to 1) If > 1 and |
A list containing the following lavaan
model strings:
modelPop |
population model |
modelTrue |
"true" analysis model freely estimating all non-zero parameters. |
modelTrueCFA |
similar to |
Computes AGFI from the minimum of the ML-fit-function.
getAGFI.F(Fmin, df, p)
getAGFI.F(Fmin, df, p)
Fmin |
minimum of the ML-fit-function |
df |
model degrees of freedom |
p |
number of observed variables |
Returns AGFI
get squared difference between requested and achieved beta on a logscale
getBetadiff( cN, critChi, logBetaTarget, fmin, df, weights = NULL, simulatedPower = FALSE, pkgEnv = NULL, ... )
getBetadiff( cN, critChi, logBetaTarget, fmin, df, weights = NULL, simulatedPower = FALSE, pkgEnv = NULL, ... )
cN |
current N |
critChi |
critical chi-square associated with chosen alpha error |
logBetaTarget |
log(desired beta) |
fmin |
minimum of the ML fit function |
df |
the model degrees of freedom |
weights |
sample weights for multiple group models |
simulatedPower |
whether to perform a simulated (TRUE) (rather than analytical, FALSE) power analysis. |
pkgEnv |
local pkgEnv containing iterationCounter. |
... |
other parameter passed to simulate() |
squared difference requested and achieved beta on a log scale
Computes CFI given the model-implied and the observed (or population) covariance matrix:
CFI = (F_null - F_hyp) / F_null
.
getCFI.Sigma(SigmaHat, S, muHat = NULL, mu = NULL, fittingFunction = "ML")
getCFI.Sigma(SigmaHat, S, muHat = NULL, mu = NULL, fittingFunction = "ML")
SigmaHat |
model implied covariance matrix |
S |
observed (or population) covariance matrix |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
fittingFunction |
whether to use |
Returns CFI
Computes CFI given the model-implied and the observed (or population) covariance matrix for multiple group models.
CFI = (F_null - F_hyp) / F_null
applying multiple group sampling weights to F_hyp
and F_null
.
getCFI.Sigma.mgroups( SigmaHat, S, muHat = NULL, mu = NULL, N, fittingFunction = "ML" )
getCFI.Sigma.mgroups( SigmaHat, S, muHat = NULL, mu = NULL, N, fittingFunction = "ML" )
SigmaHat |
a list of model implied covariance matrix |
S |
a list of observed (or population) covariance matrix |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
N |
a list of group weights |
fittingFunction |
whether to use |
Returns CFI
Computes the (Wishart-) chi-square from the population minimum of the fit-function:
chi-square = (N - 1) * F0 + df = ncp + df
. Note that F0 is the population minimum.
Using F_hat would give chi-square = (N - 1) * F_hat
.
getChiSquare.F(Fmin, n, df)
getChiSquare.F(Fmin, n, df)
Fmin |
population minimum of the fit-function (can be a list for multiple group models). |
n |
number of observations (can be a list for multiple group models). |
df |
model degrees of freedom |
Returns chi-square
Computes chi-square from the non-centrality parameter: chi-square = ncp + df
.
getChiSquare.NCP(NCP, df)
getChiSquare.NCP(NCP, df)
NCP |
non-centrality parameter |
df |
model degrees of freedom |
Returns chi-square
get proper discrepancy function (to measure F0) from fitting function (to obtain SigmaHat)
getDiscrepancyFunctionFromFittingFunction(fittingFunction)
getDiscrepancyFunctionFromFittingFunction(fittingFunction)
fittingFunction |
fittingFunction |
discrepancy function
Determine the squared log-difference between alpha and beta error given a certain chi-square value from central chi-square(df) and a non-central chi-square(df, ncp) distribution.
getErrorDiff(critChiSquare, df, ncp, log.abratio)
getErrorDiff(critChiSquare, df, ncp, log.abratio)
critChiSquare |
evaluated chi-squared value |
df |
the model degrees of freedom |
ncp |
the non-centrality parameter |
log.abratio |
log(alpha/beta) |
squared difference between alpha and beta on a log scale
Computes the minimum of the ML-fit-function from known fit indices.
getF( effect, effect.measure, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML" )
getF( effect, effect.measure, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML" )
effect |
magnitude of effect |
effect.measure |
measure of effect, one of |
df |
model degrees of freedom |
p |
number of observed variables |
SigmaHat |
model implied covariance matrix |
Sigma |
observed (or population) covariance matrix |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
fittingFunction |
one of |
Returns Fmin
Computes the minimum of the ML-fit-function from AGFI.
getF.AGFI(AGFI, df, p)
getF.AGFI(AGFI, df, p)
AGFI |
AGFI |
df |
model degrees of freedom |
p |
number of observed variables |
Returns Fmin
Computes the minimum of the ML-fit-function from GFI.
getF.GFI(GFI, p)
getF.GFI(GFI, p)
GFI |
GFI |
p |
number of observed variables |
Returns Fmin
Computes the minimum of the ML-fit-function from Mc.
getF.Mc(Mc)
getF.Mc(Mc)
Mc |
Mc |
Returns Fmin
Computes the minimum of the ML-fit-function from RMSEA:
F_min = rmsea^2 * df
.
getF.RMSEA(RMSEA, df)
getF.RMSEA(RMSEA, df)
RMSEA |
RMSEA |
df |
model degrees of freedom |
Returns Fmin
Computes the minimum of the chosen fitting-function given the model-implied and the observed (or population) covariance matrix.
The ML fitting function is:
F_min = tr(S %*% SigmaHat^-1) - p + ln(det(SigmaHat)) - ln(det(S))
. When a meanstructure is included,
(mu - muHat)' SigmaHat^-1 (mu - muHat)
is added.
The WLS fitting function is:
F_min = (Sij - SijHat)' V (Sij - SijHat)
where V is the inverse of N times the asymptotic covariance matrix of the sample statistics (Gamma; N x ACOV(mu, vech(S))).
For DWLS, V is the diagonal of the inverse of diag(NACOV), i.e. diag(solve(diag(Gamma))).
For ULS, V = I. ULS has an unknown asymptotic distribution, so it is actually irrelevant, but provided for the sake of completeness.
getF.Sigma(SigmaHat, S, muHat = NULL, mu = NULL, fittingFunction = "ML")
getF.Sigma(SigmaHat, S, muHat = NULL, mu = NULL, fittingFunction = "ML")
SigmaHat |
model implied covariance matrix |
S |
observed (or population) covariance matrix |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
fittingFunction |
one of |
Returns Fmin
get proper fitting function (to obtain sigmaHat) for chosen estimator
getFittingFunctionFromEstimator(lavOptions)
getFittingFunctionFromEstimator(lavOptions)
lavOptions |
lavOptions |
fitting function
Return data.frame containing formatted results.
getFormattedResults(type, result, digits = 6)
getFormattedResults(type, result, digits = 6)
type |
type of power analysis |
result |
result object (list) |
digits |
number of significant digits |
data.frame
Return data.frame containing formatted results.
getFormattedSimulationResults(object, digits = 2)
getFormattedSimulationResults(object, digits = 2)
object |
result object (list) |
digits |
number of significant digits |
data.frame
Computes GFI from the minimum of the ML-fit-function.
getGFI.F(Fmin, p)
getGFI.F(Fmin, p)
Fmin |
minimum of the ML-fit-function |
p |
number of observed variables |
Returns GFI
Computes known indices from the minimum of the ML-fit-function.
getIndices.F( fmin, df, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, N = NULL )
getIndices.F( fmin, df, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, N = NULL )
fmin |
minimum of the ML-fit-function |
df |
model degrees of freedom |
p |
number of observed variables |
SigmaHat |
model implied covariance matrix |
Sigma |
population covariance matrix |
muHat |
model implied means |
mu |
population means |
N |
list of sample weights |
list of indices
computes average absulute KS-distance between empirical and asympotic chi-square reference distribution.
getKSdistance(chi, df, ncp = 0)
getKSdistance(chi, df, ncp = 0)
chi |
empirical distribution |
df |
df of reference distribution |
ncp |
ncp of reference distribution |
average absolute distance
returns lavaan
options including defaults as set in sem()
as a list to be passed to lavaan()
getLavOptions(lavOptions = NULL, isCovarianceMatrix = TRUE, nGroups = 1)
getLavOptions(lavOptions = NULL, isCovarianceMatrix = TRUE, nGroups = 1)
lavOptions |
additional options to be added to (or overwriting) the defaults |
isCovarianceMatrix |
if |
nGroups |
the number of groups, 1 by default |
a list of lavaan
defaults
Computes Mc from the minimum of the ML-fit-function.
getMc.F(Fmin)
getMc.F(Fmin)
Fmin |
minimum of the ML-fit-function |
Returns Mc
Computes the non-centrality parameter from the population minimum of the fit-function
(dividing by N - 1 following the Wishart likelihood): ncp = (N - 1) * F0
.
getNCP(Fmin, n)
getNCP(Fmin, n)
Fmin |
population minimum of the fit-function (can be a list for multiple group models). |
n |
number of observations (can be a list for multiple group models). |
Returns the implied NCP.
Computes implied correlations (completely standardized) from Beta matrix, disallowing recursive paths.
getPhi.B(B, lPsi = NULL)
getPhi.B(B, lPsi = NULL)
B |
matrix of regression coefficients (all-y notation). Must only contain non-zero lower-triangular elements, so the first row only includes zeros. |
lPsi |
(lesser) matrix of residual correlations. This is not the Psi matrix, but a lesser version ignoring all variances and containing correlations off the diagonal. Can be omitted for no correlations beyond those implied by B. |
Returns the implied correlation matrix
## Not run: # mediation model B <- matrix(c( c(.00, .00, .00), c(.10, .00, .00), c(.20, .30, .00) ), byrow = TRUE, ncol = 3) Phi <- getPhi.B(B) # CLPM with residual correlations B <- matrix(c( c(.00, .00, .00, .00), c(.30, .00, .00, .00), c(.70, .10, .00, .00), c(.20, .70, .00, .00) ), byrow = TRUE, ncol = 4) lPsi <- matrix(c( c(.00, .00, .00, .00), c(.00, .00, .00, .00), c(.00, .00, .00, .30), c(.00, .00, .30, .00) ), byrow = TRUE, ncol = 4) Phi <- getPhi.B(B, lPsi) ## End(Not run)
## Not run: # mediation model B <- matrix(c( c(.00, .00, .00), c(.10, .00, .00), c(.20, .30, .00) ), byrow = TRUE, ncol = 3) Phi <- getPhi.B(B) # CLPM with residual correlations B <- matrix(c( c(.00, .00, .00, .00), c(.30, .00, .00, .00), c(.70, .10, .00, .00), c(.20, .70, .00, .00) ), byrow = TRUE, ncol = 4) lPsi <- matrix(c( c(.00, .00, .00, .00), c(.00, .00, .00, .00), c(.00, .00, .00, .30), c(.00, .00, .30, .00) ), byrow = TRUE, ncol = 4) Phi <- getPhi.B(B, lPsi) ## End(Not run)
Computes the implied Psi matrix from Beta, when all coefficients in Beta should be standardized.
getPsi.B(B, sPsi = NULL, standResCov = TRUE)
getPsi.B(B, sPsi = NULL, standResCov = TRUE)
B |
matrix of regression coefficients (all-y notation). May only contain non-zero values either above or below the diagonal. |
sPsi |
matrix of (residual) correlations/covariances. This is not the Psi matrix, but defines the desired correlations/covariances beyond those implied by B. Can be NULL for no correlations. Standardized and unstandardized residual covariances (between endogenous variables) cannot have the same value, so |
standResCov |
whether elements in |
Psi
## Not run: # mediation model B <- matrix(c( c(.00, .00, .00), c(.10, .00, .00), c(.20, .30, .00) ), byrow = TRUE, ncol = 3) Psi <- getPsi.B(B) # CLPM with residual correlations B <- matrix(c( c(.00, .00, .00, .00), c(.30, .00, .00, .00), c(.70, .10, .00, .00), c(.20, .70, .00, .00) ), byrow = TRUE, ncol = 4) sPsi <- matrix(c( c(1, .00, .00, .00), c(.00, 1, .00, .00), c(.00, .00, 1, .30), c(.00, .00, .30, 1) ), byrow = TRUE, ncol = 4) # so that residual cor is std Psi <- getPsi.B(B, sPsi, standResCov = TRUE) # so that residual cor is unsstd Psi <- getPsi.B(B, sPsi, standResCov = FALSE) ## End(Not run)
## Not run: # mediation model B <- matrix(c( c(.00, .00, .00), c(.10, .00, .00), c(.20, .30, .00) ), byrow = TRUE, ncol = 3) Psi <- getPsi.B(B) # CLPM with residual correlations B <- matrix(c( c(.00, .00, .00, .00), c(.30, .00, .00, .00), c(.70, .10, .00, .00), c(.20, .70, .00, .00) ), byrow = TRUE, ncol = 4) sPsi <- matrix(c( c(1, .00, .00, .00), c(.00, 1, .00, .00), c(.00, .00, 1, .30), c(.00, .00, .30, 1) ), byrow = TRUE, ncol = 4) # so that residual cor is std Psi <- getPsi.B(B, sPsi, standResCov = TRUE) # so that residual cor is unsstd Psi <- getPsi.B(B, sPsi, standResCov = FALSE) ## End(Not run)
Computes RMSEA from the minimum of the ML-fit-function
F_min = rmsea^2 * df
.
getRMSEA.F(Fmin, df, nGroups = 1)
getRMSEA.F(Fmin, df, nGroups = 1)
Fmin |
minimum of the ML-fit-function |
df |
model degrees of freedom |
nGroups |
the number of groups |
Returns RMSEA
Computes SRMR given the model-implied and the observed (or population) covariance matrix, using the Hu & Bentler approach to standardization.
getSRMR.Sigma(SigmaHat, S, muHat = NULL, mu = NULL)
getSRMR.Sigma(SigmaHat, S, muHat = NULL, mu = NULL)
SigmaHat |
model implied covariance matrix |
S |
observed (or population) covariance matrix |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
Returns SRMR
Computes SRMR given the model-implied and the observed (or population) covariance matrix for multiple group models using the Hu & Bentler approach to standardization and the MPlus approach to multiple group sampling weights (weight squared sums of residuals).
getSRMR.Sigma.mgroups(SigmaHat, S, muHat = NULL, mu = NULL, N)
getSRMR.Sigma.mgroups(SigmaHat, S, muHat = NULL, mu = NULL, N)
SigmaHat |
a list of model implied covariance matrices |
S |
a list of observed (or population) covariance matrices |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
N |
a list of group weights |
Returns SRMR
Computes the WLS weight matrix as the asymptotic covariance matrix of the sample statistics
getWLSv(S, mu = NULL, diag = FALSE)
getWLSv(S, mu = NULL, diag = FALSE)
S |
observed (or population) covariance matrix |
mu |
observed (or population) mean vector |
diag |
weight matrix for DWLS |
Returns V
This function is currently orphaned, but we keep it just in case.
makeRestrictionsLavFriendly(model)
makeRestrictionsLavFriendly(model)
model |
|
This function transforms a lavaan
model string into a model string that works reliably
when both equality constrains and value constrains are imposed on the same parameters.
lavaan
cannot reliably handle this case, e. g., "a == b \\n a == 0"
will not always work.
The solution is to drop the equality constraint and rather apply
the value constraint on each equality constrained parameter, e. g. "a == 0 \n b == 0"
will work.
model with lavaan
-friendly constrains
returns lavaan
implied covariance matrix in correct order.
orderLavCov(lavCov = NULL)
orderLavCov(lavCov = NULL)
lavCov |
model implied covariance matrix |
cov in correct order
returns lavaan
implied means in correct order.
orderLavMu(lavMu = NULL)
orderLavMu(lavMu = NULL)
lavMu |
model implied means |
mu in correct order
returns lavaan
implied covariance matrix or mean vector in correct order.
orderLavResults(lavCov = NULL, lavMu = NULL)
orderLavResults(lavCov = NULL, lavMu = NULL)
lavCov |
model implied covariance matrix |
lavMu |
model implied means |
either cov or mu in correct order
Performs some preparations common to all types of power analyses.
powerPrepare( type = NULL, effect = NULL, effect.measure = NULL, alpha = NULL, beta = NULL, power = NULL, abratio = NULL, N = NULL, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, nReplications = NULL, minConvergenceRate = NULL, lavOptions = NULL )
powerPrepare( type = NULL, effect = NULL, effect.measure = NULL, alpha = NULL, beta = NULL, power = NULL, abratio = NULL, N = NULL, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, nReplications = NULL, minConvergenceRate = NULL, lavOptions = NULL )
type |
type of power analysis |
effect |
effect size specifying the discrepancy between H0 and H1 (a list for multiple group models; a vector of length 2 for effect-size differences) |
effect.measure |
type of effect, one of |
alpha |
alpha error |
beta |
beta error; set either beta or power |
power |
power (=1 - beta); set either beta or power |
abratio |
the ratio of alpha to beta |
N |
the number of observations (a list for multiple group models) |
df |
the model degrees of freedom |
p |
the number of observed variables, required for |
SigmaHat |
model implied covariance matrix (a list for multiple group models). Use in conjunction with |
Sigma |
observed (or population) covariance matrix (a list for multiple group models). Use in conjunction with |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
fittingFunction |
one of |
simulatedPower |
whether to perform a simulated ( |
modelH0 |
for simulated power: |
nReplications |
for simulated power: number of random samples drawn. |
minConvergenceRate |
for simulated power: the minimum convergence rate required |
lavOptions |
for simulated power: a list of additional options passed to |
list
semPower allows for performing a-priori, post-hoc, and compromise power-analyses for structural equation models (SEM).
Perform a power analysis. This is a wrapper function for a-priori, post-hoc, and compromise power analyses.
semPower(type, ...)
semPower(type, ...)
type |
type of power analysis, one of |
... |
other parameters related to the specific type of power analysis requested. |
A-priori power analysis semPower.aPriori
computes the required N, given an effect, alpha, power, and the model df
Post-hoc power analysis semPower.postHoc
computes the achieved power, given an effect, alpha, N, and the model df
Compromise power analysis semPower.compromise
computes the implied alpha and power, given an effect, the alpha/beta ratio, N, and the model df
In SEM, the discrepancy between H0 and H1 (the magnitude of effect) refers to the difference in fit between two models. If only one model is defined (which is the default), power refers to the global chi-square test. If both models are explicitly defined, power is computed for nested model tests. semPower allows for expressing the magnitude of effect by one of the following measures: F0, RMSEA, Mc, GFI, or AGFI.
Alternatively, the implied effect can also be computed from the discrepancy between the population (or a certain model-implied) covariance matrix defining H0 and the hypothesized (model-implied) covariance matrix from a nested model defining H1. See the examples below how to use this feature in conjunction with lavaan.
list
Morten Moshagen [email protected]
Useful links:
semPower.aPriori()
, semPower.postHoc()
, semPower.compromise()
# a-priori power analyses using rmsea = .05 a target power (1-beta) of .80 ap1 <- semPower.aPriori(0.05, 'RMSEA', alpha = .05, beta = .20, df = 200) summary(ap1) # generic version gap1 <- semPower(type = 'a-priori', 0.05, 'RMSEA', alpha = .05, beta = .20, df = 200) summary(gap1) # a-priori power analyses using f0 = .75 and a target power of .95 ap2 <- semPower.aPriori(0.75, 'F0', alpha = .05, power = .95, df = 200) summary(ap2) # create a plot showing how power varies by N (given a certain effect) semPower.powerPlot.byN(.05, 'RMSEA', alpha=.05, df=200, power.min=.05, power.max=.99) # post-hoc power analyses using rmsea = .08 ph <- semPower.postHoc(.08, 'RMSEA', alpha = .05, N = 250, df = 50) summary(ph) # generic version gph1 <- semPower(type = 'post-hoc', .08, 'RMSEA', alpha = .05, N = 250, df = 50) summary(gph1) # create a plot showing how power varies by the magnitude of effect (given a certain N) semPower.powerPlot.byEffect('RMSEA', alpha=.05, N = 100, df=200, effect.min=.001, effect.max=.10) # compromise power analyses using rmsea = .08 and an abratio of 2 cp <- semPower.compromise(.08, 'RMSEA', abratio = 2, N = 1000, df = 200) summary(cp) # generic version gcp <- semPower(type = 'compromise', .08, 'RMSEA', abratio = 2, N = 1000, df = 200) summary(gcp) # use lavaan to define effect through covariance matrices: ## Not run: library(lavaan) # define population model (= H1) model.pop <- ' f1 =~ .8*x1 + .7*x2 + .6*x3 f2 =~ .7*x4 + .6*x5 + .5*x6 f1 ~~ 1*f1 f2 ~~ 1*f2 f1 ~~ 0.5*f2 ' # define (wrong) H0 model model.h0 <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f1 ~~ 0*f2 ' # get population covariance matrix; equivalent to a perfectly fitting H1 model cov.h1 <- fitted(sem(model.pop))$cov # get covariance matrix as implied by H0 model res.h0 <- sem(model.h0, sample.cov = cov.h1, sample.nobs = 1000, likelihood='wishart', sample.cov.rescale = F) df <- res.h0@test[[1]]$df cov.h0 <- fitted(res.h0)$cov ## do power analyses # post-hoc ph <- semPower.postHoc(SigmaHat = cov.h0, Sigma = cov.h1, alpha = .05, N = 1000, df = df) summary(ph) # => Power to reject the H1 model is > .9999 (1-beta = 1-1.347826e-08) with N = 1000 at alpha=.05 # compare: ph$fmin * (ph$N-1) fitmeasures(res.h1, 'chisq') # => expected chi-square matches empirical chi-square # a-priori ap <- semPower.aPriori(SigmaHat = cov.h0, Sigma = cov.h1, alpha = .05, power = .80, df = df) summary(ap) # => N = 194 gives a power of ~80% to reject the H1 model at alpha = .05 # compromise cp <- semPower.compromise(SigmaHat = cov.h0, Sigma = cov.h1, abratio = 1, N = 1000, df = df) summary(cp) # => A critical Chi-Squared of 33.999 gives balanced alpha-beta # error probabilities of alpha=beta=0.000089 with N = 1000. ## End(Not run) ## Not run: ap <- semPower(type = 'a-priori', effect = .08, effect.measure = "RMSEA", alpha = .05, beta = .05, df = 200) summary(ph) ph <- semPower(type = 'post-hoc', effect = .08, effect.measure = "RMSEA", alpha = .05, N = 250, df = 200) summary(ph) cp <- semPower(type = 'compromise', effect = .08, effect.measure = "RMSEA", abratio = 1, N = 250, df = 200) summary(ph) ## End(Not run)
# a-priori power analyses using rmsea = .05 a target power (1-beta) of .80 ap1 <- semPower.aPriori(0.05, 'RMSEA', alpha = .05, beta = .20, df = 200) summary(ap1) # generic version gap1 <- semPower(type = 'a-priori', 0.05, 'RMSEA', alpha = .05, beta = .20, df = 200) summary(gap1) # a-priori power analyses using f0 = .75 and a target power of .95 ap2 <- semPower.aPriori(0.75, 'F0', alpha = .05, power = .95, df = 200) summary(ap2) # create a plot showing how power varies by N (given a certain effect) semPower.powerPlot.byN(.05, 'RMSEA', alpha=.05, df=200, power.min=.05, power.max=.99) # post-hoc power analyses using rmsea = .08 ph <- semPower.postHoc(.08, 'RMSEA', alpha = .05, N = 250, df = 50) summary(ph) # generic version gph1 <- semPower(type = 'post-hoc', .08, 'RMSEA', alpha = .05, N = 250, df = 50) summary(gph1) # create a plot showing how power varies by the magnitude of effect (given a certain N) semPower.powerPlot.byEffect('RMSEA', alpha=.05, N = 100, df=200, effect.min=.001, effect.max=.10) # compromise power analyses using rmsea = .08 and an abratio of 2 cp <- semPower.compromise(.08, 'RMSEA', abratio = 2, N = 1000, df = 200) summary(cp) # generic version gcp <- semPower(type = 'compromise', .08, 'RMSEA', abratio = 2, N = 1000, df = 200) summary(gcp) # use lavaan to define effect through covariance matrices: ## Not run: library(lavaan) # define population model (= H1) model.pop <- ' f1 =~ .8*x1 + .7*x2 + .6*x3 f2 =~ .7*x4 + .6*x5 + .5*x6 f1 ~~ 1*f1 f2 ~~ 1*f2 f1 ~~ 0.5*f2 ' # define (wrong) H0 model model.h0 <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f1 ~~ 0*f2 ' # get population covariance matrix; equivalent to a perfectly fitting H1 model cov.h1 <- fitted(sem(model.pop))$cov # get covariance matrix as implied by H0 model res.h0 <- sem(model.h0, sample.cov = cov.h1, sample.nobs = 1000, likelihood='wishart', sample.cov.rescale = F) df <- res.h0@test[[1]]$df cov.h0 <- fitted(res.h0)$cov ## do power analyses # post-hoc ph <- semPower.postHoc(SigmaHat = cov.h0, Sigma = cov.h1, alpha = .05, N = 1000, df = df) summary(ph) # => Power to reject the H1 model is > .9999 (1-beta = 1-1.347826e-08) with N = 1000 at alpha=.05 # compare: ph$fmin * (ph$N-1) fitmeasures(res.h1, 'chisq') # => expected chi-square matches empirical chi-square # a-priori ap <- semPower.aPriori(SigmaHat = cov.h0, Sigma = cov.h1, alpha = .05, power = .80, df = df) summary(ap) # => N = 194 gives a power of ~80% to reject the H1 model at alpha = .05 # compromise cp <- semPower.compromise(SigmaHat = cov.h0, Sigma = cov.h1, abratio = 1, N = 1000, df = df) summary(cp) # => A critical Chi-Squared of 33.999 gives balanced alpha-beta # error probabilities of alpha=beta=0.000089 with N = 1000. ## End(Not run) ## Not run: ap <- semPower(type = 'a-priori', effect = .08, effect.measure = "RMSEA", alpha = .05, beta = .05, df = 200) summary(ph) ph <- semPower(type = 'post-hoc', effect = .08, effect.measure = "RMSEA", alpha = .05, N = 250, df = 200) summary(ph) cp <- semPower(type = 'compromise', effect = .08, effect.measure = "RMSEA", abratio = 1, N = 250, df = 200) summary(ph) ## End(Not run)
Performs an a-priori power analysis, i. e., determines the required sample size given alpha, beta (or power: 1 - beta), df, and a measure of effect.
semPower.aPriori( effect = NULL, effect.measure = NULL, alpha, beta = NULL, power = NULL, N = NULL, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, modelH1 = NULL, simOptions = NULL, lavOptions = NULL, lavOptionsH1 = lavOptions, ... )
semPower.aPriori( effect = NULL, effect.measure = NULL, alpha, beta = NULL, power = NULL, N = NULL, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, modelH1 = NULL, simOptions = NULL, lavOptions = NULL, lavOptionsH1 = lavOptions, ... )
effect |
effect size specifying the discrepancy between the null hypothesis (H0) and the alternative hypothesis (H1). A list for multiple group models; a vector of length 2 for effect-size differences. Can be |
effect.measure |
type of effect, one of |
alpha |
alpha error |
beta |
beta error; set either |
power |
power (= 1 - beta); set either |
N |
a list of sample weights for multiple group power analyses, e.g. |
df |
the model degrees of freedom. See |
p |
the number of observed variables, only required for |
SigmaHat |
can be used instead of |
Sigma |
can be used instead of |
muHat |
can be used instead of |
mu |
can be used instead of |
fittingFunction |
one of |
simulatedPower |
whether to perform a simulated ( |
modelH0 |
for simulated power: |
modelH1 |
for simulated power: |
simOptions |
a list of additional options specifying simulation details, see |
lavOptions |
a list of additional options passed to |
lavOptionsH1 |
alternative options passed to |
... |
other parameters related to plots, notably |
Returns a list. Use summary()
to obtain formatted results.
semPower.postHoc()
semPower.compromise()
## Not run: # determine the required sample size to reject a model showing misspecifications # amounting to RMSEA >= .05 on 200 df with a power of 95 % on alpha = .05 ap <- semPower.aPriori(effect = .05, effect.measure = "RMSEA", alpha = .05, beta = .05, df = 200) summary(ap) # use f0 as effect size metric ap <- semPower.aPriori(effect = .15, effect.measure = "F0", alpha = .05, power = .80, df = 200) summary(ap) # power analysis for to detect the difference between a model (with df = 200) exhibiting RMSEA = .05 # and a model (with df = 210) exhibiting RMSEA = .06. ap <- semPower.aPriori(effect = c(.05, .06), effect.measure = "RMSEA", alpha = .05, power = .80, df = c(200, 210)) summary(ap) # power analysis based on SigmaHat and Sigma (nonsense example) ap <- semPower.aPriori(alpha = .05, beta = .05, df = 5, SigmaHat = diag(4), Sigma = cov(matrix(rnorm(4*1000), ncol=4))) summary(ap) # multiple group example ap <- semPower.aPriori(effect = list(.05, .10), effect.measure = "F0", alpha = .05, power = .80, df = 100, N = list(1, 1)) summary(ap) # simulated power analysis (nonsense example) ap <- semPower.aPriori(alpha = .05, beta = .05, df = 200, SigmaHat = list(diag(4), diag(4)), Sigma = list(cov(matrix(rnorm(4*1000), ncol=4)), cov(matrix(rnorm(4*1000), ncol=4))), simulatedPower = TRUE, nReplications = 100) summary(ap) ## End(Not run)
## Not run: # determine the required sample size to reject a model showing misspecifications # amounting to RMSEA >= .05 on 200 df with a power of 95 % on alpha = .05 ap <- semPower.aPriori(effect = .05, effect.measure = "RMSEA", alpha = .05, beta = .05, df = 200) summary(ap) # use f0 as effect size metric ap <- semPower.aPriori(effect = .15, effect.measure = "F0", alpha = .05, power = .80, df = 200) summary(ap) # power analysis for to detect the difference between a model (with df = 200) exhibiting RMSEA = .05 # and a model (with df = 210) exhibiting RMSEA = .06. ap <- semPower.aPriori(effect = c(.05, .06), effect.measure = "RMSEA", alpha = .05, power = .80, df = c(200, 210)) summary(ap) # power analysis based on SigmaHat and Sigma (nonsense example) ap <- semPower.aPriori(alpha = .05, beta = .05, df = 5, SigmaHat = diag(4), Sigma = cov(matrix(rnorm(4*1000), ncol=4))) summary(ap) # multiple group example ap <- semPower.aPriori(effect = list(.05, .10), effect.measure = "F0", alpha = .05, power = .80, df = 100, N = list(1, 1)) summary(ap) # simulated power analysis (nonsense example) ap <- semPower.aPriori(alpha = .05, beta = .05, df = 200, SigmaHat = list(diag(4), diag(4)), Sigma = list(cov(matrix(rnorm(4*1000), ncol=4)), cov(matrix(rnorm(4*1000), ncol=4))), simulatedPower = TRUE, nReplications = 100) summary(ap) ## End(Not run)
Performs a compromise power analysis, i. e., determines the critical chi-square along with the implied alpha error and beta error , given the alpha/beta ratio, a measure of effect, N, and df
semPower.compromise( effect = NULL, effect.measure = NULL, abratio = 1, N, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", ... )
semPower.compromise( effect = NULL, effect.measure = NULL, abratio = 1, N, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", ... )
effect |
effect size specifying the discrepancy between the null hypothesis (H0) and the alternative hypothesis (H1). A list for multiple group models; a vector of length 2 for effect-size differences. Can be |
effect.measure |
type of effect, one of |
abratio |
the ratio of alpha to beta |
N |
the number of observations (a list for multiple group models) |
df |
the model degrees of freedom. See |
p |
the number of observed variables, only required for |
SigmaHat |
can be used instead of |
Sigma |
can be used instead of |
muHat |
can be used instead of |
mu |
can be used instead of |
fittingFunction |
one of |
... |
other parameters related to plots, notably |
Returns a list. Use summary()
to obtain formatted results.
semPower.aPriori()
semPower.postHoc()
## Not run: # determine the critical value such that alpha = beta when distinguishing a model # involving 200 df exhibiting an RMSEA >= .08 from a perfectly fitting model. cp <- semPower.compromise(effect = .08, effect.measure = "RMSEA", abratio = 1, N = 250, df = 200) summary(cp) ## End(Not run)
## Not run: # determine the critical value such that alpha = beta when distinguishing a model # involving 200 df exhibiting an RMSEA >= .08 from a perfectly fitting model. cp <- semPower.compromise(effect = .08, effect.measure = "RMSEA", abratio = 1, N = 250, df = 200) summary(cp) ## End(Not run)
Generate a covariance matrix (and a mean vector) and associated lavaan
model strings based on CFA or SEM model matrices.
semPower.genSigma( Lambda = NULL, Phi = NULL, Beta = NULL, Psi = NULL, Theta = NULL, tau = NULL, Alpha = NULL, ... )
semPower.genSigma( Lambda = NULL, Phi = NULL, Beta = NULL, Psi = NULL, Theta = NULL, tau = NULL, Alpha = NULL, ... )
Lambda |
factor loading matrix. A list for multiple group models. Can also be specified using various shortcuts, see |
Phi |
for CFA models, factor correlation (or covariance) matrix or single number giving the correlation between all factors or |
Beta |
for SEM models, matrix of regression slopes between latent variables (all-y notation). A list for multiple group models. |
Psi |
for SEM models, variance-covariance matrix of latent residuals when |
Theta |
variance-covariance matrix between manifest residuals. If |
tau |
vector of intercepts. If |
Alpha |
vector of factor means. If |
... |
other |
This function generates the variance-covariance matrix of the observed variables
and their means
via a confirmatory factor (CFA) model or a more general structural equation model.
In the CFA model,
where is the
loading matrix,
is the variance-covariance matrix of the
factors, and
is the residual variance-covariance matrix of the observed variables. The means are
with the indicator intercepts
and the
factor means
.
In the structural equation model,
where is the
matrix containing the regression slopes and
is the (residual) variance-covariance matrix of the
factors. The means are
In either model, the meanstructure can be omitted, leading to factors with zero means and zero intercepts.
When , the models above do not contain any factors and reduce to ordinary regression or path models.
If Phi
is defined, a CFA model is used, if Beta
is defined, a structural equation model.
When both Phi
and Beta
are NULL
, a CFA model is used with , i. e., uncorrelated factors.
When
Phi
is a single number, all factor correlations are equal to this number.
When Beta
is defined and Psi
is NULL
, .
When Theta
is NULL
, is a diagonal matrix with all elements such that the variances of the observed variables are 1. When there is only a single observed indicator for a factor, the corresponding element in
is set to zero.
Instead of providing the loading matrix via
Lambda
, there are several shortcuts (see genLambda()
):
loadings
: defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading in the second factor by .8, .6, .6, and .4.
nIndicator
: used in conjunction with loadM
or loadMinmax
, defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: defines the mean loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the mean loadings of the first factor to equal .5 and those of the second factor do equal .6
loadSD
: used in conjunction with loadM
, defines the standard deviations of the loadings. If omitted or NULL, the standard deviations are zero. Otherwise, the loadings are sampled from a normal distribution with N(loadM, loadSD) for each factor.
loadMinMax
: defines the minimum and maximum loading either for all factors or separately for each factor (as a list). The loadings are then sampled from a uniform distribution. For example, loadMinMax = list(c(.4, .6), c(.4, .8))
defines the loadings for the first factor lying between .4 and .6, and those for the second factor between .4 and .8.
Returns a list (or list of lists for multiple group models) containing the following components:
Sigma |
implied variance-covariance matrix. |
mu |
implied means |
Lambda |
loading matrix |
Phi |
covariance matrix of latent variables |
Beta |
matrix of regression slopes |
Psi |
residual covariance matrix of latent variables |
Theta |
residual covariance matrix of observed variables |
tau |
intercepts |
Alpha |
factor means |
modelPop |
|
modelTrue |
|
modelTrueCFA |
|
## Not run: # single factor model with five indicators each loading by .5 gen <- semPower.genSigma(nIndicator = 5, loadM = .5) gen$Sigma # implied covariance matrix gen$modelTrue # analysis model string gen$modelPop # population model string # orthogonal two factor model with four and five indicators each loading by .5 gen <- semPower.genSigma(nIndicator = c(4, 5), loadM = .5) # correlated (r = .25) two factor model with # four indicators loading by .7 on the first factor # and five indicators loading by .6 on the second factor gen <- semPower.genSigma(Phi = .25, nIndicator = c(4, 5), loadM = c(.7, .6)) # correlated three factor model with variying indicators and loadings, # factor correlations according to Phi Phi <- matrix(c( c(1.0, 0.2, 0.5), c(0.2, 1.0, 0.3), c(0.5, 0.3, 1.0) ), byrow = TRUE, ncol = 3) gen <- semPower.genSigma(Phi = Phi, nIndicator = c(3, 4, 5), loadM = c(.7, .6, .5)) # same as above, but using a factor loadings matrix Lambda <- matrix(c( c(0.8, 0.0, 0.0), c(0.7, 0.0, 0.0), c(0.6, 0.0, 0.0), c(0.0, 0.7, 0.0), c(0.0, 0.8, 0.0), c(0.0, 0.5, 0.0), c(0.0, 0.4, 0.0), c(0.0, 0.0, 0.5), c(0.0, 0.0, 0.4), c(0.0, 0.0, 0.6), c(0.0, 0.0, 0.4), c(0.0, 0.0, 0.5) ), byrow = TRUE, ncol = 3) gen <- semPower.genSigma(Phi = Phi, Lambda = Lambda) # same as above, but using a reduced loading matrix, i. e. # only define the primary loadings for each factor loadings <- list( c(0.8, 0.7, 0.6), c(0.7, 0.8, 0.5, 0.4), c(0.5, 0.4, 0.6, 0.4, 0.5) ) gen <- semPower.genSigma(Phi = Phi, loadings = loadings) # Provide Beta for a three factor model # with 3, 4, and 5 indicators # loading by .6, 5, and .4, respectively. Beta <- matrix(c( c(0.0, 0.0, 0.0), c(0.3, 0.0, 0.0), # f2 = .3*f1 c(0.2, 0.4, 0.0) # f3 = .2*f1 + .4*f2 ), byrow = TRUE, ncol = 3) gen <- semPower.genSigma(Beta = Beta, nIndicator = c(3, 4, 5), loadM = c(.6, .5, .4)) # two group example: # correlated two factor model (r = .25 and .35 in the first and second group, # respectively) # the first factor is indicated by four indicators loading by .7 in the first # and .5 in the second group, # the second factor is indicated by five indicators loading by .6 in the first # and .8 in the second group, # all item intercepts are zero in both groups, # the latent means are zero in the first group # and .25 and .10 in the second group. gen <- semPower.genSigma(Phi = list(.25, .35), nIndicator = list(c(4, 5), c(4, 5)), loadM = list(c(.7, .6), c(.5, .8)), tau = list(rep(0, 9), rep(0, 9)), Alpha = list(c(0, 0), c(.25, .10)) ) gen[[1]]$Sigma # implied covariance matrix group 1 gen[[2]]$Sigma # implied covariance matrix group 2 gen[[1]]$mu # implied means group 1 gen[[2]]$mu # implied means group 2 ## End(Not run)
## Not run: # single factor model with five indicators each loading by .5 gen <- semPower.genSigma(nIndicator = 5, loadM = .5) gen$Sigma # implied covariance matrix gen$modelTrue # analysis model string gen$modelPop # population model string # orthogonal two factor model with four and five indicators each loading by .5 gen <- semPower.genSigma(nIndicator = c(4, 5), loadM = .5) # correlated (r = .25) two factor model with # four indicators loading by .7 on the first factor # and five indicators loading by .6 on the second factor gen <- semPower.genSigma(Phi = .25, nIndicator = c(4, 5), loadM = c(.7, .6)) # correlated three factor model with variying indicators and loadings, # factor correlations according to Phi Phi <- matrix(c( c(1.0, 0.2, 0.5), c(0.2, 1.0, 0.3), c(0.5, 0.3, 1.0) ), byrow = TRUE, ncol = 3) gen <- semPower.genSigma(Phi = Phi, nIndicator = c(3, 4, 5), loadM = c(.7, .6, .5)) # same as above, but using a factor loadings matrix Lambda <- matrix(c( c(0.8, 0.0, 0.0), c(0.7, 0.0, 0.0), c(0.6, 0.0, 0.0), c(0.0, 0.7, 0.0), c(0.0, 0.8, 0.0), c(0.0, 0.5, 0.0), c(0.0, 0.4, 0.0), c(0.0, 0.0, 0.5), c(0.0, 0.0, 0.4), c(0.0, 0.0, 0.6), c(0.0, 0.0, 0.4), c(0.0, 0.0, 0.5) ), byrow = TRUE, ncol = 3) gen <- semPower.genSigma(Phi = Phi, Lambda = Lambda) # same as above, but using a reduced loading matrix, i. e. # only define the primary loadings for each factor loadings <- list( c(0.8, 0.7, 0.6), c(0.7, 0.8, 0.5, 0.4), c(0.5, 0.4, 0.6, 0.4, 0.5) ) gen <- semPower.genSigma(Phi = Phi, loadings = loadings) # Provide Beta for a three factor model # with 3, 4, and 5 indicators # loading by .6, 5, and .4, respectively. Beta <- matrix(c( c(0.0, 0.0, 0.0), c(0.3, 0.0, 0.0), # f2 = .3*f1 c(0.2, 0.4, 0.0) # f3 = .2*f1 + .4*f2 ), byrow = TRUE, ncol = 3) gen <- semPower.genSigma(Beta = Beta, nIndicator = c(3, 4, 5), loadM = c(.6, .5, .4)) # two group example: # correlated two factor model (r = .25 and .35 in the first and second group, # respectively) # the first factor is indicated by four indicators loading by .7 in the first # and .5 in the second group, # the second factor is indicated by five indicators loading by .6 in the first # and .8 in the second group, # all item intercepts are zero in both groups, # the latent means are zero in the first group # and .25 and .10 in the second group. gen <- semPower.genSigma(Phi = list(.25, .35), nIndicator = list(c(4, 5), c(4, 5)), loadM = list(c(.7, .6), c(.5, .8)), tau = list(rep(0, 9), rep(0, 9)), Alpha = list(c(0, 0), c(.25, .10)) ) gen[[1]]$Sigma # implied covariance matrix group 1 gen[[2]]$Sigma # implied covariance matrix group 2 gen[[1]]$mu # implied means group 1 gen[[2]]$mu # implied means group 2 ## End(Not run)
Determines the degrees of freedom of a given model provided as lavaan
model string. This only returns the regular df and does not account for approaches using scaled df.
This requires the lavaan
package.
semPower.getDf(lavModel, nGroups = NULL, group.equal = NULL)
semPower.getDf(lavModel, nGroups = NULL, group.equal = NULL)
lavModel |
the |
nGroups |
for multigroup models: the number of groups. |
group.equal |
for multigroup models: vector defining the type(s) of cross-group equality constraints following the |
Returns the df of the model.
## Not run: lavModel <- ' f1 =~ x1 + x2 + x3 + x4 f2 =~ x5 + x6 + x7 + x8 f3 =~ y1 + y2 + y3 f3 ~ f1 + f2 ' semPower.getDf(lavModel) # multigroup version semPower.getDf(lavModel, nGroups = 3) semPower.getDf(lavModel, nGroups = 3, group.equal = c('loadings')) semPower.getDf(lavModel, nGroups = 3, group.equal = c('loadings', 'intercepts')) ## End(Not run)
## Not run: lavModel <- ' f1 =~ x1 + x2 + x3 + x4 f2 =~ x5 + x6 + x7 + x8 f3 =~ y1 + y2 + y3 f3 ~ f1 + f2 ' semPower.getDf(lavModel) # multigroup version semPower.getDf(lavModel, nGroups = 3) semPower.getDf(lavModel, nGroups = 3, group.equal = c('loadings')) semPower.getDf(lavModel, nGroups = 3, group.equal = c('loadings', 'intercepts')) ## End(Not run)
Performs a post-hoc power analysis, i. e., determines power (= 1 - beta) given alpha, df, and and a measure of effect.
semPower.postHoc( effect = NULL, effect.measure = NULL, alpha, N, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, modelH1 = NULL, simOptions = NULL, lavOptions = NULL, lavOptionsH1 = lavOptions, ... )
semPower.postHoc( effect = NULL, effect.measure = NULL, alpha, N, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, modelH1 = NULL, simOptions = NULL, lavOptions = NULL, lavOptionsH1 = lavOptions, ... )
effect |
effect size specifying the discrepancy between the null hypothesis (H0) and the alternative hypothesis (H1). A list for multiple group models; a vector of length 2 for effect-size differences. Can be |
effect.measure |
type of effect, one of |
alpha |
alpha error |
N |
the number of observations (a list for multiple group models) |
df |
the model degrees of freedom. See |
p |
the number of observed variables, only required for |
SigmaHat |
can be used instead of |
Sigma |
can be used instead of |
muHat |
can be used instead of |
mu |
can be used instead of |
fittingFunction |
one of |
simulatedPower |
whether to perform a simulated ( |
modelH0 |
for simulated power: |
modelH1 |
for simulated power: |
simOptions |
a list of additional options specifying simulation details, see |
lavOptions |
a list of additional options passed to |
lavOptionsH1 |
alternative options passed to |
... |
other parameters related to plots, notably |
Returns a list. Use summary()
to obtain formatted results.
semPower.aPriori()
semPower.compromise()
## Not run: # achieved power with a sample of N = 250 to detect misspecifications corresponding # to RMSEA >= .05 on 200 df on alpha = .05. ph <- semPower.postHoc(effect = .05, effect.measure = "RMSEA", alpha = .05, N = 250, df = 200) summary(ph) # power analysis for to detect the difference between a model (with df = 200) exhibiting RMSEA = .05 # and a model (with df = 210) exhibiting RMSEA = .06. ph <- semPower.postHoc(effect = c(.05, .06), effect.measure = "RMSEA", alpha = .05, N = 500, df = c(200, 210)) summary(ph) # multigroup example ph <- semPower.postHoc(effect = list(.02, .01), effect.measure = "F0", alpha = .05, N = list(250, 350), df = 200) summary(ph) # power analysis based on SigmaHat and Sigma (nonsense example) ph <- semPower.postHoc(alpha = .05, N = 1000, df = 5, SigmaHat = diag(4), Sigma = cov(matrix(rnorm(4*1000), ncol=4))) summary(ph) # simulated power analysis (nonsense example) ph <- semPower.aPriori(alpha = .05, N = 500, df = 200, SigmaHat = list(diag(4), diag(4)), Sigma = list(cov(matrix(rnorm(4*1000), ncol=4)), cov(matrix(rnorm(4*1000), ncol=4))), simulatedPower = TRUE, nReplications = 100) summary(ph) ## End(Not run)
## Not run: # achieved power with a sample of N = 250 to detect misspecifications corresponding # to RMSEA >= .05 on 200 df on alpha = .05. ph <- semPower.postHoc(effect = .05, effect.measure = "RMSEA", alpha = .05, N = 250, df = 200) summary(ph) # power analysis for to detect the difference between a model (with df = 200) exhibiting RMSEA = .05 # and a model (with df = 210) exhibiting RMSEA = .06. ph <- semPower.postHoc(effect = c(.05, .06), effect.measure = "RMSEA", alpha = .05, N = 500, df = c(200, 210)) summary(ph) # multigroup example ph <- semPower.postHoc(effect = list(.02, .01), effect.measure = "F0", alpha = .05, N = list(250, 350), df = 200) summary(ph) # power analysis based on SigmaHat and Sigma (nonsense example) ph <- semPower.postHoc(alpha = .05, N = 1000, df = 5, SigmaHat = diag(4), Sigma = cov(matrix(rnorm(4*1000), ncol=4))) summary(ph) # simulated power analysis (nonsense example) ph <- semPower.aPriori(alpha = .05, N = 500, df = 200, SigmaHat = list(diag(4), diag(4)), Sigma = list(cov(matrix(rnorm(4*1000), ncol=4)), cov(matrix(rnorm(4*1000), ncol=4))), simulatedPower = TRUE, nReplications = 100) summary(ph) ## End(Not run)
Convenience function for performing power analysis on effects in an ARMA model. This requires the lavaan package.
semPower.powerARMA( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, autoregLag1 = autoregEffects, autoregLag2 = NULL, autoregLag3 = NULL, mvAvgLag1 = NULL, mvAvgLag2 = NULL, mvAvgLag3 = NULL, means = NULL, variances = NULL, waveEqual = NULL, groupEqual = NULL, nullEffect = NULL, nullWhich = NULL, nullWhichGroups = NULL, invariance = TRUE, autocorResiduals = TRUE, ... )
semPower.powerARMA( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, autoregLag1 = autoregEffects, autoregLag2 = NULL, autoregLag3 = NULL, mvAvgLag1 = NULL, mvAvgLag2 = NULL, mvAvgLag3 = NULL, means = NULL, variances = NULL, waveEqual = NULL, groupEqual = NULL, nullEffect = NULL, nullWhich = NULL, nullWhichGroups = NULL, invariance = TRUE, autocorResiduals = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
nWaves |
number of waves, must be >= 2. |
autoregEffects |
vector of the lag-1 autoregressive effects, e.g. |
autoregLag1 |
alternative name for autoregEffects. |
autoregLag2 |
vector of lag-2 effects, e.g. |
autoregLag3 |
vector of lag-3 effects, e.g. |
mvAvgLag1 |
vector of the lag-1 moving average parameters, e.g. |
mvAvgLag2 |
vector of the lag-2 moving average parameters, e.g. |
mvAvgLag3 |
vector of the lag-3 moving average parameters, e.g. |
means |
vector of means of |
variances |
vector of variances of the noise factors |
waveEqual |
parameters that are assumed to be equal across waves in both the H0 and the H1 model. Because ARMA models are likely not identified when no such constraints are imposed, this may not be empty. Valid are |
groupEqual |
parameters that are restricted across groups in both the H0 and the H1 model, when |
nullEffect |
defines the hypothesis of interest. Valid are the same arguments as in |
nullWhich |
used in conjunction with |
nullWhichGroups |
for hypothesis involving cross-groups comparisons, vector indicating the groups for which equality constrains should be applied, e.g. |
invariance |
whether metric invariance over waves is assumed ( |
autocorResiduals |
whether the residuals of the indicators of latent variables are autocorrelated over waves ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising
in models with autoregressive and moving average parameters (ARMA models), where one variable X
is repeatedly
assessed at different time points (nWaves
), and autoregressive (lag-1 effects; X1 -> X2 -> X3
, and optionally lag-2 and lag-3) effects,
and moving average parameters (N1 -> X2
, or equivalently for lag-2 and lag-3 effects) are assumed.
Relevant hypotheses in arising in an ARMA model are:
autoreg
: Tests the hypothesis that the autoregressive lag-1 effects are equal across waves (stationarity of autoregressive lag-1 effects).
autoregLag2
: Tests the hypothesis that the autoregressive lag-2 effects are equal across waves (stationarity of autoregressive lag-2 effects).
autoregLag3
: Tests the hypothesis that the autoregressive lag-3 effects are equal across waves (stationarity of autoregressive lag-3 effects).
mvAvg
: Tests the hypothesis that the moving average lag-1 parameters are equal across waves (stationarity of moving average lag-1 effects).
mvAvgLag2
: Tests the hypothesis that the moving average lag-2 parameters are equal across waves (stationarity of moving average lag-2 effects).
mvAvgLag3
: Tests the hypothesis that the moving average lag-3 parameters are equal across waves (stationarity of moving average lag-3 effects).
var
: Tests the hypothesis that the variances of the noise factors N (= the residual variances of X) are equal across waves 2 to nWaves (stationarity of variance).
mean
: Tests the hypothesis that the conditional means of X are equal across waves 2 to nWaves (stationarity of means).
autoreg = 0
, autoregLag2 = 0
, autoregLag3 = 0
: Tests the hypothesis that the autoregressive effects of the specified lag is zero.
mvAvg = 0
, mvAvgLag2 = 0
, mvAvgLag3 = 0
: Tests the hypothesis that the moving average parameter of the specified lag is zero.
autoregA = autoregB
: Tests the hypothesis that the autoregressive lag-1 effect is equal across groups.
mvAvgA = mvAvgB
: Tests the hypothesis that the moving average lag-1 parameter is equal across groups.
varA = varB
: Tests the hypothesis that the variance of the noise factors are equal across groups.
meanA = meanB
: Tests the hypothesis that latent means are equal across groups.
For hypotheses regarding a simple autoregression, see semPower.powerAutoreg()
. For hypotheses regarding a CLPM structure, see semPower.powerCLPM()
. For hypotheses regarding longitudinal measurement invariance, see semPower.powerLI()
.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined. Note that neither may contain the noise factors.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
The order of the factors is (X1, X2, ..., X_nWaves).
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # Determine required N in a 10-wave ARMA model # to detect that the autoregressive effects differ across waves # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave), and # the autoregressive effects vary between .5 and .7, and # the moving average parameters are .3 at each wave and # are assumed to be constant across waves (in both the H0 and the H1 model) and # there are no lagged effects, and # metric invariance and autocorrelated residuals are assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # show summary summary(powerARMA) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerARMA$modelH1, sample.cov = powerARMA$Sigma, sample.nobs = powerARMA$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerARMA$modelH0, sample.cov = powerARMA$Sigma, sample.nobs = powerARMA$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 250 on alpha = .05 powerARMA <- semPower.powerARMA( 'post-hoc', alpha = .05, N = 250, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but determine the critical chi-square with N = 250 so that alpha = beta powerARMA <- semPower.powerARMA( 'compromise', abratio = 1, N = 250, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but assume only observed variables powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', Lambda = diag(1, 10), invariance = TRUE, autocorResiduals = TRUE ) # same as above, but provide reduced loadings matrix to define that # X is measured by 3 indicators each loading by .5, .6, .4 (at each wave) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4), # X3 c(.5, .6, .4), # X4 c(.5, .6, .4), # X5 c(.5, .6, .4), # X6 c(.5, .6, .4), # X7 c(.5, .6, .4), # X8 c(.5, .6, .4), # X9 c(.5, .6, .4) # X10 ), invariance = TRUE, autocorResiduals = TRUE ) # same as above, but detect that the moving average parameters differ across waves # with a power of 80% on alpha = 5%, where # the moving average parameters vary between .05 and .4, and # the autoregressive effects are .5 at each wave and # are assumed to be constant across waves (in both the H0 and the H1 model) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), mvAvgLag1 = c(.1, .05, .2, .1, .1, .3, .4, .4, .4), variances = rep(1, 10), waveEqual = c('autoreg'), nullEffect = 'mvAvg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but detect that the (noise) variances differ across waves # with a power of 80% on alpha = 5%, where # the variances vary between 0.5 and 2, and # the autoregressive effects are .5 at each wave and # the moving average parameters are .3 at each wave and # bothj are assumed to be constant across waves (in both the H0 and the H1 model) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), mvAvgLag1 = rep(.3, 9), variances = c(1, .5, .7, .6, .7, .9, 1.2, 1.7, 2.0, 1.5), waveEqual = c('autoreg', 'mvAvg'), nullEffect = 'var', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but include a meanstructure and # detect that the means differ across waves # with a power of 80% on alpha = 5%, where # the means vary between 0 and .5, and # the autoregressive effects are .5 at each wave and # the moving average parameters are .3 at each wave and # the variances are 1 at each wave and # all are assumed to be constant across waves (in both the H0 and the H1 model) and # metric and scalar invariance is assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), means = c(0, .1, .2, .3, .4, .5, .3, .4, .5, .5), waveEqual = c('autoreg', 'mvAvg', 'var'), nullEffect = 'mean', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # Determine required N in a 10-wave ARMA model # to detect that the autoregressive lag-2 effects differ from zero # with a power of 80% on alpha = 5%, where # the lag-2 autoregressive effects are .2 at each wave and # the lag-2 autoregressive effects are .1 at each wave and # the autoregressive effects are .5 at each wave and # the moving average parameters are .3 at each wave and # the noise variances are equal to 1 in each wave, # and all are assumed to be constant across waves (in both the H0 and the H1 model) and # metric invariance and autocorrelated residuals are assumed, and # the autoregressive lag2- and lag3-effects are estimated powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), autoregLag2 = rep(.2, 8), autoregLag3 = rep(.1, 7), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg', 'autoreg', 'var', 'autoreglag2', 'autoreglag3'), nullEffect = 'autoreglag2 = 0', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # similar as above, but get required N to detect that # lag-2 moving average parameters are constant across waves powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), autoregLag2 = rep(.2, 8), mvAvgLag1 = rep(.3, 9), mvAvgLag2 = c(.1, .2, .3, .1, .2, .3, .1, .1), variances = rep(1, 10), waveEqual = c('mvAvg', 'autoreg', 'var', 'autoreglag2'), nullEffect = 'mvAvgLag2', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE ) # Determine required N in a 5-wave ARMA model # to detect that the autoregressive effects in group 1 # differ from the ones in group 2, where # both groups are equal-sized # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the autoregressive effects in group 1 are .5 (constant across waves) and # the autoregressive effects in group 2 are .6 (constant across waves) and # the moving average parameters are .25 at each wave and in both groups and # the variances are 1 at each wave and in both groups and # all are assumed to be constant across waves (in both the H0 and the H1 model) # metric invariance (across both waves and groups) and # autocorrelated residuals are assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 5, autoregLag1 = list( c(.5, .5, .5, .5), # group 1 c(.6, .6, .6, .6)), # group 2 mvAvgLag1 = rep(.25, 4), variances = rep(1, 5), waveEqual = c('autoreg', 'var', 'mvavg'), nullEffect = 'autoregA = autoregB', nIndicator = rep(3, 5), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # Determine required N in a 5-wave ARMA model # to detect that the means in group 1 # differ from the means in group 2, where # both groups are equal-sized # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the autoregressive effects are .5 at each wave and in both groups and # the moving average parameters are .25 at each wave and in both groups and # the variances are 1 at each wave and in both groups and # all are assumed to be constant across waves (in both the H0 and the H1 model) and # invariance of variances, autoregressive effects, and moving average parameters # across groups as well as # metric and scalar invariance (across both waves and groups) and # autocorrelated residuals are assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 5, autoregLag1 = list( c(.5, .5, .5, .5), # group 1 c(.5, .5, .5, .5)), # group 2 mvAvgLag1 = rep(.25, 4), variances = rep(1, 5), means = list( c(0, .1, .1, .1, .1), # group 1 c(0, .4, .4, .4, .4) # group 2 ), waveEqual = c('autoreg', 'var', 'mvavg', 'mean'), groupEqual = c('var', 'autoreg', 'mvavg'), nullEffect = 'meanA = meanB', nIndicator = rep(3, 5), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # perform a simulated post-hoc power analysis # with 250 replications set.seed(300121) powerARMA <- semPower.powerARMA( 'post-hoc', alpha = .05, N = 500, nWaves = 5, autoregLag1 = c(.3, .7, .6, .3), mvAvgLag1 = rep(.3, 4), variances = rep(1, 5), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 5), loadM = .5, invariance = TRUE, autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 250) ) ## End(Not run)
## Not run: # Determine required N in a 10-wave ARMA model # to detect that the autoregressive effects differ across waves # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave), and # the autoregressive effects vary between .5 and .7, and # the moving average parameters are .3 at each wave and # are assumed to be constant across waves (in both the H0 and the H1 model) and # there are no lagged effects, and # metric invariance and autocorrelated residuals are assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # show summary summary(powerARMA) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerARMA$modelH1, sample.cov = powerARMA$Sigma, sample.nobs = powerARMA$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerARMA$modelH0, sample.cov = powerARMA$Sigma, sample.nobs = powerARMA$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 250 on alpha = .05 powerARMA <- semPower.powerARMA( 'post-hoc', alpha = .05, N = 250, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but determine the critical chi-square with N = 250 so that alpha = beta powerARMA <- semPower.powerARMA( 'compromise', abratio = 1, N = 250, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but assume only observed variables powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', Lambda = diag(1, 10), invariance = TRUE, autocorResiduals = TRUE ) # same as above, but provide reduced loadings matrix to define that # X is measured by 3 indicators each loading by .5, .6, .4 (at each wave) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = c(.5, .7, .6, .5, .7, .6, .6, .5, .6), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg'), nullEffect = 'autoreg', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4), # X3 c(.5, .6, .4), # X4 c(.5, .6, .4), # X5 c(.5, .6, .4), # X6 c(.5, .6, .4), # X7 c(.5, .6, .4), # X8 c(.5, .6, .4), # X9 c(.5, .6, .4) # X10 ), invariance = TRUE, autocorResiduals = TRUE ) # same as above, but detect that the moving average parameters differ across waves # with a power of 80% on alpha = 5%, where # the moving average parameters vary between .05 and .4, and # the autoregressive effects are .5 at each wave and # are assumed to be constant across waves (in both the H0 and the H1 model) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), mvAvgLag1 = c(.1, .05, .2, .1, .1, .3, .4, .4, .4), variances = rep(1, 10), waveEqual = c('autoreg'), nullEffect = 'mvAvg', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but detect that the (noise) variances differ across waves # with a power of 80% on alpha = 5%, where # the variances vary between 0.5 and 2, and # the autoregressive effects are .5 at each wave and # the moving average parameters are .3 at each wave and # bothj are assumed to be constant across waves (in both the H0 and the H1 model) powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), mvAvgLag1 = rep(.3, 9), variances = c(1, .5, .7, .6, .7, .9, 1.2, 1.7, 2.0, 1.5), waveEqual = c('autoreg', 'mvAvg'), nullEffect = 'var', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # same as above, but include a meanstructure and # detect that the means differ across waves # with a power of 80% on alpha = 5%, where # the means vary between 0 and .5, and # the autoregressive effects are .5 at each wave and # the moving average parameters are .3 at each wave and # the variances are 1 at each wave and # all are assumed to be constant across waves (in both the H0 and the H1 model) and # metric and scalar invariance is assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), means = c(0, .1, .2, .3, .4, .5, .3, .4, .5, .5), waveEqual = c('autoreg', 'mvAvg', 'var'), nullEffect = 'mean', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # Determine required N in a 10-wave ARMA model # to detect that the autoregressive lag-2 effects differ from zero # with a power of 80% on alpha = 5%, where # the lag-2 autoregressive effects are .2 at each wave and # the lag-2 autoregressive effects are .1 at each wave and # the autoregressive effects are .5 at each wave and # the moving average parameters are .3 at each wave and # the noise variances are equal to 1 in each wave, # and all are assumed to be constant across waves (in both the H0 and the H1 model) and # metric invariance and autocorrelated residuals are assumed, and # the autoregressive lag2- and lag3-effects are estimated powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), autoregLag2 = rep(.2, 8), autoregLag3 = rep(.1, 7), mvAvgLag1 = rep(.3, 9), variances = rep(1, 10), waveEqual = c('mvAvg', 'autoreg', 'var', 'autoreglag2', 'autoreglag3'), nullEffect = 'autoreglag2 = 0', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # similar as above, but get required N to detect that # lag-2 moving average parameters are constant across waves powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, nWaves = 10, autoregLag1 = rep(.5, 9), autoregLag2 = rep(.2, 8), mvAvgLag1 = rep(.3, 9), mvAvgLag2 = c(.1, .2, .3, .1, .2, .3, .1, .1), variances = rep(1, 10), waveEqual = c('mvAvg', 'autoreg', 'var', 'autoreglag2'), nullEffect = 'mvAvgLag2', nIndicator = rep(3, 10), loadM = .5, invariance = TRUE ) # Determine required N in a 5-wave ARMA model # to detect that the autoregressive effects in group 1 # differ from the ones in group 2, where # both groups are equal-sized # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the autoregressive effects in group 1 are .5 (constant across waves) and # the autoregressive effects in group 2 are .6 (constant across waves) and # the moving average parameters are .25 at each wave and in both groups and # the variances are 1 at each wave and in both groups and # all are assumed to be constant across waves (in both the H0 and the H1 model) # metric invariance (across both waves and groups) and # autocorrelated residuals are assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 5, autoregLag1 = list( c(.5, .5, .5, .5), # group 1 c(.6, .6, .6, .6)), # group 2 mvAvgLag1 = rep(.25, 4), variances = rep(1, 5), waveEqual = c('autoreg', 'var', 'mvavg'), nullEffect = 'autoregA = autoregB', nIndicator = rep(3, 5), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # Determine required N in a 5-wave ARMA model # to detect that the means in group 1 # differ from the means in group 2, where # both groups are equal-sized # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the autoregressive effects are .5 at each wave and in both groups and # the moving average parameters are .25 at each wave and in both groups and # the variances are 1 at each wave and in both groups and # all are assumed to be constant across waves (in both the H0 and the H1 model) and # invariance of variances, autoregressive effects, and moving average parameters # across groups as well as # metric and scalar invariance (across both waves and groups) and # autocorrelated residuals are assumed powerARMA <- semPower.powerARMA( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 5, autoregLag1 = list( c(.5, .5, .5, .5), # group 1 c(.5, .5, .5, .5)), # group 2 mvAvgLag1 = rep(.25, 4), variances = rep(1, 5), means = list( c(0, .1, .1, .1, .1), # group 1 c(0, .4, .4, .4, .4) # group 2 ), waveEqual = c('autoreg', 'var', 'mvavg', 'mean'), groupEqual = c('var', 'autoreg', 'mvavg'), nullEffect = 'meanA = meanB', nIndicator = rep(3, 5), loadM = .5, invariance = TRUE, autocorResiduals = TRUE ) # perform a simulated post-hoc power analysis # with 250 replications set.seed(300121) powerARMA <- semPower.powerARMA( 'post-hoc', alpha = .05, N = 500, nWaves = 5, autoregLag1 = c(.3, .7, .6, .3), mvAvgLag1 = rep(.3, 4), variances = rep(1, 5), waveEqual = c('mvAvg'), nullEffect = 'autoreg', nIndicator = rep(3, 5), loadM = .5, invariance = TRUE, autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 250) ) ## End(Not run)
Convenience function for performing power analysis on effects in an autoregressive model. This requires the lavaan package.
semPower.powerAutoreg( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, lag1Effects = autoregEffects, lag2Effects = NULL, lag3Effects = NULL, means = NULL, variances = NULL, waveEqual = NULL, nullEffect = NULL, nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, invariance = TRUE, autocorResiduals = TRUE, ... )
semPower.powerAutoreg( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, lag1Effects = autoregEffects, lag2Effects = NULL, lag3Effects = NULL, means = NULL, variances = NULL, waveEqual = NULL, nullEffect = NULL, nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, invariance = TRUE, autocorResiduals = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
nWaves |
number of waves, must be >= 2. |
autoregEffects |
vector of the autoregressive effects, e.g. |
lag1Effects |
alternative name for |
lag2Effects |
vector of lag-2 effects, e.g. |
lag3Effects |
vector of lag-3 effects, e.g. |
means |
vector of means for |
variances |
vector of (residual-)variances for |
waveEqual |
parameters that are assumed to be equal across waves in both the H0 and the H1 model. Valid are |
nullEffect |
defines the hypothesis of interest. Valid are the same arguments as in |
nullWhich |
used in conjunction with |
nullWhichGroups |
for hypothesis involving cross-groups comparisons, vector indicating the groups for which equality constrains should be applied, e.g. |
standardized |
whether all parameters should be standardized ( |
invariance |
whether metric invariance over waves is assumed ( |
autocorResiduals |
whether the residuals of the indicators of latent variables are autocorrelated over waves ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising
in simple autoregressive (simplex) models, where one variable is repeatedly
assessed at two or more different time points (nWaves
), yielding
autoregressive effects (aka lag-1 effects or stabilities, ; X1 -> X2 -> X3
), and optionally
lagged effects (X1 -> X3
), variances, and means.
Relevant hypotheses in arising in an autogressive model are:
autoreg
or lag1
: Tests the hypothesis that the autoregressive (lag-1) effects are equal across waves (stationarity of autoregressive parameters).
lag2
: Tests the hypothesis that the lag-2 effects are equal across waves (stationarity of lag-2 effects).
lag3
: Tests the hypothesis that the lag-3 effects are equal across waves (stationarity of lag-3 effects).
var
: Tests the hypothesis that the residual-variances of X (i.e., X_2, ..., X_nWaves) are equal across waves (stationarity of variance).
mean
: Tests the hypothesis that the conditional means of X (i.e., X_2, ..., X_nWaves) are equal across waves (stationarity of means).
autoreg = 0
or lag1 = 0
: Tests the hypothesis that the autoregressive (lag-1) effect of X is zero.
lag2 = 0
and lag3 = 0
: Tests the hypothesis that a lag-2 or a lag-3 effect is zero.
autoregA = autoregB
or lag1A = lag1B
: : Tests the hypothesis that the autoregressive effect of X is equal across groups.
For hypotheses in an ARMA model, see semPower.powerARMA()
. For hypotheses regarding a CLPM structure, see semPower.powerCLPM()
. For hypotheses regarding longitudinal measurement invariance, see semPower.powerLI()
.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
Note that the order of the factors is (X1, X2, ..., X_nWaves).
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # Determine required N in a 4-wave autoregressive model # to detect an autoregressive effect between X1 -> X2 of >= .5 # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave), and # the autoregressive effecst are .5 (X1 -> X2), .7 (X2 -> X3), and .6 (X3 -> X4), and # there are no lagged effects, and # metric invariance and autocorrelated residuals are assumed powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # show summary summary(powerAutoreg) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerAutoreg$modelH1, sample.cov = powerAutoreg$Sigma, sample.nobs = powerAutoreg$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerAutoreg$modelH0, sample.cov = powerAutoreg$Sigma, sample.nobs = powerAutoreg$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 250 on alpha = .05 powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but determine the critical chi-square with N = 250 so that alpha = beta powerAutoreg <- semPower.powerAutoreg( 'compromise', abratio = 1, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, comparison = 'saturated', nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but assume only observed variables powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, Lambda = diag(4)) # same as above, but provide reduced loadings matrix to define that # X is measured by 3 indicators each loading by .8, .6, .7 (at each wave) powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, loadings = list( c(.8, .6, .7), # X1 c(.8, .6, .7), # X2 c(.8, .6, .7), # X3 c(.8, .6, .7) # X4 ), invariance = TRUE, autocorResiduals = TRUE) # same as above, but assume wave-constant autoregressive effects powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), waveEqual = c('autoreg'), nullEffect = 'autoreg=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but detect that autoregressive effects are not wave-constant powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .7, .8), nullEffect = 'autoreg', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but include lag-2 and lag-3 effects powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .20), lag3Effects = c(.15), waveEqual = c('autoreg'), nullEffect = 'autoreg=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but detect that first lag-2 effect differs from zero powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .20), lag3Effects = c(.15), waveEqual = c('autoreg'), nullEffect = 'lag2=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but assume wave-constant lag2 effects powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .25), lag3Effects = c(.15), waveEqual = c('autoreg', 'lag2'), nullEffect = 'lag2=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but detect that lag3 effect differs from zero powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .25), lag3Effects = c(.15), waveEqual = c('autoreg', 'lag2'), nullEffect = 'lag3=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # Determine required N in a 3-wave autoregressive model # assuming wave-constant autoregressive effects # that the autoregressive effects in group 1 # differ from those in group 2 # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the autoregressive effect is .7 in group 1 and # the autoregressive effect is .5 in group 2 and # there are no lagged effects, and # metric invariance over both time and groups and autocorrelated residuals are assumed and # the groups are equal-sized powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 3, autoregEffects = list( c(.7, .7), c(.5, .5) ), waveEqual = c('autoreg'), nullEffect = 'autoregA = autoregB', nullWhich = 1, nIndicator = rep(3, 3), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # Determine required N in a 4-wave autoregressive model # to detect that the factor residual-variances (X2, X3, X4) differ # with a power of 80% on alpha = 5%, where # the (residual-)variances are 1, .5, 1.5, and 1, respectively, # X is measured by 3 indicators loading by .5 each (at each wave), and # the autoregressive effects are .6, and # both the H0 and the H1 assume wave-constant autoregressive effects, and # there are no lagged effects, and # metric invariance and autocorrelated residuals are assumed powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), variances = c(1, .5, 1.5, 1), waveEqual = c('autoreg'), nullEffect = 'var', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, standardized = FALSE, invariance = TRUE, autocorResiduals = TRUE) # same as above, but # include latent means and # detect that latent means differ and # assume wave-constant variances and autoregressive parameters for both H0 and H1 powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), variances = c(1, 1, 1, 1), means = c(0, .5, 1, .7), waveEqual = c('autoreg', 'var'), nullEffect = 'mean', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, standardized = FALSE, invariance = TRUE, autocorResiduals = TRUE) # request a simulated post-hoc power analysis with 500 replications set.seed(300121) powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 500, nWaves = 3, autoregEffects = c(.7, .7), waveEqual = c('autoreg'), nullEffect = 'autoreg = 0', nullWhich = 1, nIndicator = rep(3, 3), loadM = .5, invariance = TRUE, autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 500) ) ## End(Not run)
## Not run: # Determine required N in a 4-wave autoregressive model # to detect an autoregressive effect between X1 -> X2 of >= .5 # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave), and # the autoregressive effecst are .5 (X1 -> X2), .7 (X2 -> X3), and .6 (X3 -> X4), and # there are no lagged effects, and # metric invariance and autocorrelated residuals are assumed powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # show summary summary(powerAutoreg) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerAutoreg$modelH1, sample.cov = powerAutoreg$Sigma, sample.nobs = powerAutoreg$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerAutoreg$modelH0, sample.cov = powerAutoreg$Sigma, sample.nobs = powerAutoreg$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 250 on alpha = .05 powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but determine the critical chi-square with N = 250 so that alpha = beta powerAutoreg <- semPower.powerAutoreg( 'compromise', abratio = 1, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, comparison = 'saturated', nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but assume only observed variables powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, Lambda = diag(4)) # same as above, but provide reduced loadings matrix to define that # X is measured by 3 indicators each loading by .8, .6, .7 (at each wave) powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 250, nWaves = 4, autoregEffects = c(.5, .7, .6), nullEffect = 'autoreg=0', nullWhich = 1, loadings = list( c(.8, .6, .7), # X1 c(.8, .6, .7), # X2 c(.8, .6, .7), # X3 c(.8, .6, .7) # X4 ), invariance = TRUE, autocorResiduals = TRUE) # same as above, but assume wave-constant autoregressive effects powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), waveEqual = c('autoreg'), nullEffect = 'autoreg=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but detect that autoregressive effects are not wave-constant powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .7, .8), nullEffect = 'autoreg', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but include lag-2 and lag-3 effects powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .20), lag3Effects = c(.15), waveEqual = c('autoreg'), nullEffect = 'autoreg=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but detect that first lag-2 effect differs from zero powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .20), lag3Effects = c(.15), waveEqual = c('autoreg'), nullEffect = 'lag2=0', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but assume wave-constant lag2 effects powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .25), lag3Effects = c(.15), waveEqual = c('autoreg', 'lag2'), nullEffect = 'lag2=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # same as above, but detect that lag3 effect differs from zero powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), lag2Effects = c(.25, .25), lag3Effects = c(.15), waveEqual = c('autoreg', 'lag2'), nullEffect = 'lag3=0', nIndicator = rep(3, 4), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # Determine required N in a 3-wave autoregressive model # assuming wave-constant autoregressive effects # that the autoregressive effects in group 1 # differ from those in group 2 # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the autoregressive effect is .7 in group 1 and # the autoregressive effect is .5 in group 2 and # there are no lagged effects, and # metric invariance over both time and groups and autocorrelated residuals are assumed and # the groups are equal-sized powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 3, autoregEffects = list( c(.7, .7), c(.5, .5) ), waveEqual = c('autoreg'), nullEffect = 'autoregA = autoregB', nullWhich = 1, nIndicator = rep(3, 3), loadM = .5, invariance = TRUE, autocorResiduals = TRUE) # Determine required N in a 4-wave autoregressive model # to detect that the factor residual-variances (X2, X3, X4) differ # with a power of 80% on alpha = 5%, where # the (residual-)variances are 1, .5, 1.5, and 1, respectively, # X is measured by 3 indicators loading by .5 each (at each wave), and # the autoregressive effects are .6, and # both the H0 and the H1 assume wave-constant autoregressive effects, and # there are no lagged effects, and # metric invariance and autocorrelated residuals are assumed powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), variances = c(1, .5, 1.5, 1), waveEqual = c('autoreg'), nullEffect = 'var', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, standardized = FALSE, invariance = TRUE, autocorResiduals = TRUE) # same as above, but # include latent means and # detect that latent means differ and # assume wave-constant variances and autoregressive parameters for both H0 and H1 powerAutoreg <- semPower.powerAutoreg( 'a-priori', alpha = .05, power = .80, nWaves = 4, autoregEffects = c(.6, .6, .6), variances = c(1, 1, 1, 1), means = c(0, .5, 1, .7), waveEqual = c('autoreg', 'var'), nullEffect = 'mean', nullWhich = 1, nIndicator = rep(3, 4), loadM = .5, standardized = FALSE, invariance = TRUE, autocorResiduals = TRUE) # request a simulated post-hoc power analysis with 500 replications set.seed(300121) powerAutoreg <- semPower.powerAutoreg( 'post-hoc', alpha = .05, N = 500, nWaves = 3, autoregEffects = c(.7, .7), waveEqual = c('autoreg'), nullEffect = 'autoreg = 0', nullWhich = 1, nIndicator = rep(3, 3), loadM = .5, invariance = TRUE, autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 500) ) ## End(Not run)
Perform a power analysis for models including one or more bifactors to reject one of the following hypotheses: (a) a zero correlation between two factors, (b) the equality of two correlations between factors, or (c) the equality of a correlation between two factors across two or more groups. This requires the lavaan package.
semPower.powerBifactor( type, comparison = "restricted", bfLoadings = NULL, bfWhichFactors = NULL, Phi = NULL, nullEffect = "cor = 0", nullWhich = NULL, nullWhichGroups = NULL, ... )
semPower.powerBifactor( type, comparison = "restricted", bfLoadings = NULL, bfWhichFactors = NULL, Phi = NULL, nullEffect = "cor = 0", nullWhich = NULL, nullWhichGroups = NULL, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
bfLoadings |
a single vector or a list containing one or more vectors giving the loadings on each bifactor. For example, list(rep(.6, 10), rep(.6, 10)) defines two bifactors with 10 indicators each, loading by .6 each. Can be a list of lists for multiple group models. |
bfWhichFactors |
a list containing one or more vectors defining which (specific) factors defined in the respective arguments in ... are part of the bifactor structure. See details. |
Phi |
either a single number defining the correlation between exactly two factors or the factor correlation matrix. Must only contain the bifactor(s) and the covariate(s). Must be a list for multiple group models. Phi assumes the following order (bifactor_1, bifactor_2, ..., bifactor_j, covariate_1, covariate_2, ..., covariate_k). See details. |
nullEffect |
defines the hypothesis of interest, must be one of |
nullWhich |
vector of size 2 indicating which factor correlation in |
nullWhichGroups |
for |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising in a model including a bifactor structure:
nullEffect = 'cor = 0'
: Tests the hypothesis that the correlation between a bifactor and another factor (which can also be a bifactor) is zero.
nullEffect = 'corX = corZ'
: Tests the hypothesis that two or more correlations involving one or more bifactors are equal to each other.
nullEffect = 'corA = corB'
: Tests the hypothesis that the correlation between the bifactor and another factor (which can also be a bifactor) is equal in two or more groups (always assuming metric invariance).
A bifactor structure is defined by specifying the loadings on the general factor in bfLoadings
, the comprised specific
factors in bfWhichFactors
, and the loadings on the specific factors in either Lambda
, or loadings
,
or nIndicator
and loadM
. The latter arguments also include the loadings defining the
covariate(s).
The correlations betwen the bifactor(s) and the covariate(s) are defined in Phi
, which
must omit the specific factors and only includes the bifactor(s) and the covariate(s) assuming
the following order: (bifactor_1, bifactor_2, ..., bifactor_j, covariate_1, covariate_2, ..., covariate_k).
For example, the following defines a single bifactor with 10 indicators loading by .5 each. The bifactor structure involves 3 specific factors measured by 3 indicators each, each loading by .3, .2, and .1 on the respective specific factor (in addition to the loadings on the bifactor). Furthermore, two covariate with 5 indicators each, all loading by .7, are defined. The correlation between the covariates is .5, the one between the bifactor and the first and second covariate are .3 and .2, respectively.
bfLoadings <- rep(.5, 10) bfWhichFactors <- c(1, 2, 3) loadings <- list( rep(.3, 3), # specific factor 1 rep(.2, 3), # specific factor 2 rep(.1, 3), # specific factor 3 rep(.7, 5), # covariate 1 rep(.7, 5) # covariate 2 ) Phi <- matrix(c( c(1, .3, .2), # bifactor c(.3, 1, .5), # covariate 1 c(.2, .5, 1) # covariate 2 ), ncol = 3, byrow = TRUE)
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model concerning the specific factors and the covariate(s). The loadings on the bifactor must be provided via bfLoadings
.
Lambda
: The factor loading matrix (with the number of columns equaling the number of specific factors and covariates).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # get required N to detect a correlation of >= .3 between # a single bifactor with 11 indicators all loadings by .6 # spanning the indicators of 3 specific factors # with three indicators each, loading by .2, .15, and .25, respectively # and a covariate measured by 4 indicators loading by .7 each, # with a power of 95% on alpha = 5% bfLoadings <- rep(.6, 11) bfWhichFactors <- c(1, 2, 3) loadings <- list( # specific factors rep(.2, 3), rep(.15, 3), rep(.25, 3), # covariate rep(.7, 4) ) Phi <- .3 # bifactor - covariate powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05) # show summary summary(powerbifactor) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerbifactor$modelH1, sample.cov = powerbifactor$Sigma, sample.nobs = powerbifactor$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerbifactor$modelH0, sample.cov = powerbifactor$Sigma, sample.nobs = powerbifactor$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerbifactor <- semPower.powerBifactor(type = 'post-hoc', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerbifactor <- semPower.powerBifactor(type = 'compromise', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerbifactor <- semPower.powerBifactor(type = 'a-priori', comparison = 'saturated', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05) # define two bifactors with 10 indicators each, where # all loadings are .6 on the first and .5 on the second bifactor. # the first bifactor spans the indicators of specific factors 1-3, # the second bifactor spans the indicators of specific factors 4-6, # all specific factors are measured by three indicators each, # loadings are .2, .15, .25, .1, .15., and.2, respectively. # define an additional covariate measured by 4 indicators loading by .6 each. # get required N to detect a correlation of >= .3 between the bifactors # with a power of 95% on alpha = 5% bfLoadings <- list(rep(.6, 10), rep(.6, 10)) bfWhichFactors <- list(c(1, 2, 3), c(4, 5, 6)) loadings <- list( # specific factors for bf1 rep(.2, 3), rep(.15, 3), rep(.25, 3), # specific factors bf2 rep(.1, 3), rep(.15, 3), rep(.2, 3), # covariate rep(.6, 4) ) Phi <- diag(3) Phi[1, 2] <- Phi[2, 1] <- .3 # bifactor1 - bifactor2 Phi[1, 3] <- Phi[3, 1] <- .5 # bifactor1 - covariate Phi[2, 3] <- Phi[3, 2] <- .1 # bifactor2 - covariate powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05) # same as above, but get required N to detect that # the correlation between the first bifactor and the covariate (of r=.5) differs from # the correlation between the second bifactor and the covariate (of r=.1) powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullEffect = 'corx = corz', nullWhich = list(c(1, 3), c(2, 3)), loadings = loadings, alpha = .05, beta = .05) # multiple group example: get required N to detect that # the correlation of a bifactor with 10 indicators # spanning three specific factors with 3 indicators each # to a covariate in group 1 (of r = .3) # differs from the one in group 2 (of r = .1) bfLoadings <- rep(.6, 10) bfWhichFactors <- c(1, 2, 3) loadings <- list( # specific factors rep(.2, 3), rep(.15, 3), rep(.25, 3), # covariate rep(.7, 4) ) Phi1 <- Phi2 <- diag(2) Phi1[1, 2] <- Phi1[2, 1] <- .3 # bifactor - covariate Phi2[1, 2] <- Phi2[2, 1] <- .1 # bifactor - covariate Phi <- list(Phi1, Phi2) powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullEffect = 'corA = corB', nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications. bfLoadings <- rep(.6, 11) bfWhichFactors <- c(1, 2, 3) loadings <- list( # specific factors rep(.2, 3), rep(.15, 3), rep(.1, 3), # covariate rep(.7, 5) ) Phi <- .2 set.seed(300121) powerbifactor <- semPower.powerBifactor(type = 'post-hoc', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500) ) ## End(Not run)
## Not run: # get required N to detect a correlation of >= .3 between # a single bifactor with 11 indicators all loadings by .6 # spanning the indicators of 3 specific factors # with three indicators each, loading by .2, .15, and .25, respectively # and a covariate measured by 4 indicators loading by .7 each, # with a power of 95% on alpha = 5% bfLoadings <- rep(.6, 11) bfWhichFactors <- c(1, 2, 3) loadings <- list( # specific factors rep(.2, 3), rep(.15, 3), rep(.25, 3), # covariate rep(.7, 4) ) Phi <- .3 # bifactor - covariate powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05) # show summary summary(powerbifactor) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerbifactor$modelH1, sample.cov = powerbifactor$Sigma, sample.nobs = powerbifactor$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerbifactor$modelH0, sample.cov = powerbifactor$Sigma, sample.nobs = powerbifactor$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerbifactor <- semPower.powerBifactor(type = 'post-hoc', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerbifactor <- semPower.powerBifactor(type = 'compromise', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerbifactor <- semPower.powerBifactor(type = 'a-priori', comparison = 'saturated', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05) # define two bifactors with 10 indicators each, where # all loadings are .6 on the first and .5 on the second bifactor. # the first bifactor spans the indicators of specific factors 1-3, # the second bifactor spans the indicators of specific factors 4-6, # all specific factors are measured by three indicators each, # loadings are .2, .15, .25, .1, .15., and.2, respectively. # define an additional covariate measured by 4 indicators loading by .6 each. # get required N to detect a correlation of >= .3 between the bifactors # with a power of 95% on alpha = 5% bfLoadings <- list(rep(.6, 10), rep(.6, 10)) bfWhichFactors <- list(c(1, 2, 3), c(4, 5, 6)) loadings <- list( # specific factors for bf1 rep(.2, 3), rep(.15, 3), rep(.25, 3), # specific factors bf2 rep(.1, 3), rep(.15, 3), rep(.2, 3), # covariate rep(.6, 4) ) Phi <- diag(3) Phi[1, 2] <- Phi[2, 1] <- .3 # bifactor1 - bifactor2 Phi[1, 3] <- Phi[3, 1] <- .5 # bifactor1 - covariate Phi[2, 3] <- Phi[3, 2] <- .1 # bifactor2 - covariate powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05) # same as above, but get required N to detect that # the correlation between the first bifactor and the covariate (of r=.5) differs from # the correlation between the second bifactor and the covariate (of r=.1) powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullEffect = 'corx = corz', nullWhich = list(c(1, 3), c(2, 3)), loadings = loadings, alpha = .05, beta = .05) # multiple group example: get required N to detect that # the correlation of a bifactor with 10 indicators # spanning three specific factors with 3 indicators each # to a covariate in group 1 (of r = .3) # differs from the one in group 2 (of r = .1) bfLoadings <- rep(.6, 10) bfWhichFactors <- c(1, 2, 3) loadings <- list( # specific factors rep(.2, 3), rep(.15, 3), rep(.25, 3), # covariate rep(.7, 4) ) Phi1 <- Phi2 <- diag(2) Phi1[1, 2] <- Phi1[2, 1] <- .3 # bifactor - covariate Phi2[1, 2] <- Phi2[2, 1] <- .1 # bifactor - covariate Phi <- list(Phi1, Phi2) powerbifactor <- semPower.powerBifactor(type = 'a-priori', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullEffect = 'corA = corB', nullWhich = c(1, 2), loadings = loadings, alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications. bfLoadings <- rep(.6, 11) bfWhichFactors <- c(1, 2, 3) loadings <- list( # specific factors rep(.2, 3), rep(.15, 3), rep(.1, 3), # covariate rep(.7, 5) ) Phi <- .2 set.seed(300121) powerbifactor <- semPower.powerBifactor(type = 'post-hoc', bfLoadings = bfLoadings, bfWhichFactors = bfWhichFactors, Phi = Phi, nullWhich = c(1, 2), loadings = loadings, alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500) ) ## End(Not run)
Convenience function for performing power analyses for CFA models to reject one of the following hypotheses: (a) a zero correlation between two factors, (b) the equality of two correlations between factors, or (c) the equality of a correlation between two factors across two or more groups. This requires the lavaan package.
semPower.powerCFA( type, comparison = "restricted", Phi = NULL, nullEffect = "cor = 0", nullWhich = NULL, nullWhichGroups = NULL, ... )
semPower.powerCFA( type, comparison = "restricted", Phi = NULL, nullEffect = "cor = 0", nullWhich = NULL, nullWhichGroups = NULL, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
Phi |
either a single number defining the correlation between exactly two factors or the factor correlation matrix. A list for multiple group models. |
nullEffect |
defines the hypothesis of interest, must be one of |
nullWhich |
vector of size 2 indicating which element in Lambda should equal zero when |
nullWhichGroups |
for |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising in standard CFA models:
nullEffect = 'loading = 0'
: Tests the hypothesis that a loading is zero.
nullEffect = 'cor = 0'
: Tests the hypothesis that the correlation between two factors is zero.
nullEffect = 'corX = corZ'
: Tests the hypothesis that two or more correlations between three or more factors are equal to each other.
nullEffect = 'corA = corB'
: Tests the hypothesis that the correlation between two factors is equal in two or more groups (always assuming metric invariance).
For hypotheses regarding regression relationships between factors, see semPower.powerRegression()
.
For hypotheses regarding mediation effects, see semPower.powerMediation()
.
For hypotheses regarding measurement invariance, see semPower.powerMI()
.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
The approaches generating non-normal data require additional arguments detailed below.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # get required N to detect a correlation of >= .2 between two factors # with a power of 95% on alpha = 5%, where the factors are # measured by 5 and 6 indicators, respectively, and all loadings are equal to .5 powercfa <- semPower.powerCFA(type = 'a-priori', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, beta = .05) # show summary summary(powercfa) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powercfa$modelH1, sample.cov = powercfa$Sigma, sample.nobs = powercfa$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powercfa$modelH0, sample.cov = powercfa$Sigma, sample.nobs = powercfa$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powercfa <- semPower.powerCFA(type = 'post-hoc', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powercfa <- semPower.powerCFA(type = 'compromise', Phi = .2, nIndicator = c(5, 6), loadM = .5, abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powercfa <- semPower.powerCFA(type = 'a-priori', comparison = 'saturated', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, beta = .05) # same as above, but provide a reduced loading matrix defining # three indicators with loadings of .7, .6, and .5 on the first factor and # four indicators with loadings of .5, .6, .4, .8 on the second factor powercfa <- semPower.powerCFA(type = 'a-priori', Phi = .2, loadings = list(c(.7, .6, .5), c(.5, .6, .4, .8)), alpha = .05, beta = .05) # detect that the loading of indicator 4 on the first factor differs from zero Lambda <- matrix(c( c(.8, 0), c(.4, 0), c(.6, 0), c(.1, .5), c(0, .6), c(0, .7) ), ncol = 2, byrow = TRUE) powercfa <- semPower.powerCFA(type = 'a-priori', Phi = .2, nullEffect = 'loading = 0', nullWhich = c(4, 1), Lambda = Lambda, alpha = .05, beta = .05) # get required N to detect a correlation of >= .3 between factors 1 and 3 # in a three factor model. Factors are measured by 3 indicators each, and all loadings # on the first, second, and third factor are .5, .6, and .7, respectively. Phi <- matrix(c( c(1.00, 0.20, 0.30), c(0.20, 1.00, 0.10), c(0.30, 0.10, 1.00) ), ncol = 3,byrow = TRUE) powercfa <- semPower.powerCFA(type = 'a-priori', Phi = Phi, nullWhich = c(1, 3), nIndicator = c(3, 3, 3), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for N to detect that # the correlation between factors 1 and 2 (of r = .2) differs from # the correlation between factors 2 and 3 (of r = .3). powercfa <- semPower.powerCFA(type = 'a-priori', Phi = Phi, nullEffect = 'corX = corZ', nullWhich = list(c(1, 2), c(1, 3)), nIndicator = c(3, 3, 3), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for N to detect that all three correlations are unequal powercfa <- semPower.powerCFA(type = 'a-priori', Phi = Phi, nullEffect = 'corX = corZ', nullWhich = list(c(1, 2), c(1, 3), c(2, 3)), nIndicator = c(3, 3, 3), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # get required N to detect that the correlation between two factors # in group 1 (of r = .2) differs from the one in group 2 (of r = .4). # The measurement model is identical for both groups: # The first factor is measured by 3 indicators loading by .7 each, # the second factor is measured by 6 indicators loading by .5 each. # Both groups are sized equally (N = list(1, 1)). powercfa <- semPower.powerCFA(type = 'a-priori', nullEffect = 'corA = corB', Phi = list(.2, .4), loadM = c(.7, .5), nIndicator = c(3, 6), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications. set.seed(300121) powercfa <- semPower.powerCFA(type = 'post-hoc', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
## Not run: # get required N to detect a correlation of >= .2 between two factors # with a power of 95% on alpha = 5%, where the factors are # measured by 5 and 6 indicators, respectively, and all loadings are equal to .5 powercfa <- semPower.powerCFA(type = 'a-priori', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, beta = .05) # show summary summary(powercfa) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powercfa$modelH1, sample.cov = powercfa$Sigma, sample.nobs = powercfa$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powercfa$modelH0, sample.cov = powercfa$Sigma, sample.nobs = powercfa$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powercfa <- semPower.powerCFA(type = 'post-hoc', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powercfa <- semPower.powerCFA(type = 'compromise', Phi = .2, nIndicator = c(5, 6), loadM = .5, abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powercfa <- semPower.powerCFA(type = 'a-priori', comparison = 'saturated', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, beta = .05) # same as above, but provide a reduced loading matrix defining # three indicators with loadings of .7, .6, and .5 on the first factor and # four indicators with loadings of .5, .6, .4, .8 on the second factor powercfa <- semPower.powerCFA(type = 'a-priori', Phi = .2, loadings = list(c(.7, .6, .5), c(.5, .6, .4, .8)), alpha = .05, beta = .05) # detect that the loading of indicator 4 on the first factor differs from zero Lambda <- matrix(c( c(.8, 0), c(.4, 0), c(.6, 0), c(.1, .5), c(0, .6), c(0, .7) ), ncol = 2, byrow = TRUE) powercfa <- semPower.powerCFA(type = 'a-priori', Phi = .2, nullEffect = 'loading = 0', nullWhich = c(4, 1), Lambda = Lambda, alpha = .05, beta = .05) # get required N to detect a correlation of >= .3 between factors 1 and 3 # in a three factor model. Factors are measured by 3 indicators each, and all loadings # on the first, second, and third factor are .5, .6, and .7, respectively. Phi <- matrix(c( c(1.00, 0.20, 0.30), c(0.20, 1.00, 0.10), c(0.30, 0.10, 1.00) ), ncol = 3,byrow = TRUE) powercfa <- semPower.powerCFA(type = 'a-priori', Phi = Phi, nullWhich = c(1, 3), nIndicator = c(3, 3, 3), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for N to detect that # the correlation between factors 1 and 2 (of r = .2) differs from # the correlation between factors 2 and 3 (of r = .3). powercfa <- semPower.powerCFA(type = 'a-priori', Phi = Phi, nullEffect = 'corX = corZ', nullWhich = list(c(1, 2), c(1, 3)), nIndicator = c(3, 3, 3), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for N to detect that all three correlations are unequal powercfa <- semPower.powerCFA(type = 'a-priori', Phi = Phi, nullEffect = 'corX = corZ', nullWhich = list(c(1, 2), c(1, 3), c(2, 3)), nIndicator = c(3, 3, 3), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # get required N to detect that the correlation between two factors # in group 1 (of r = .2) differs from the one in group 2 (of r = .4). # The measurement model is identical for both groups: # The first factor is measured by 3 indicators loading by .7 each, # the second factor is measured by 6 indicators loading by .5 each. # Both groups are sized equally (N = list(1, 1)). powercfa <- semPower.powerCFA(type = 'a-priori', nullEffect = 'corA = corB', Phi = list(.2, .4), loadM = c(.7, .5), nIndicator = c(3, 6), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications. set.seed(300121) powercfa <- semPower.powerCFA(type = 'post-hoc', Phi = .2, nIndicator = c(5, 6), loadM = .5, alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
Convenience function for performing power analysis on effects in a cross-lagged panel model (CLPM). This requires the lavaan package.
semPower.powerCLPM( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, crossedEffects = NULL, rXY = NULL, waveEqual = NULL, nullEffect = NULL, nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, standardizedResidualCovariances = TRUE, metricInvariance = TRUE, autocorResiduals = TRUE, ... )
semPower.powerCLPM( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, crossedEffects = NULL, rXY = NULL, waveEqual = NULL, nullEffect = NULL, nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, standardizedResidualCovariances = TRUE, metricInvariance = TRUE, autocorResiduals = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
nWaves |
number of waves, must be >= 2. |
autoregEffects |
vector of the autoregressive effects of X and Y (constant across waves), or a list of vectors of autoregressive effects for X and Y from wave to wave, e.g. |
crossedEffects |
vector of crossed effects of X on Y |
rXY |
vector of (residual-)correlations between X and Y for each wave. If |
waveEqual |
parameters that are assumed to be equal across waves in both the H0 and the H1 model. Valid are |
nullEffect |
defines the hypothesis of interest. Valid are the same arguments as in |
nullWhich |
used in conjunction with |
nullWhichGroups |
for hypothesis involving cross-groups comparisons, vector indicating the groups for which equality constrains should be applied, e.g. |
standardized |
whether all parameters should be treated as standardized ( |
standardizedResidualCovariances |
whether the residual covariances provided in |
metricInvariance |
whether metric invariance over waves is assumed ( |
autocorResiduals |
whether the residuals of the indicators of latent variables are autocorrelated over waves ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising
in crossed-lagged panel models (CLPM). In a standard CLPM implemented here,
two variables X and Y are repeatedly assessed at two or more different time points (nWaves
), yielding
autoregressive effects (stabilities; X1 -> X2 and Y1 -> Y2),
synchronous effects (X1 <-> Y1, X2 <-> Y2), and cross-lagged effects (X1 -> Y2 and Y1 -> X2).
CLPM including more than two waves are typically implemented assuming that the parameters are constant across waves (waveEqual
), and usually omit lag-2 effects (e.g., X1 -> Y3).
CLPM based on latent factors usually assume at least metric invariance of the factors over waves (metricInvariance
).
Relevant hypotheses in arising in a CLPM are:
autoregX = 0
and autoregY = 0
: Tests the hypothesis that the autoregressive effect of X and Y, respectively, is zero.
crossedX = 0
and crossedY = 0
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) and of Y on X (crossedY
), respectively, is zero.
autoregX = autoregY
: Tests the hypothesis that the autoregressive effect of X and Y are equal.
crossedX = crossedY
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) and of Y on X (crossedY
) are equal.
autoregX
and autoregY
: Tests the hypothesis that the autoregressive effect of X and Y, respectively, is equal across waves.
crossedX
and crossedY
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) and of Y on X (crossedY
), respectively, is equal across waves.
corXY
: Tests the hypothesis that the (residual-)correlations between X and Y are equal across waves.
autoregXA = autoregXB
and autoregYA = autoregYB
: Tests the hypothesis that the autoregressive effect of either X or Y are equal across groups.
crossedXA = crossedXB
and crossedYA = crossedYB
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) or of Y on X (crossedY
), respectively, is equal across groups.
For hypotheses regarding the random-intercept CLPM, see semPower.powerRICLPM()
. For hypothesis in autoregressive models, see semPower.powerAutoreg()
.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
Note that the order of the factors is (X1, Y1, X2, Y2, ..., X_nWaves, Y_nWaves), i. e., the first factor is treated as the first measurement of X, the second as the first measurement of Y, the third as the second measurement of X, etc..
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # Determine required N in a 2-wave CLPM # to detect a crossed-effect of X (X1 -> Y2) of >= .2 # with a power of 95% on alpha = 5%, where # X1 and X2 are measured by 5 indicators loading by .5 each, and # Y1 and Y2 are measured by 3 indicators loading by .6 each, and # there is no synchronous correlation between X and Y (rXY = NULL), # the stability of X is .8, # the stability of Y is .7, and # the crossed-effect of Y (Y1 -> X2) is .1. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # show summary summary(powerCLPM) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerCLPM$modelH1, sample.cov = powerCLPM$Sigma, sample.nobs = powerCLPM$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerCLPM$modelH0, sample.cov = powerCLPM$Sigma, sample.nobs = powerCLPM$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerCLPM <- semPower.powerCLPM(type = 'post-hoc', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerCLPM <- semPower.powerCLPM(type = 'compromise', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerCLPM <- semPower.powerCLPM(type = 'compromise', comparison = 'saturated', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), abratio = 1, N = 500) # same as above, but assume only observed variables powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', Lambda = diag(4), alpha = .05, beta = .05) # same as above, but provide reduced loadings matrix to define that # X1 and X2 are measured by 5 indicators each loading by .4, .5, .6, .5, .4 # Y1 and Y2 are measured by 3 indicators each loading by .8, .6, .7 powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', loadings = list( c(.4, .5, .6, .5, .4), # X1 c(.8, .6, .7), # Y1 c(.4, .5, .6, .5, .4), # X2 c(.8, .6, .7) # Y2 ), alpha = .05, beta = .05) # same as above, but do not assume metric invariance across waves powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), metricInvariance = FALSE, alpha = .05, beta = .05) # same as above, but determine N to detect that the crossed-effect of Y (Y1 -> X2) is >= .1. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedY = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that the stability of X (X1 -> X2) is >= .8. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'autoregX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that the stability of Y (Y1 -> Y2) is >= .7. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'autoregY = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed effect of X (X1 -> Y2) of .2 differs from # the crossed effect of Y (Y1 -> X2) of .1 powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = crossedY', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the autoregressive effect of X (X1 -> X2) of .8 differs from # the autoregressive effect of Y (Y1 -> Y2) of .7 powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'autoregX = autoregY', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but assume that the synchronous correlation between X and Y # is .3 at the first wave, and the respective residual correlation is .2 at the second wave, # and determine N to detect that synchronous residual correlation (at wave 2) is => .2. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = c(.3, .2), nullEffect = 'corXY = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # Determine required N in a 3-wave CLPM # to detect a crossed-effect of X (X1 -> Y2 and X2 -> Y3) of >= .2 # with a power of 95% on alpha = 5%, where # the crossed, autoregressive, and synchronous effects of X and Y are equal over waves, # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .6 each, and # the synchronous correlation between X and Y are .2 across all three waves, and # the stability of X is .8 across all three waves, # the stability of Y is .7 across all three waves, and # the crossed-effect of Y (Y1 -> X2, and Y2 -> Y3) is .1. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = c(.2, .2, .2), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # Determine required N in a 3-wave CLPM to detect that # the crossed-effect of X in wave 1 (X1 -> Y2) of .20 is equal to the # the crossed-effect of X in wave 2 (X2 -> Y3) of .10 # with a power of 95% on alpha = 5%, where # the autoregressive effects of X and Y are equal over waves, # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .6 each, and # the synchronous correlation between X and Y are .2, .3, and .4 at the first, # second, and third wave, and # the stability of X is .8 across all three waves, # the stability of Y is .7 across all three waves, and # the crossed-effects of Y (Y1 -> X2, and Y2 -> X3) are both .1 # (but freely estimated for each wave). powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( c(.20, .10), # X1 -> Y2, X2 -> Y3 c(.05, .10)), # Y1 -> X2, Y2 -> X3 rXY = c(.2, .3, .4), nullEffect = 'crossedX', waveEqual = c('autoregX', 'autoregY'), nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed-effect of X at wave 2 is >= .10. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( c(.20, .10), # X1 -> Y2, X2 -> Y3 c(.05, .10)), # Y1 -> X2, Y2 -> X3 rXY = c(.2, .3, .4), nullEffect = 'crossedX', nullWhich = 2, waveEqual = c('autoregX', 'autoregY'), nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the residual correlation between X and Y at wave 2 (of .3) differs from # the residual correlation between X and Y at wave 3 (of .4) # and define unstandardized parameters powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( c(.20, .10), # X1 -> Y2, X2 -> Y3 c(.05, .10)), # Y1 -> X2, Y2 -> X3 rXY = c(.2, .3, .4), nullEffect = 'corXY', waveEqual = c('autoregX', 'autoregY'), standardized = FALSE, nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # multiple group example # determine power in a 3-wave CLPM to detect that # the autoregressive effect of X in group 1 (of .8) differs from the # autoregressive effect of X in group 2 (of .6) # with a 500 observations in both groups on alpha = 5%, where # the autoregressive effects of X and Y are equal over waves (but not across groups), # the cross-lagged effects of X and Y are equal over waves (and also across groups), # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .4 each, and # there are no synchronous correlation between X and Y. powerCLPM <- semPower.powerCLPM(type = 'post-hoc', alpha = .05, N = list(500, 500), nWaves = 3, autoregEffects = list( # group 1 list(c(.8, .8), # X1 -> X2, X2 -> X3 c(.7, .7)), # Y1 -> Y2, Y2 -> Y3 # group 2 list(c(.6, .6), # X1 -> X2, X2 -> X3 c(.7, .7)) # Y1 -> Y2, Y2 -> Y3 ), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, nullEffect = 'autoregxa=autoregxb', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4)) # request a simulated post-hoc power analysis with 500 replications. set.seed(300121) powerCLPM <- semPower.powerCLPM(type = 'post-hoc', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', Lambda = diag(4), alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
## Not run: # Determine required N in a 2-wave CLPM # to detect a crossed-effect of X (X1 -> Y2) of >= .2 # with a power of 95% on alpha = 5%, where # X1 and X2 are measured by 5 indicators loading by .5 each, and # Y1 and Y2 are measured by 3 indicators loading by .6 each, and # there is no synchronous correlation between X and Y (rXY = NULL), # the stability of X is .8, # the stability of Y is .7, and # the crossed-effect of Y (Y1 -> X2) is .1. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # show summary summary(powerCLPM) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerCLPM$modelH1, sample.cov = powerCLPM$Sigma, sample.nobs = powerCLPM$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerCLPM$modelH0, sample.cov = powerCLPM$Sigma, sample.nobs = powerCLPM$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerCLPM <- semPower.powerCLPM(type = 'post-hoc', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerCLPM <- semPower.powerCLPM(type = 'compromise', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerCLPM <- semPower.powerCLPM(type = 'compromise', comparison = 'saturated', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), abratio = 1, N = 500) # same as above, but assume only observed variables powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', Lambda = diag(4), alpha = .05, beta = .05) # same as above, but provide reduced loadings matrix to define that # X1 and X2 are measured by 5 indicators each loading by .4, .5, .6, .5, .4 # Y1 and Y2 are measured by 3 indicators each loading by .8, .6, .7 powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', loadings = list( c(.4, .5, .6, .5, .4), # X1 c(.8, .6, .7), # Y1 c(.4, .5, .6, .5, .4), # X2 c(.8, .6, .7) # Y2 ), alpha = .05, beta = .05) # same as above, but do not assume metric invariance across waves powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), metricInvariance = FALSE, alpha = .05, beta = .05) # same as above, but determine N to detect that the crossed-effect of Y (Y1 -> X2) is >= .1. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedY = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that the stability of X (X1 -> X2) is >= .8. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'autoregX = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that the stability of Y (Y1 -> Y2) is >= .7. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'autoregY = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed effect of X (X1 -> Y2) of .2 differs from # the crossed effect of Y (Y1 -> X2) of .1 powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = crossedY', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the autoregressive effect of X (X1 -> X2) of .8 differs from # the autoregressive effect of Y (Y1 -> Y2) of .7 powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'autoregX = autoregY', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but assume that the synchronous correlation between X and Y # is .3 at the first wave, and the respective residual correlation is .2 at the second wave, # and determine N to detect that synchronous residual correlation (at wave 2) is => .2. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = c(.3, .2), nullEffect = 'corXY = 0', nIndicator = c(5, 3, 5, 3), loadM = c(.5, .6, .5, .6), alpha = .05, beta = .05) # Determine required N in a 3-wave CLPM # to detect a crossed-effect of X (X1 -> Y2 and X2 -> Y3) of >= .2 # with a power of 95% on alpha = 5%, where # the crossed, autoregressive, and synchronous effects of X and Y are equal over waves, # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .6 each, and # the synchronous correlation between X and Y are .2 across all three waves, and # the stability of X is .8 across all three waves, # the stability of Y is .7 across all three waves, and # the crossed-effect of Y (Y1 -> X2, and Y2 -> Y3) is .1. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = c(.2, .2, .2), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # Determine required N in a 3-wave CLPM to detect that # the crossed-effect of X in wave 1 (X1 -> Y2) of .20 is equal to the # the crossed-effect of X in wave 2 (X2 -> Y3) of .10 # with a power of 95% on alpha = 5%, where # the autoregressive effects of X and Y are equal over waves, # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .6 each, and # the synchronous correlation between X and Y are .2, .3, and .4 at the first, # second, and third wave, and # the stability of X is .8 across all three waves, # the stability of Y is .7 across all three waves, and # the crossed-effects of Y (Y1 -> X2, and Y2 -> X3) are both .1 # (but freely estimated for each wave). powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( c(.20, .10), # X1 -> Y2, X2 -> Y3 c(.05, .10)), # Y1 -> X2, Y2 -> X3 rXY = c(.2, .3, .4), nullEffect = 'crossedX', waveEqual = c('autoregX', 'autoregY'), nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed-effect of X at wave 2 is >= .10. powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( c(.20, .10), # X1 -> Y2, X2 -> Y3 c(.05, .10)), # Y1 -> X2, Y2 -> X3 rXY = c(.2, .3, .4), nullEffect = 'crossedX', nullWhich = 2, waveEqual = c('autoregX', 'autoregY'), nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # same as above, but determine N to detect that # the residual correlation between X and Y at wave 2 (of .3) differs from # the residual correlation between X and Y at wave 3 (of .4) # and define unstandardized parameters powerCLPM <- semPower.powerCLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( c(.20, .10), # X1 -> Y2, X2 -> Y3 c(.05, .10)), # Y1 -> X2, Y2 -> X3 rXY = c(.2, .3, .4), nullEffect = 'corXY', waveEqual = c('autoregX', 'autoregY'), standardized = FALSE, nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .6, .5, .6, .5, .6), alpha = .05, beta = .05) # multiple group example # determine power in a 3-wave CLPM to detect that # the autoregressive effect of X in group 1 (of .8) differs from the # autoregressive effect of X in group 2 (of .6) # with a 500 observations in both groups on alpha = 5%, where # the autoregressive effects of X and Y are equal over waves (but not across groups), # the cross-lagged effects of X and Y are equal over waves (and also across groups), # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .4 each, and # there are no synchronous correlation between X and Y. powerCLPM <- semPower.powerCLPM(type = 'post-hoc', alpha = .05, N = list(500, 500), nWaves = 3, autoregEffects = list( # group 1 list(c(.8, .8), # X1 -> X2, X2 -> X3 c(.7, .7)), # Y1 -> Y2, Y2 -> Y3 # group 2 list(c(.6, .6), # X1 -> X2, X2 -> X3 c(.7, .7)) # Y1 -> Y2, Y2 -> Y3 ), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, nullEffect = 'autoregxa=autoregxb', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4)) # request a simulated post-hoc power analysis with 500 replications. set.seed(300121) powerCLPM <- semPower.powerCLPM(type = 'post-hoc', nWaves = 2, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), rXY = NULL, nullEffect = 'crossedX = 0', Lambda = diag(4), alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
Perform a power analysis given lavaan
model strings defining the H0 and the H1 model based on either
a lavaan
model string defining the population model or the population covariance matrix Sigma and the population means mu.
This requires the lavaan
package.
semPower.powerLav( type, modelPop = NULL, modelH0 = NULL, modelH1 = NULL, fitH1model = TRUE, Sigma = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, lavOptions = NULL, lavOptionsH1 = lavOptions, ... )
semPower.powerLav( type, modelPop = NULL, modelH0 = NULL, modelH1 = NULL, fitH1model = TRUE, Sigma = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, lavOptions = NULL, lavOptionsH1 = lavOptions, ... )
type |
type of power analysis, one of |
modelPop |
|
modelH0 |
|
modelH1 |
|
fitH1model |
whether to fit the H1 model. If |
Sigma |
can be used instead of |
mu |
can be used instead of |
fittingFunction |
one of |
simulatedPower |
whether to perform a simulated ( |
lavOptions |
a list of additional options passed to |
lavOptionsH1 |
alternative options passed to |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
Generic function to perform a power analysis based on a true population covariance matrix Sigma
and a model implied covariance matrix SigmaHat (and optionally the associated mean vectors),
where SigmaHat (and muHat) is determined by fitting a respective H0 model using lavaan
,
and Sigma (and mu) can also be provided through a corresponding lavaan
model string.
All semPower
convenience functions internally call this function.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # set up two CFA factors with a true correlation of .2 mPop <- ' f1 =~ .5*x1 + .6*x2 + .4*x3 f2 =~ .7*x4 + .8*x5 + .3*x6 x1 ~~ .75*x1 x2 ~~ .64*x2 x3 ~~ .84*x3 x4 ~~ .51*x4 x5 ~~ .36*x5 x6 ~~ .91*x6 f1 ~~ 1*f1 f2 ~~ 1*f2 f1 ~~ .2*f2 ' # define the H0 analysis model (restricting the factor correlation to zero) mH0 <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f1 ~~ 0*f2 ' # determine N to reject the H0 that the correlation is zero # with a power of 95% on alpha = .05 powerLav <- semPower.powerLav(type = 'a-priori', modelPop = mPop, modelH0 = mH0, alpha = .05, beta = .05) summary(powerLav) # same as above, but also define an H1 comparison model mH1 <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f1 ~~ f2 ' powerLav <- semPower.powerLav(type = 'a-priori', modelPop = mPop, modelH0 = mH0, modelH1 = mH1, alpha = .05, beta = .05) # same as above, but use covariance matrix input instead of modelPop gen <- semPower.genSigma(Phi = .2, loadings = list(c(.5, .6, .4), c(.7, .8, .3))) Sigma <- gen$Sigma powerLav <- semPower.powerLav(type = 'a-priori', Sigma = Sigma, modelH0 = mH0, alpha = .05, beta = .05) # note all of the above is identical to the output provided by the semPower.powerCFA function powerCFA <- semPower.powerCFA(type = 'a-priori', comparison = 'saturated', Phi = .2, loadings = list(c(.5, .6, .4), c(.7, .8, .3)), alpha = .05, beta = .05) # same as above, but perform simulated power analysis # with 250 replications using a robust ML test-statistic set.seed(300121) powerLav <- semPower.powerLav(type = 'a-priori', Sigma = Sigma, modelH0 = mH0, alpha = .05, beta = .05, simulatedPower = TRUE, simOptions = list(nReplications = 250) lavOptions = list(estimator = 'MLM')) ## End(Not run)
## Not run: # set up two CFA factors with a true correlation of .2 mPop <- ' f1 =~ .5*x1 + .6*x2 + .4*x3 f2 =~ .7*x4 + .8*x5 + .3*x6 x1 ~~ .75*x1 x2 ~~ .64*x2 x3 ~~ .84*x3 x4 ~~ .51*x4 x5 ~~ .36*x5 x6 ~~ .91*x6 f1 ~~ 1*f1 f2 ~~ 1*f2 f1 ~~ .2*f2 ' # define the H0 analysis model (restricting the factor correlation to zero) mH0 <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f1 ~~ 0*f2 ' # determine N to reject the H0 that the correlation is zero # with a power of 95% on alpha = .05 powerLav <- semPower.powerLav(type = 'a-priori', modelPop = mPop, modelH0 = mH0, alpha = .05, beta = .05) summary(powerLav) # same as above, but also define an H1 comparison model mH1 <- ' f1 =~ x1 + x2 + x3 f2 =~ x4 + x5 + x6 f1 ~~ f2 ' powerLav <- semPower.powerLav(type = 'a-priori', modelPop = mPop, modelH0 = mH0, modelH1 = mH1, alpha = .05, beta = .05) # same as above, but use covariance matrix input instead of modelPop gen <- semPower.genSigma(Phi = .2, loadings = list(c(.5, .6, .4), c(.7, .8, .3))) Sigma <- gen$Sigma powerLav <- semPower.powerLav(type = 'a-priori', Sigma = Sigma, modelH0 = mH0, alpha = .05, beta = .05) # note all of the above is identical to the output provided by the semPower.powerCFA function powerCFA <- semPower.powerCFA(type = 'a-priori', comparison = 'saturated', Phi = .2, loadings = list(c(.5, .6, .4), c(.7, .8, .3)), alpha = .05, beta = .05) # same as above, but perform simulated power analysis # with 250 replications using a robust ML test-statistic set.seed(300121) powerLav <- semPower.powerLav(type = 'a-priori', Sigma = Sigma, modelH0 = mH0, alpha = .05, beta = .05, simulatedPower = TRUE, simOptions = list(nReplications = 250) lavOptions = list(estimator = 'MLM')) ## End(Not run)
Convenience function for performing power analysis on effects in a latent growth curve model (LGCM). This requires the lavaan package.
semPower.powerLGCM( type, comparison = "restricted", nWaves = NULL, means = NULL, variances = NULL, covariances = NULL, quadratic = FALSE, timeCodes = NULL, ticExogSlopes = NULL, ticEndogSlopes = NULL, groupEqual = NULL, nullEffect = NULL, nullWhichGroups = NULL, autocorResiduals = TRUE, ... )
semPower.powerLGCM( type, comparison = "restricted", nWaves = NULL, means = NULL, variances = NULL, covariances = NULL, quadratic = FALSE, timeCodes = NULL, ticExogSlopes = NULL, ticEndogSlopes = NULL, groupEqual = NULL, nullEffect = NULL, nullWhichGroups = NULL, autocorResiduals = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
nWaves |
number of waves, must be >= 3 for linear and > 3 for quadratic trends. |
means |
vector providing the means of the intercept and the linear slope factor (and the quadratic slope factor, if |
variances |
vector providing the variances of the intercept and the linear slope factor (and the quadratic slope factor, if |
covariances |
either the variance-covariance matrix between the intercept and the slope (and the quadratic slope factor, if |
quadratic |
whether to include a quadratic slope factor in addition to a linear slope factor. Defaults to |
timeCodes |
vector of length |
ticExogSlopes |
vector defining the slopes for an exogenous time-invariant covariate in the prediction of the intercept and slope factors (and the quadratic slope factor, if |
ticEndogSlopes |
vector defining the slopes for the intercept and slope factors (and the quadratic slope factor, if |
groupEqual |
parameters that are restricted across groups in both the H0 and the H1 model, when |
nullEffect |
defines the hypothesis of interest. See details for valid arguments. |
nullWhichGroups |
for hypothesis involving cross-groups comparisons, vector indicating the groups for which equality constrains should be applied, e.g. |
autocorResiduals |
whether the residuals of the indicators of latent variables are autocorrelated over waves ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising
in latent growth curve models (LGCM), where one variable X
is repeatedly
assessed at different time points (nWaves
), and a latent intercept and a
linear (and optionally a quadratic) latent slope factor is assumed.
Relevant hypotheses in arising in a LCGM are:
iMean = 0
, sMean = 0
, s2Mean = 0
: Tests the hypothesis that the mean of the intercept, linear slope, and quadratic slope factors, respectively, is zero.
iVar = 0
, sVar = 0
, s2Var = 0
: Tests the hypothesis that the variance of the intercept, linear slope, and quadratic slope factors, respectively, is zero.
isCov = 0
: Tests the hypothesis that covariance between the intercept and linear slope factor is zero.
is2Cov = 0
: Tests the hypothesis that covariance between the intercept and quadratic slope factor is zero.
ss2Cov = 0
: Tests the hypothesis that covariance between the linear and the quadratic slope factor is zero.
betaIT = 0
, betaST = 0
, betaS2T = 0
: Tests the hypothesis that the slope for an exogenous time-invariant covariate in the prediction of the intercept, the linear slope, and the quadratic slope factor, respectively, is zero (TIC -> I, S, S2
).
betaTI = 0
, betaTS = 0
, betaTS2 = 0
: Tests the hypothesis that the slope the intercept, the linear slope, and the quadratic slope factor, respectively, in the prediction of an endogenous time-invariant covariate is zero (I, S, S2 -> TIC
).
iMeanA = iMeanB
, sMeanA = sMeanB
, s2MeanA = s2MeanB
: Tests the hypothesis that the means of the intercept, linear slope, and quadratic slope factors, respectively, are equal across groups.
iVarA = iVarB
, sVarA = sVarB
, s2VarA = s2VarB
: Tests the hypothesis that the variances of the intercept, linear slope, and quadratic slope factors, respectively, are equal across groups.
isCovA = isCovA
: Tests the hypothesis that covariance between the intercept and linear slope factor is equal across groups.
is2CovA = is2CovA
: Tests the hypothesis that the covariance between the intercept and quadratic slope factor is equal across groups.
ss2CovA = ss2CovA
: Tests the hypothesis that the covariance between the linear and quadratic slope factor is equal across groups.
betaITA = betaITB
, betaSTA = betaSTB
, betaS2TA = betaS2TB
: Tests the hypothesis that the slopes for the time-invariant covariate in the prediction of the intercept, the linear slope, and the quadratic slope factor, respectively, are equal across groups (TIC -> I, S, S2
).
betaTIA = betaTIB
, betaTSA = betaTSB
, betaTS2A = betaTS2B
: Tests the hypothesis that the slope the intercept, the linear slope, and the quadratic slope factor, respectively, in the prediction of the time-invariant covariate are equal across groups (I, S, S2 -> TIC
).
For hypotheses regarding longitudinal invariance, see semPower.powerLI()
. For hypotheses regarding a simple autoregression, see semPower.powerAutoreg()
. For hypotheses in an ARMA model, see semPower.powerARMA()
.
Note that power analyses concerning the hypotheses iVar = 0
, sVar = 0
, and s2Var = 0
are only approximate,
because the H0 model involves a parameter constraint on the boundary of the parameter space (a variance of zero),
so that the correct limiting distribution is a mixture of non-central distributions
(see Stoel et al., 2006). In effect, power is (slightly) underestimated.
Stoel, R. D., Garre, F. G., Dolan, C., & Van Den Wittenboer, G. (2006). On the likelihood ratio test in structural equation modeling when parameters are subject to boundary constraints. Psychological Methods, 11, 439-455.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined. Neither may contain entries referring to the intercept and slope factors.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
The order of the factors is (X1, X2, ..., X_nWaves, ticExogenous, ticEndogenous). If ticExogenous is undefined, ticEndogenous takes its place.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # Determine required N in a 3-wave LGCM model # to detect that the mean of the slope factor differs from zero # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave), and # the mean of the intercept factor is .5 and # the mean of the slope factor is .2 and # the variance of the intercept factor is 1 and # the variance of the slope factor is .5 and # the intercept-slope covariance is .25 and # autocorrelated residuals are assumed powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), # i, s variances = c(1, .5), # i, s covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # show summary summary(powerLGCM) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerLGCM$modelH1, sample.cov = powerLGCM$Sigma, sample.mean = powerLGCM$mu, sample.nobs = powerLGCM$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerLGCM$modelH0, sample.cov = powerLGCM$Sigma, sample.mean = powerLGCM$mu, sample.nobs = powerLGCM$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 250 on alpha = .05 powerLGCM <- semPower.powerLGCM( 'post-hoc', alpha = .05, N = 250, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but determine the critical chi-square with N = 250 so that alpha = beta powerLGCM <- semPower.powerLGCM( 'compromise', abratio = 1, N = 250, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but assume only observed variables powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', Lambda = diag(3), autocorResiduals = TRUE ) # same as above, but provide reduced loadings matrix to define that # X is measured by 3 indicators each loading by .5, .6, .4 (at each wave) powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4) # X3 ), autocorResiduals = TRUE ) # same as above, but get required N to detect that # the variance of the intercept factor differs from zero powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'iVar = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but get required N to detect that # the intercept-slope covariance differs from zero powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'iscov = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # include a quadratic slope factor # and get required N to detect that # its variance differs from zero. # provide the variance-covariance matrix # between intercept, slope, and quadratic slope factors powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 4, quadratic = TRUE, means = c(.5, .2, .1), covariances = matrix(c( # i s s2 c(1, .3, .2), c(.3, .5, .01), c(.2, .01, .1) ), ncol = 3, byrow = TRUE), nullEffect = 's2var = 0', nIndicator = rep(3, 4), loadM = .5, autocorResiduals = TRUE ) # Determine required N in a 3-wave LGCM model # to detect that the slope of an time-invariant covariate (TIC) # on the slope factor differs from zero. # The TIC is measured by 4 indicators loading # by .7, .7, .5, and .8. The slope of the TIC in the prediction of # the intercept factor is .5, and in the prediction of the slope factor is .4. powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, ticExogSlopes = c(.5, .4), # i s nullEffect = 'betaST = 0', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4), # X3 c(.7, .7, .5, .8) # TIC ), autocorResiduals = TRUE ) # Determine required N in a 3-wave LGCM model # to detect that the slope of the slope factor in # the prediction of a time-invariant covariate (TIC) differs from zero. # The TIC is measured by 4 indicators loading # by .7, .7, .5, and .8. The slopes of the intercept and the slope factors in # the prediction of the TIC are .1 and .3, respectively. powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, ticEndogSlopes = c(.1, .3), # i s nullEffect = 'betaTS = 0', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4), # X3 c(.7, .7, .5, .8) # TIC ), autocorResiduals = TRUE ) # Determine required N in a 3-wave LGCM model # to detect that the mean of the slope factor in group 1 # differs from the mean of the slope factor in group 2 # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the means of the intercept factor in group 1 and 2 are .5 and .25 # the means of the slope factor in group 1 and 2 are .25 and .4 # the variance of the intercept factor is 1 in both groups and # the variance of the slope factor is .5in both groups and # the intercept-slope covariance is .25 in both groups and # autocorrelated residuals are assumed and # the groups are equal-sized powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 3, means = list( # i, s c(.5, .2), # group 1 c(.25, .4)), # group 2 variances = c(1, .5), covariances = .25, nullEffect = 'sMeanA = sMeanB', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # similar as above, but get required N to detect that # the intercept-slope covariance differs across groups, # assuming that intercept and slope variances are equal across groups. powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = list( c(.25), # group 1 c(.1)), # group 2 nullEffect = 'isCovA = isCovB', groupEqual = c('ivar', 'svar'), nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # perform a simulated post-hoc power analysis # with 250 replications set.seed(300121) powerLGCM <- semPower.powerLGCM( 'post-hoc', alpha = .05, N = 500, nWaves = 3, means = c(.5, .2), # i, s variances = c(1, .5), # i, s covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 250) ) ## End(Not run)
## Not run: # Determine required N in a 3-wave LGCM model # to detect that the mean of the slope factor differs from zero # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave), and # the mean of the intercept factor is .5 and # the mean of the slope factor is .2 and # the variance of the intercept factor is 1 and # the variance of the slope factor is .5 and # the intercept-slope covariance is .25 and # autocorrelated residuals are assumed powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), # i, s variances = c(1, .5), # i, s covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # show summary summary(powerLGCM) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerLGCM$modelH1, sample.cov = powerLGCM$Sigma, sample.mean = powerLGCM$mu, sample.nobs = powerLGCM$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerLGCM$modelH0, sample.cov = powerLGCM$Sigma, sample.mean = powerLGCM$mu, sample.nobs = powerLGCM$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 250 on alpha = .05 powerLGCM <- semPower.powerLGCM( 'post-hoc', alpha = .05, N = 250, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but determine the critical chi-square with N = 250 so that alpha = beta powerLGCM <- semPower.powerLGCM( 'compromise', abratio = 1, N = 250, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but assume only observed variables powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', Lambda = diag(3), autocorResiduals = TRUE ) # same as above, but provide reduced loadings matrix to define that # X is measured by 3 indicators each loading by .5, .6, .4 (at each wave) powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'sMean = 0', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4) # X3 ), autocorResiduals = TRUE ) # same as above, but get required N to detect that # the variance of the intercept factor differs from zero powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'iVar = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # same as above, but get required N to detect that # the intercept-slope covariance differs from zero powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, nullEffect = 'iscov = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # include a quadratic slope factor # and get required N to detect that # its variance differs from zero. # provide the variance-covariance matrix # between intercept, slope, and quadratic slope factors powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 4, quadratic = TRUE, means = c(.5, .2, .1), covariances = matrix(c( # i s s2 c(1, .3, .2), c(.3, .5, .01), c(.2, .01, .1) ), ncol = 3, byrow = TRUE), nullEffect = 's2var = 0', nIndicator = rep(3, 4), loadM = .5, autocorResiduals = TRUE ) # Determine required N in a 3-wave LGCM model # to detect that the slope of an time-invariant covariate (TIC) # on the slope factor differs from zero. # The TIC is measured by 4 indicators loading # by .7, .7, .5, and .8. The slope of the TIC in the prediction of # the intercept factor is .5, and in the prediction of the slope factor is .4. powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, ticExogSlopes = c(.5, .4), # i s nullEffect = 'betaST = 0', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4), # X3 c(.7, .7, .5, .8) # TIC ), autocorResiduals = TRUE ) # Determine required N in a 3-wave LGCM model # to detect that the slope of the slope factor in # the prediction of a time-invariant covariate (TIC) differs from zero. # The TIC is measured by 4 indicators loading # by .7, .7, .5, and .8. The slopes of the intercept and the slope factors in # the prediction of the TIC are .1 and .3, respectively. powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = .25, ticEndogSlopes = c(.1, .3), # i s nullEffect = 'betaTS = 0', loadings = list( c(.5, .6, .4), # X1 c(.5, .6, .4), # X2 c(.5, .6, .4), # X3 c(.7, .7, .5, .8) # TIC ), autocorResiduals = TRUE ) # Determine required N in a 3-wave LGCM model # to detect that the mean of the slope factor in group 1 # differs from the mean of the slope factor in group 2 # with a power of 80% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each (at each wave and in each group), and # the means of the intercept factor in group 1 and 2 are .5 and .25 # the means of the slope factor in group 1 and 2 are .25 and .4 # the variance of the intercept factor is 1 in both groups and # the variance of the slope factor is .5in both groups and # the intercept-slope covariance is .25 in both groups and # autocorrelated residuals are assumed and # the groups are equal-sized powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 3, means = list( # i, s c(.5, .2), # group 1 c(.25, .4)), # group 2 variances = c(1, .5), covariances = .25, nullEffect = 'sMeanA = sMeanB', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # similar as above, but get required N to detect that # the intercept-slope covariance differs across groups, # assuming that intercept and slope variances are equal across groups. powerLGCM <- semPower.powerLGCM( 'a-priori', alpha = .05, power = .80, N = list(1, 1), nWaves = 3, means = c(.5, .2), variances = c(1, .5), covariances = list( c(.25), # group 1 c(.1)), # group 2 nullEffect = 'isCovA = isCovB', groupEqual = c('ivar', 'svar'), nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE ) # perform a simulated post-hoc power analysis # with 250 replications set.seed(300121) powerLGCM <- semPower.powerLGCM( 'post-hoc', alpha = .05, N = 500, nWaves = 3, means = c(.5, .2), # i, s variances = c(1, .5), # i, s covariances = .25, nullEffect = 'sMean = 0', nIndicator = rep(3, 3), loadM = .5, autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 250) ) ## End(Not run)
Convenience function for performing power analyses for hypothesis arising in longitudinal measurement invariance models concerning a specific level of invariance. This requires the lavaan package.
semPower.powerLI( type, comparison = NULL, nullEffect = NULL, autocorResiduals = TRUE, Phi = NULL, ... )
semPower.powerLI( type, comparison = NULL, nullEffect = NULL, autocorResiduals = TRUE, Phi = NULL, ... )
type |
type of power analysis, one of |
comparison |
comparison model, either |
nullEffect |
defines the hypothesis (i.e., level of invariance) of interest. Accepts the same arguments as |
autocorResiduals |
whether the residuals of the indicators of latent variables are autocorrelated over waves ( |
Phi |
the factor correlation matrix. Can be |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising in the context of longitudinal measurement invariance, where a single attribute is measured repeatedly. The typical - but not in all parts necessary - sequence concerning the measurement part is (a) configural, (b) metric, (c) scalar, (d) residual invariance, and concerning the structural part (e) latent covariances, (f) latent means, where each level of invariance is compared against the previous level (e.g., scalar vs. metric). Power analysis provides the power (or the required N) to reject a particular level of invariance.
For hypotheses regarding multiple group invariance, see semPower.powerMI()
. For hypotheses regarding autoregressive models, see semPower.powerAutoreg()
. For hypotheses in an ARMA model, see semPower.powerARMA()
.
There are two ways to specify the models defined in the comparison
and the nullEffect
arguments. Either, one may
specify a specific level of invariance that includes all previous levels:
'configural'
: no invariance constraints. Shows the same fit as the saturated model, so only the delta df differ.
'metric'
: all loadings are restricted to equality over measurement occasions. Note that reference scaling is used, so the first indicator should be invariant.
'scalar'
: all loadings and (indicator-)intercepts are restricted to equality.
'residual'
: all loadings, (indicator-)intercepts, and (indicator-)residuals are restricted to equality.
'covariances'
: all loadings, (indicator-)intercepts, (indicator-)residuals, and latent covariances are restricted to equality.
'means'
: all loadings, (indicator-)intercepts, (indicator-)residuals, latent covariances, and latent means are restricted to equality.
For example, setting comparison = 'metric'
and nullEffect = 'scalar'
determines power
to reject the hypothesis that the constraints placed in the scalar invariance model
(restricting loadings and intercepts) over the
metric invariance model (restricting only the loadings) are defensible.
For greater flexibility, the models can also be defined using lavaan
style restrictions as a vector, namely
'none'
(no restrictions), 'loadings'
(loadings), 'intercepts'
(intercepts), 'residuals'
(residuals), 'lv.covariances'
(latent covariances), 'means'
(latent means).
For instance:
'none'
: no invariance constraints and thus representing a configural invariance model. Shows the same fit as the saturated model, so only the delta df differ.
c('loadings')
: all loadings are restricted to equality. Note that reference scaling is used, so the first indicator should be invariant.
c('loadings', 'intercepts')
: all loadings and (indicator-)intercepts are restricted to equality.
c('loadings', 'intercepts', 'residuals')
: all loadings, (indicator-)intercepts, and (indicator-)residuals are restricted to equality.
c('loadings', 'residuals')
: all loadings and (indicator-)residuals are restricted to equality.
c('loadings', 'intercepts', 'means')
: all loadings, (indicator-)intercepts, and latent factor means are restricted to equality.
c('loadings', 'residuals', 'lv.covariances')
: all loadings, (indicator-)residuals, and latent factor covariances are restricted to equality.
For example, setting comparison = c('loadings')
and nullEffect = 'c('loadings', 'intercepts')'
determines power to reject the hypothesis that the constraints placed in the scalar invariance model
(restricting loadings and intercepts) over the metric invariance model (restricting only the loadings) are defensible.
Note that variance scaling is used, so invariance of variances ('lv.variances'
) is always met. Latent means are identified using single occasion identification.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
Theta
: Variance-covariance matrix of the indicator residuals, which should be a diagonal matrix. Required when residual non-invariance is to be detected. When NULL
, Theta is a diagonal matrix with elements such that all variances are 1.
tau
: Defines the indicator intercepts, required whenever a model involves hypotheses about means (e.g., scalar invariance). If NULL
and Alpha
is set, all intercepts are assumed to equal zero.
Alpha
: Defines the latent means, required whenever a model involves hypotheses about latent means (e.g., latent mean invariance). If NULL
and tau
is set, all latent means are assumed to equal zero. Because variance scaling is used so that all factor variances are 1, latent mean differences can be interpreted akin to Cohen's d as standardized mean differences.
So either Lambda
, or loadings
, or nIndicator
and loadM
always need to be defined,
and Theta
, tau
and Alpha
need to be defined for particular levels of invariance.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # obtain the required N to reject the hypothesis of metric invariance # in comparison to the configural invariance model # with a power of 80% on alpha = 5% # for amodel involving a two factors (= two measurements) which # is measured by 5 indicators # loading by .5 each at the first measurement occasion # loading by .6 each in the second measurement occasion, # and assuming autocorrelated residuals powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'configural', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # show summary summary(powerLI) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerLI$modelH1, sample.cov = powerLI$Sigma, sample.nobs = 1000, sample.cov.rescale = FALSE) lavaan::sem(powerLI$modelH0, sample.cov = powerLI$Sigma, sample.nobs = 1000, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerLI <- semPower.powerLI( type = 'post-hoc', alpha = .05, N = 500, comparison = 'configural', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # same as above, but determine the critical chi-square with N = 500 in each # group so that alpha = beta powerLI <- semPower.powerLI( type = 'compromise', abratio = 1, N = 500, comparison = 'configural', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # same as above, but compare to the saturated model # (rather than to the configural invariance model) powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # same as above, but provide individual factor loadings by group using a # reduced loading matrix to define a single factor model with three indicators # loading by .4, .6, .5 at the first measurement occasion and # loading by .5, .6, .7 at the second measurement occasion powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'configural', nullEffect = 'metric', loadings = list( c(.4, .6, .5), c(.5, .6, .7) ), autocorResiduals = TRUE ) # obtain the required N to reject the hypothesis of scalar invariance # in comparison to the metric invariance model # with a power of 80% on alpha = 5% # for a two factor model, where both factors are # measured by 3 indicators each and all loadings equal .5 (at both measurements), # all intercepts are 0.0 at the first measurement occasion, but # all intercepts are 0.2 at the second measurement occasion and powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'metric', nullEffect = 'scalar', nIndicator = c(5, 5), loadM = c(.5, .5), tau = c(0, 0, 0, 0, 0, .2, .2, .2, .2, .2), autocorResiduals = TRUE ) # same as above, but use lavaan strings powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = c('loadings'), nullEffect = c('loadings', 'intercepts'), nIndicator = c(5, 5), loadM = c(.5, .5), tau = c(0, 0, 0, 0, 0, .2, .2, .2, .2, .2), autocorResiduals = TRUE ) # obtain the required N to reject the hypothesis of equal latent means # in comparison to the scalar invariance model; # all intercepts are zero in both groups, # at the first measurement occasion, the latent mean is 0.0, # at the first measurement occasion, the latent mean is 0.5 powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = c('loadings', 'intercepts'), nullEffect = c('loadings', 'intercepts', 'means'), nIndicator = c(5, 5), loadM = c(.5, .5), tau = rep(0, 10), Alpha = c(0, .5), autocorResiduals = TRUE ) # obtain the required N to reject the hypothesis of equal covariances # in comparison to the residual invariance model; Phi <- matrix(c( c(1, .3, .1), c(.3, 1, .2), c(.1, .2, 1) ), nrow=3, byrow = TRUE) powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'residual', nullEffect = 'covariances', nIndicator = c(3, 3, 3), loadM = c(.5, .5, .5), Phi = Phi, tau = rep(0, 9) ) # request a simulated post-hoc power analysis with 250 replications # to reject the hypothesis of equal latent means. set.seed(300121) powerLI <- semPower.powerLI( type = 'post-hoc', alpha = .05, N = 500, comparison = c('loadings', 'intercepts'), nullEffect = c('loadings', 'intercepts', 'means'), nIndicator = c(5, 5), loadM = c(.5, .5), tau = rep(0, 10), Alpha = c(0, .5), autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 250) ) ## End(Not run)
## Not run: # obtain the required N to reject the hypothesis of metric invariance # in comparison to the configural invariance model # with a power of 80% on alpha = 5% # for amodel involving a two factors (= two measurements) which # is measured by 5 indicators # loading by .5 each at the first measurement occasion # loading by .6 each in the second measurement occasion, # and assuming autocorrelated residuals powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'configural', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # show summary summary(powerLI) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerLI$modelH1, sample.cov = powerLI$Sigma, sample.nobs = 1000, sample.cov.rescale = FALSE) lavaan::sem(powerLI$modelH0, sample.cov = powerLI$Sigma, sample.nobs = 1000, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerLI <- semPower.powerLI( type = 'post-hoc', alpha = .05, N = 500, comparison = 'configural', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # same as above, but determine the critical chi-square with N = 500 in each # group so that alpha = beta powerLI <- semPower.powerLI( type = 'compromise', abratio = 1, N = 500, comparison = 'configural', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # same as above, but compare to the saturated model # (rather than to the configural invariance model) powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'saturated', nullEffect = 'metric', nIndicator = c(5, 5), loadM = c(.5, .6), autocorResiduals = TRUE ) # same as above, but provide individual factor loadings by group using a # reduced loading matrix to define a single factor model with three indicators # loading by .4, .6, .5 at the first measurement occasion and # loading by .5, .6, .7 at the second measurement occasion powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'configural', nullEffect = 'metric', loadings = list( c(.4, .6, .5), c(.5, .6, .7) ), autocorResiduals = TRUE ) # obtain the required N to reject the hypothesis of scalar invariance # in comparison to the metric invariance model # with a power of 80% on alpha = 5% # for a two factor model, where both factors are # measured by 3 indicators each and all loadings equal .5 (at both measurements), # all intercepts are 0.0 at the first measurement occasion, but # all intercepts are 0.2 at the second measurement occasion and powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'metric', nullEffect = 'scalar', nIndicator = c(5, 5), loadM = c(.5, .5), tau = c(0, 0, 0, 0, 0, .2, .2, .2, .2, .2), autocorResiduals = TRUE ) # same as above, but use lavaan strings powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = c('loadings'), nullEffect = c('loadings', 'intercepts'), nIndicator = c(5, 5), loadM = c(.5, .5), tau = c(0, 0, 0, 0, 0, .2, .2, .2, .2, .2), autocorResiduals = TRUE ) # obtain the required N to reject the hypothesis of equal latent means # in comparison to the scalar invariance model; # all intercepts are zero in both groups, # at the first measurement occasion, the latent mean is 0.0, # at the first measurement occasion, the latent mean is 0.5 powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = c('loadings', 'intercepts'), nullEffect = c('loadings', 'intercepts', 'means'), nIndicator = c(5, 5), loadM = c(.5, .5), tau = rep(0, 10), Alpha = c(0, .5), autocorResiduals = TRUE ) # obtain the required N to reject the hypothesis of equal covariances # in comparison to the residual invariance model; Phi <- matrix(c( c(1, .3, .1), c(.3, 1, .2), c(.1, .2, 1) ), nrow=3, byrow = TRUE) powerLI <- semPower.powerLI( type = 'a-priori', alpha = .05, power = .80, comparison = 'residual', nullEffect = 'covariances', nIndicator = c(3, 3, 3), loadM = c(.5, .5, .5), Phi = Phi, tau = rep(0, 9) ) # request a simulated post-hoc power analysis with 250 replications # to reject the hypothesis of equal latent means. set.seed(300121) powerLI <- semPower.powerLI( type = 'post-hoc', alpha = .05, N = 500, comparison = c('loadings', 'intercepts'), nullEffect = c('loadings', 'intercepts', 'means'), nIndicator = c(5, 5), loadM = c(.5, .5), tau = rep(0, 10), Alpha = c(0, .5), autocorResiduals = TRUE, simulatedPower = TRUE, simOptions = list(nReplications = 250) ) ## End(Not run)
Convenience function for performing power analysis concerning indirect effect(s) in a mediation model. This requires the lavaan package.
semPower.powerMediation( type, comparison = "restricted", bYX = NULL, bMX = NULL, bYM = NULL, Beta = NULL, indirect = NULL, nullEffect = "ind = 0", nullWhichGroups = NULL, standardized = TRUE, ... )
semPower.powerMediation( type, comparison = "restricted", bYX = NULL, bMX = NULL, bYM = NULL, Beta = NULL, indirect = NULL, nullEffect = "ind = 0", nullWhichGroups = NULL, standardized = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
bYX |
the slope (direct effect) for X -> Y. A list for multiple group models. Can be |
bMX |
the slope for X -> M. A list for multiple group models. Can be |
bYM |
the slope for M -> Y. A list for multiple group models. Can be |
Beta |
can be used instead of |
indirect |
|
nullEffect |
defines the hypothesis of interest, must be one of |
nullWhichGroups |
for |
standardized |
whether all parameters should be standardized ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising in the context of mediation:
nullEffect = 'ind = 0'
: Tests the hypothesis that an indirect effect is zero.
nullEffect = 'indA = indB'
: Tests the hypothesis that an indirect effect is equal in two or more groups. This is currently only possible for models without latent variables.
The indirect effect of interest can be specified in two ways:
If a simple mediation involving three variables of the form X -> M -> Y
is assumed, the arguments
bYX
, bMX
, and bYM
are used to define the respective slopes, e. g. bYX = .4
, bMX = .5
, and bYM = .3
translates to
X -- .5 --> M -- .3 --> Y
and X -- .4 --> Y
.
More complex mediation structures can be defined by providing the Beta
matrix along with indirect
specifying which paths define the indirect effect. See examples below.
Notes on implementation:
For models without latent variables, nullEffect = 'ind = 0'
and nullEffect = 'indA = indB'
constrain the indirect effect to zero and to equality, respectively, yielding the test described in Tofighi & Kelley (2020).
For models with latent variables and nullEffect = 'ind = 0'
, power is (sometimes roughly) approximated by constraining the smallest slope contained in the indirect effect to zero.
For models with latent variables multiple groups (i. e., nullEffect = 'indA = indB'
), there is currently no way to determine power.
Tofighi, D., & Kelley, K. (2020). Improved inference in mediation analysis: Introducing the model-based constrained optimization procedure. Psychological Methods, 25(4), 496–515. https://doi.org/10.1037/met0000259
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
Note that in case of a simple mediation model involving three variables, the order of the factors is X, M, Y, i. e., the first factor is treated as X, the second as M, and the third as Y. In case of a more complex mediation defined via the Beta
matrix, the order of factors matches the order of Beta
.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # simple case of X -> M -> Y mediation in the form of # X -- .30 --> M -- .40 --> Y # X --------- .25 --------> Y # determine the required N to detect the indirect effect of >= .12 (= .3 * .4) # with a power of 95% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each, # M is measured by 5 indicators loading by .6 each, # Y is measured by 4 indicators loading by .7 each. powerMed <- semPower.powerMediation(type = 'a-priori', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # show summary summary(powerMed) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerMed$modelH1, sample.cov = powerMed$Sigma, sample.nobs = powerMed$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerMed$modelH0, sample.cov = powerMed$Sigma, sample.nobs = powerMed$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerMed <- semPower.powerMediation(type = 'post-hoc', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerMed <- semPower.powerMediation(type = 'compromise', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerMed <- semPower.powerMediation(type = 'a-priori', comparison = 'saturated', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but assuming observed variables only (Lambda = diag(3)) powerMed <- semPower.powerMediation(type = 'a-priori', bYX = .25, bMX = .3, bYM = .4, Lambda = diag(3), alpha = .05, beta = .05) # same mediation model as above, but specifying Beta and indirect Beta <- matrix(c( # X M Y c(.00, .00, .00), # X c(.30, .00, .00), # M c(.25, .40, .00) # Y ), byrow = TRUE, ncol = 3) powerMed <- semPower.powerMediation(type = 'a-priori', Beta = Beta, indirect = list(c(2, 1), c(3, 2)), nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # Beta for a more complex mediation hypothesis # of the form X -- .2 --> M1 -- .3 --> M2 -- .40 -> Y # (and all other effects being zero) # using a reduced loading matrix to define that # X is measured by 3 indicators loading by .4, .5, .8 # M1 is measured by 4 indicators loading by .7, .6, .5, .8 # M2 is measured by 5 indicators loading by .5, .6, .3, .4, .6 # Y is measured by 4 indicators loading by .6, .7, .8 Beta <- matrix(c( c(.00, .00, .00, .00), # X c(.20, .00, .00, .00), # M1 c(.00, .30, .00, .00), # M2 c(.00, .00, .40, .00) # Y ), byrow = TRUE, ncol = 4) loadings <- list( c(0.4, 0.5, 0.8), # X c(0.7, 0.6, 0.5, 0.8), # M1 c(0.5, 0.6, 0.3, 0.4, 0.6), # M2 c(0.6, 0.7, 0.8) # Y ) powerMed <- semPower.powerMediation(type = 'a-priori', Beta = B, indirect = list(c(2, 1), c(3, 2), c(4, 3)), loadings = loadings, alpha = .05, beta = .05) # Determine required N to detect that the indirect effect # in group 1 (of .2 * .3 = .09) differs from the indirect effect # in group 2 (of .3 * .5 = .15). # The direct effect of X on Y is .25 in both groups. # The model is based on observed variables only (Lambda = diag(3)) # Both groups are sized equally (N = list(1, 1)). powerMed <- semPower.powerMediation(type = 'a-priori', nullEffect = 'indA = indB', bYX = list(.25, .25), bMX = list(.2, .3), bYM = list(.3, .5), Lambda = diag(3), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but specifying Beta Beta1 <- matrix(c( c(.00, .00, .00), # X c(.20, .00, .00), # M c(.25, .30, .00) # Y ), byrow = TRUE, ncol = 3) Beta2 <- matrix(c( c(.00, .00, .00), # X c(.30, .00, .00), # M c(.25, .50, .00) # Y ), byrow = TRUE, ncol = 3) powerMed <- semPower.powerMediation(type = 'a-priori', nullEffect = 'indA = indB', Beta = list(Beta1, Beta2), indirect = list(c(2, 1), c(3, 2)), Lambda = diag(3), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications. set.seed(300121) powerMed <- semPower.powerMediation(type = 'post-hoc', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
## Not run: # simple case of X -> M -> Y mediation in the form of # X -- .30 --> M -- .40 --> Y # X --------- .25 --------> Y # determine the required N to detect the indirect effect of >= .12 (= .3 * .4) # with a power of 95% on alpha = 5%, where # X is measured by 3 indicators loading by .5 each, # M is measured by 5 indicators loading by .6 each, # Y is measured by 4 indicators loading by .7 each. powerMed <- semPower.powerMediation(type = 'a-priori', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # show summary summary(powerMed) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerMed$modelH1, sample.cov = powerMed$Sigma, sample.nobs = powerMed$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerMed$modelH0, sample.cov = powerMed$Sigma, sample.nobs = powerMed$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerMed <- semPower.powerMediation(type = 'post-hoc', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerMed <- semPower.powerMediation(type = 'compromise', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerMed <- semPower.powerMediation(type = 'a-priori', comparison = 'saturated', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but assuming observed variables only (Lambda = diag(3)) powerMed <- semPower.powerMediation(type = 'a-priori', bYX = .25, bMX = .3, bYM = .4, Lambda = diag(3), alpha = .05, beta = .05) # same mediation model as above, but specifying Beta and indirect Beta <- matrix(c( # X M Y c(.00, .00, .00), # X c(.30, .00, .00), # M c(.25, .40, .00) # Y ), byrow = TRUE, ncol = 3) powerMed <- semPower.powerMediation(type = 'a-priori', Beta = Beta, indirect = list(c(2, 1), c(3, 2)), nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # Beta for a more complex mediation hypothesis # of the form X -- .2 --> M1 -- .3 --> M2 -- .40 -> Y # (and all other effects being zero) # using a reduced loading matrix to define that # X is measured by 3 indicators loading by .4, .5, .8 # M1 is measured by 4 indicators loading by .7, .6, .5, .8 # M2 is measured by 5 indicators loading by .5, .6, .3, .4, .6 # Y is measured by 4 indicators loading by .6, .7, .8 Beta <- matrix(c( c(.00, .00, .00, .00), # X c(.20, .00, .00, .00), # M1 c(.00, .30, .00, .00), # M2 c(.00, .00, .40, .00) # Y ), byrow = TRUE, ncol = 4) loadings <- list( c(0.4, 0.5, 0.8), # X c(0.7, 0.6, 0.5, 0.8), # M1 c(0.5, 0.6, 0.3, 0.4, 0.6), # M2 c(0.6, 0.7, 0.8) # Y ) powerMed <- semPower.powerMediation(type = 'a-priori', Beta = B, indirect = list(c(2, 1), c(3, 2), c(4, 3)), loadings = loadings, alpha = .05, beta = .05) # Determine required N to detect that the indirect effect # in group 1 (of .2 * .3 = .09) differs from the indirect effect # in group 2 (of .3 * .5 = .15). # The direct effect of X on Y is .25 in both groups. # The model is based on observed variables only (Lambda = diag(3)) # Both groups are sized equally (N = list(1, 1)). powerMed <- semPower.powerMediation(type = 'a-priori', nullEffect = 'indA = indB', bYX = list(.25, .25), bMX = list(.2, .3), bYM = list(.3, .5), Lambda = diag(3), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but specifying Beta Beta1 <- matrix(c( c(.00, .00, .00), # X c(.20, .00, .00), # M c(.25, .30, .00) # Y ), byrow = TRUE, ncol = 3) Beta2 <- matrix(c( c(.00, .00, .00), # X c(.30, .00, .00), # M c(.25, .50, .00) # Y ), byrow = TRUE, ncol = 3) powerMed <- semPower.powerMediation(type = 'a-priori', nullEffect = 'indA = indB', Beta = list(Beta1, Beta2), indirect = list(c(2, 1), c(3, 2)), Lambda = diag(3), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications. set.seed(300121) powerMed <- semPower.powerMediation(type = 'post-hoc', bYX = .25, bMX = .3, bYM = .4, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
Convenience function for performing power analyses for hypothesis arising in multigroup measurement invariance models concerning a specific level of invariance. This requires the lavaan package.
semPower.powerMI(type, comparison = NULL, nullEffect = NULL, ...)
semPower.powerMI(type, comparison = NULL, nullEffect = NULL, ...)
type |
type of power analysis, one of |
comparison |
comparison model, either |
nullEffect |
defines the hypothesis (i.e., level of invariance) of interest. One of |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising in the context of multigroup measurement invariance. Multigroup invariance models fit the specified model simultaneously to various groups and place increasingly restrictive cross-group equality constrains on the model parameters. The typical - but not in all parts necessary - sequence is (a) configural, (b) metric, (c) scalar, and (d) residual invariance, where each level of invariance is compared against the previous level (e.g., scalar vs. metric). Power analysis provides the power (or the required N) to reject a particular level of invariance.
For hypotheses regarding longitudinal invariance, see semPower.powerLI()
.
The models defined in the comparison
and the nullEffect
arguments can be specified in two ways. Either specify
a specific level of invariance that includes all previous levels:
'configural'
: no invariance constraints. Shows the same fit as the saturated model, so only the delta df differ.
'metric'
: all loadings are restricted to equality.
'scalar'
: all loadings and (indicator-)intercepts are restricted to equality.
'residual'
: all loadings, (indicator-)intercepts, and (indicator-)residuals are restricted to equality.
'covariances'
: all loadings, (indicator-)intercepts, and (indicator-)residuals, and latent covariances are restricted to equality.
'means'
: all loadings, (indicator-)intercepts, (indicator-)residuals, latent covariances, and latent means are restricted to equality.
For example, setting comparison = 'metric'
and nullEffect = 'scalar'
determines power
to reject the hypothesis that the constraints placed in the scalar invariance model
(restricting loadings and intercepts) over the
metric invariance model (restricting only the loadings) are defensible.
For greater flexibility, the models can also be defined using lavaan
style group.equal
restrictions as a vector:
'none'
: no invariance constraints and thus representing a configural invariance model. Shows the same fit as the saturated model, so only the delta df differ.
c('loadings')
: all loadings are restricted to equality.
c('loadings', 'intercepts')
: all loadings and (indicator-)intercepts are restricted to equality.
c('loadings', 'intercepts', 'residuals')
: all loadings, (indicator-)intercepts, and (indicator-)residuals are restricted to equality.
c('loadings', 'residuals')
: all loadings and (indicator-)residuals are restricted to equality.
c('loadings', 'intercepts', 'means')
: all loadings, (indicator-)intercepts, and latent factor means are restricted to equality.
For example, setting comparison = c('loadings')
and nullEffect = 'c('loadings', 'intercepts')'
determines power to reject the hypothesis that the constraints placed in the scalar invariance model
(restricting loadings and intercepts) over the metric invariance model (restricting only the loadings) are defensible.
Note that variance scaling is used, so invariance of variances ('lv.variances'
) is always met.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
Theta
: Variance-covariance matrix of the indicator residuals, which should be a diagonal matrix. Required when residual non-invariance is to be detected. When NULL
, Theta is a diagonal matrix with elements such that all variances are 1.
tau
: Defines the item intercepts, required whenever a model involves hypotheses about means (e.g., scalar invariance). If NULL
and Alpha
is set, all intercepts are assumed to equal zero.
Alpha
: Defines the latent means, required whenever a model involves hypotheses about latent means (e.g., latent mean invariance). If NULL
and tau
is set, all latent means are assumed to equal zero. Because variance scaling is used so that all factor variances are 1, latent mean differences can be interpreted akin to Cohen's d as standardized mean differences.
So either Lambda
, or loadings
, or nIndicator
and loadM
always need to be defined,
and Theta
, tau
and Alpha
need to be defined for particular levels of invariance.
As this function operates on multiple groups, either argument is a list whenever there are
group differences in the respective parameters. When no list is provided, the same
parameter values are assumed for all groups.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # obtain the required N to reject the hypothesis of metric invariance # in comparison to the configural invariance model # with a power of 95% on alpha = 5% # assuming equally sized groups (N = list(1, 1)) # for a factor model involving a single factor which # is measured by 5 indicators (in both groups) # loading by .5 each in the first group and # loading by .6 each in the second group. powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'configural', nullEffect = 'metric', nIndicator = list(5, 5), loadM = list(.5, .6), alpha = .05, beta = .05, N = list(1, 1)) # show summary summary(powerMI) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerMI$modelH1, sample.cov = list(powerMI$Sigma[[1]], powerMI$Sigma[[2]]), sample.nobs = as.list(powerMI$requiredN.g), sample.cov.rescale = FALSE) lavaan::sem(powerMI$modelH0, sample.cov = list(powerMI$Sigma[[1]], powerMI$Sigma[[2]]), sample.nobs = as.list(powerMI$requiredN.g), sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 in each group on alpha = .05 powerMI <- semPower.powerMI(type = 'post-hoc', comparison = 'configural', nullEffect = 'metric', nIndicator = 5, loadM = list(.5, .6), alpha = .05, N = list(500, 500)) # same as above, but determine the critical chi-square with N = 500 in each # group so that alpha = beta powerMI <- semPower.powerMI(type = 'compromise', comparison = 'configural', nullEffect = 'metric', nIndicator = 5, loadM = list(.5, .6), abratio = 1, N = list(500, 500)) # same as above, but compare to the saturated model # (rather than to the configural invariance model) powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'saturated', nullEffect = 'metric', nIndicator = 5, loadM = list(.5, .6), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but provide individual factor loadings by group using a # reduced loading matrix to define a single factor model with three indicators # loading by .4, .6, .5 in the first group and # loading by .5, .6, .7 in the second group powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'saturated', nullEffect = 'metric', loadings = list( list(c(.4, .6, .5)), list(c(.5, .6, .7))), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but make first group twice as large as the second group powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'saturated', nullEffect = 'metric', loadings = list( list(c(.4, .6, .5)), list(c(.5, .6, .7))), alpha = .05, beta = .05, N = list(2, 1)) # obtain the required N to reject the hypothesis of scalar invariance # in comparison to the metric invariance model # with a power of 95% on alpha = 5% # assuming equally sized groups (N = list(1, 1)) # for a two factor model, where both factors are # measured by 3 indicators each and all loadings equal .5 (in both groups), # the factor correlation is .3 in both groups, and the # all intercepts are 0.0 in the first group, but # the intercepts are .1, .2, .3, .4, .5, .6 in the second group powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'metric', nullEffect = 'scalar', Phi = list(.3, .3), nIndicator = list( c(3, 3), c(3, 3)), loadM = .5, tau = list( rep(0.0, 6), seq(.1, .6, .1) ), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but use lavaan group.equal strings powerMI <- semPower.powerMI(type = 'a-priori', comparison = c('loadings'), nullEffect = c('loadings', 'intercepts'), Phi = list(.3, .3), nIndicator = list( c(3, 3), c(3, 3)), loadM = .5, tau = list( rep(0.0, 6), seq(.1, .6, .1) ), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but # obtain the required N to reject the hypothesis of equal latent means # in comparison to the scalar invariance model; # all intercepts are zero in both groups, # in the first group, the latent means equal 0.0, # in the second group, the latent mean of the factors are 0.0 and 0.5 powerMI <- semPower.powerMI(type = 'a-priori', comparison = c('loadings', 'intercepts'), nullEffect = c('loadings', 'intercepts', 'means'), Phi = list(.3, .3), nIndicator = list( c(3, 3), c(3, 3)), loadM = .5, tau = list( rep(0.0, 6), rep(0.0, 6) ), Alpha = list( c(0.0, 0.0), c(0.0, 0.5) ), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications # to reject the hypothesis of metric invariance. set.seed(300121) powerMI <- semPower.powerMI(type = 'post-hoc', comparison = 'configural', nullEffect = 'metric', nIndicator = list(5, 5), loadM = list(.5, .6), alpha = .05, N = list(500, 500), simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
## Not run: # obtain the required N to reject the hypothesis of metric invariance # in comparison to the configural invariance model # with a power of 95% on alpha = 5% # assuming equally sized groups (N = list(1, 1)) # for a factor model involving a single factor which # is measured by 5 indicators (in both groups) # loading by .5 each in the first group and # loading by .6 each in the second group. powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'configural', nullEffect = 'metric', nIndicator = list(5, 5), loadM = list(.5, .6), alpha = .05, beta = .05, N = list(1, 1)) # show summary summary(powerMI) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerMI$modelH1, sample.cov = list(powerMI$Sigma[[1]], powerMI$Sigma[[2]]), sample.nobs = as.list(powerMI$requiredN.g), sample.cov.rescale = FALSE) lavaan::sem(powerMI$modelH0, sample.cov = list(powerMI$Sigma[[1]], powerMI$Sigma[[2]]), sample.nobs = as.list(powerMI$requiredN.g), sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 in each group on alpha = .05 powerMI <- semPower.powerMI(type = 'post-hoc', comparison = 'configural', nullEffect = 'metric', nIndicator = 5, loadM = list(.5, .6), alpha = .05, N = list(500, 500)) # same as above, but determine the critical chi-square with N = 500 in each # group so that alpha = beta powerMI <- semPower.powerMI(type = 'compromise', comparison = 'configural', nullEffect = 'metric', nIndicator = 5, loadM = list(.5, .6), abratio = 1, N = list(500, 500)) # same as above, but compare to the saturated model # (rather than to the configural invariance model) powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'saturated', nullEffect = 'metric', nIndicator = 5, loadM = list(.5, .6), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but provide individual factor loadings by group using a # reduced loading matrix to define a single factor model with three indicators # loading by .4, .6, .5 in the first group and # loading by .5, .6, .7 in the second group powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'saturated', nullEffect = 'metric', loadings = list( list(c(.4, .6, .5)), list(c(.5, .6, .7))), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but make first group twice as large as the second group powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'saturated', nullEffect = 'metric', loadings = list( list(c(.4, .6, .5)), list(c(.5, .6, .7))), alpha = .05, beta = .05, N = list(2, 1)) # obtain the required N to reject the hypothesis of scalar invariance # in comparison to the metric invariance model # with a power of 95% on alpha = 5% # assuming equally sized groups (N = list(1, 1)) # for a two factor model, where both factors are # measured by 3 indicators each and all loadings equal .5 (in both groups), # the factor correlation is .3 in both groups, and the # all intercepts are 0.0 in the first group, but # the intercepts are .1, .2, .3, .4, .5, .6 in the second group powerMI <- semPower.powerMI(type = 'a-priori', comparison = 'metric', nullEffect = 'scalar', Phi = list(.3, .3), nIndicator = list( c(3, 3), c(3, 3)), loadM = .5, tau = list( rep(0.0, 6), seq(.1, .6, .1) ), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but use lavaan group.equal strings powerMI <- semPower.powerMI(type = 'a-priori', comparison = c('loadings'), nullEffect = c('loadings', 'intercepts'), Phi = list(.3, .3), nIndicator = list( c(3, 3), c(3, 3)), loadM = .5, tau = list( rep(0.0, 6), seq(.1, .6, .1) ), alpha = .05, beta = .05, N = list(1, 1)) # same as above, but # obtain the required N to reject the hypothesis of equal latent means # in comparison to the scalar invariance model; # all intercepts are zero in both groups, # in the first group, the latent means equal 0.0, # in the second group, the latent mean of the factors are 0.0 and 0.5 powerMI <- semPower.powerMI(type = 'a-priori', comparison = c('loadings', 'intercepts'), nullEffect = c('loadings', 'intercepts', 'means'), Phi = list(.3, .3), nIndicator = list( c(3, 3), c(3, 3)), loadM = .5, tau = list( rep(0.0, 6), rep(0.0, 6) ), Alpha = list( c(0.0, 0.0), c(0.0, 0.5) ), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications # to reject the hypothesis of metric invariance. set.seed(300121) powerMI <- semPower.powerMI(type = 'post-hoc', comparison = 'configural', nullEffect = 'metric', nIndicator = list(5, 5), loadM = list(.5, .6), alpha = .05, N = list(500, 500), simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
Convenience function for performing power analyses for hypothesis arising in a generic path model. This requires the lavaan package.
semPower.powerPath( type, comparison = "restricted", Beta, Psi = NULL, nullEffect = "beta = 0", nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, ... )
semPower.powerPath( type, comparison = "restricted", Beta, Psi = NULL, nullEffect = "beta = 0", nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
Beta |
matrix of regression slopes between latent variables (all-Y notation). A list for multiple group models. Exogenous variables must occupy the first rows in |
Psi |
variance-covariance matrix of latent (residual) factors. If |
nullEffect |
defines the hypothesis of interest, must be one of |
nullWhich |
vector of size 2 indicating which slope in |
nullWhichGroups |
for |
standardized |
whether all parameters should be standardized ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject a hypothesis arising in a generic structural equation model specifying regression relations between the factors via the Beta matrix:
nullEffect = 'beta = 0'
: Tests the hypothesis that a slope is zero.
nullEffect = 'betaX = betaZ'
: Tests the hypothesis that two or more slopes are equal to each other.
nullEffect = 'betaA = betaB'
: Tests the hypothesis that a slope is equal in two or more groups (always assuming metric invariance).
This function provides a generic way to perform power analyses (as compared to other functions covering special cases in a more accessible manner).
A specific hypothesis is defined by setting nullEffect
to define the hypothesis type,
nullWhich
to define the slope(s) that are targeted, and by providing
the Beta
(and optionally the Psi
) matrix to define the population structure.
To understand the structure of Beta
and Psi
, consider the general structural equation model,
where is the
matrix containing the regression slopes and
is the (residual) variance-covariance matrix of the
factors.
As an example, suppose there are four factors (X1, X2, X3, X4), and Beta is defined as follows:
Each row specifies how a particular factor is predicted by the available factors, so the above implies the following regression relations:
which simplifies to
Further suppose that Psi is
which implies a correlation between X1 and X2 of .3 and a residual correlation between X3 and X4 of .2.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
always need to be defined.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # set up pathmodel in the form of # f2 = .2*f1 # f3 = .3*f2 # f4 = .1*f1 + .4*f3 # obtain the required N to detect that the # slope f1 -> f4 is >= .10 # with a power of 95% on alpha = 5% # where f1 is measured by 3, f2 by 4, f3 by 5, and f4 by 6 indicators, # and all loadings are .5 Beta <- matrix(c( c(.00, .00, .00, .00), # f1 c(.20, .00, .00, .00), # f2 c(.00, .30, .00, .00), # f3 c(.10, .00, .40, .00) # f4 ), byrow = TRUE, ncol = 4) powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullWhich = c(4, 1), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05) # show summary summary(powerPath) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerPath$modelH1, sample.cov = powerPath$Sigma, sample.nobs = powerPath$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerPath$modelH0, sample.cov = powerPath$Sigma, sample.nobs = powerPath$requiredN, sample.cov.rescale = FALSE) # same as above, but detect that the slope f3 -> f4 is >= .30 powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullWhich = c(4, 3), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05) # same as above, but detect that # the slope f1 -> f2 (of .20) differs from the slope f2 -> f3 (of .30) powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullEffect = 'betaX = betaZ', nullWhich = list(c(2, 1), c(3, 2)), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05) # same as above, but consider a multiple group model with equally sized groups, # and obtain the required N to detect that the slope # in group 1 (of .20) differs from the one in group 2 (of .40) Beta1 <- Beta2 <- matrix(c( c(.00, .00, .00, .00), # f1 c(.20, .00, .00, .00), # f2 c(.00, .30, .00, .00), # f3 c(.10, .00, .40, .00) # f4 ), byrow = TRUE, ncol = 4) Beta2[2, 1] <- .40 Beta <- list(Beta1, Beta2) powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullEffect = 'betaA = betaB', nullWhich = c(2, 1), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05, N = list(1, 1)) ## End(Not run)
## Not run: # set up pathmodel in the form of # f2 = .2*f1 # f3 = .3*f2 # f4 = .1*f1 + .4*f3 # obtain the required N to detect that the # slope f1 -> f4 is >= .10 # with a power of 95% on alpha = 5% # where f1 is measured by 3, f2 by 4, f3 by 5, and f4 by 6 indicators, # and all loadings are .5 Beta <- matrix(c( c(.00, .00, .00, .00), # f1 c(.20, .00, .00, .00), # f2 c(.00, .30, .00, .00), # f3 c(.10, .00, .40, .00) # f4 ), byrow = TRUE, ncol = 4) powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullWhich = c(4, 1), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05) # show summary summary(powerPath) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerPath$modelH1, sample.cov = powerPath$Sigma, sample.nobs = powerPath$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerPath$modelH0, sample.cov = powerPath$Sigma, sample.nobs = powerPath$requiredN, sample.cov.rescale = FALSE) # same as above, but detect that the slope f3 -> f4 is >= .30 powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullWhich = c(4, 3), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05) # same as above, but detect that # the slope f1 -> f2 (of .20) differs from the slope f2 -> f3 (of .30) powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullEffect = 'betaX = betaZ', nullWhich = list(c(2, 1), c(3, 2)), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05) # same as above, but consider a multiple group model with equally sized groups, # and obtain the required N to detect that the slope # in group 1 (of .20) differs from the one in group 2 (of .40) Beta1 <- Beta2 <- matrix(c( c(.00, .00, .00, .00), # f1 c(.20, .00, .00, .00), # f2 c(.00, .30, .00, .00), # f3 c(.10, .00, .40, .00) # f4 ), byrow = TRUE, ncol = 4) Beta2[2, 1] <- .40 Beta <- list(Beta1, Beta2) powerPath <- semPower.powerPath(type = 'a-priori', Beta = Beta, nullEffect = 'betaA = betaB', nullWhich = c(2, 1), nIndicator = c(3, 4, 5, 6), loadM = .5, alpha = .05, beta = .05, N = list(1, 1)) ## End(Not run)
Shows a plot showing power as function of N given the output of a power analysis.
semPower.powerPlot(semPowerRes, ...)
semPower.powerPlot(semPowerRes, ...)
semPowerRes |
results of a semPower analysis |
... |
other parameters passed to |
powerplot
## Not run: # perform a power analysis powerCFA <- semPower.powerCFA(type = 'post-hoc', alpha = .05, N = 300, Phi = .15, nIndicator = c(5, 4), loadM = c(.5, .6)) # show plot semPower.powerPlot(powerCFA) ## End(Not run)
## Not run: # perform a power analysis powerCFA <- semPower.powerCFA(type = 'post-hoc', alpha = .05, N = 300, Phi = .15, nIndicator = c(5, 4), loadM = c(.5, .6)) # show plot semPower.powerPlot(powerCFA) ## End(Not run)
Shows a plot showing power as function of the effect for a given N and alpha.
semPower.powerPlot.byEffect( effect.measure = NULL, alpha, N, df, p = NULL, effect.min = NULL, effect.max = NULL, steps = 50, linewidth = 1 )
semPower.powerPlot.byEffect( effect.measure = NULL, alpha, N, df, p = NULL, effect.min = NULL, effect.max = NULL, steps = 50, linewidth = 1 )
effect.measure |
type of effect, one of |
alpha |
alpha error |
N |
the number of observations |
df |
the model degrees of freedom |
p |
the number of observed variables, required for |
effect.min |
minimum effect |
effect.max |
maximum effect |
steps |
number of steps |
linewidth |
linewidth |
powerplot
## Not run: semPower.powerPlot.byEffect(effect.measure = "RMSEA", alpha = .05, N = 500, effect.min = .01, effect.max = .15, df = 200) ## End(Not run)
## Not run: semPower.powerPlot.byEffect(effect.measure = "RMSEA", alpha = .05, N = 500, effect.min = .01, effect.max = .15, df = 200) ## End(Not run)
Shows a plot showing power as function of N for a given effect and alpha.
semPower.powerPlot.byN( effect = NULL, effect.measure = NULL, alpha, df, p = NULL, SigmaHat = NULL, Sigma = NULL, power.min = alpha, power.max = 0.99, steps = 50, linewidth = 1 )
semPower.powerPlot.byN( effect = NULL, effect.measure = NULL, alpha, df, p = NULL, SigmaHat = NULL, Sigma = NULL, power.min = alpha, power.max = 0.99, steps = 50, linewidth = 1 )
effect |
effect size specifying the discrepancy between H0 and H1 |
effect.measure |
type of effect, one of |
alpha |
alpha error |
df |
the model degrees of freedom |
p |
the number of observed variables, required for |
SigmaHat |
model implied covariance matrix. Use in conjunction with |
Sigma |
population covariance matrix. Use in conjunction with |
power.min |
minimum power, must not be smaller than |
power.max |
maximum power |
steps |
number of steps |
linewidth |
linewidth |
powerplot
## Not run: semPower.powerPlot.byN(effect = .05, effect.measure = "RMSEA", alpha = .05, power.min = .05, power.max = .99, df = 200) ## End(Not run)
## Not run: semPower.powerPlot.byN(effect = .05, effect.measure = "RMSEA", alpha = .05, power.min = .05, power.max = .99, df = 200) ## End(Not run)
Convenience function for performing power analysis on slope(s) in a latent regression of the form Y = XB. This requires the lavaan package.
semPower.powerRegression( type, comparison = "restricted", slopes = NULL, corXX = NULL, nullEffect = "slope = 0", nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, ... )
semPower.powerRegression( type, comparison = "restricted", slopes = NULL, corXX = NULL, nullEffect = "slope = 0", nullWhich = NULL, nullWhichGroups = NULL, standardized = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
slopes |
vector of slopes (or a single number for a single slope) of the k predictors for Y. A list of slopes for multigroup models. |
corXX |
correlation(s) between the k predictors (X). Either |
nullEffect |
defines the hypothesis of interest, must be one of |
nullWhich |
single number indicating which slope is hypothesized to equal zero when |
nullWhichGroups |
for |
standardized |
whether all parameters should be standardized ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising
in SEM models involving a simple regression relation of the form Y = b_1*X_1 + ... + b_k*X_k
between the factors:
nullEffect = 'slope = 0'
: Tests the hypothesis that the slope for a predictor is zero.
nullEffect = 'slopeX = slopeZ'
: Tests the hypothesis that two or more slopes are equal to each other.
nullEffect = 'slopeA = slopeB'
: Tests the hypothesis that the slope for a predictor is equal in two or more groups (always assuming metric invariance).
For hypotheses regarding mediation effects, see semPower.powerMediation()
. For hypothesis in autoregressive models, see semPower.powerAutoreg()
.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling the number of factors).
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure, e. g. loadings = list(c(.5, .4, .6), c(.8, .6, .6, .4))
defines a two factor model with three indicators loading on the first factor by .5, , 4., and .6, and four indicators loading on the second factor by .8, .6, .6, and .4.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators by factor, e. g., nIndicator = c(3, 4)
defines a two factor model with three and four indicators for the first and second factor, respectively. nIndicator
can also be a single number to define the same number of indicators for each factor.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor (if a vector is provided), e. g. loadM = c(.5, .6)
defines the loadings of the first factor to equal .5 and those of the second factor do equal .6.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
Note that the first factor acts as the criterion Y, the subsequent factors as predictors X_1 to X_k.
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # latent regression of the form `Y = .2*X1 + .3*X2`, where X1 and X2 correlate by .4 # obtain required N to reject the hypothesis that the slope of X1 is zero # with a power of 95% on alpha = 5%, # where Y is measured by 3 indicators loading by .5 each, # X1 by 5 indicators loading by .6 each, and # X2 by 4 indicators loading by .7 each. powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 1, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # show summary summary(powerReg) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerReg$modelH1, sample.cov = powerReg$Sigma, sample.nobs = powerReg$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerReg$modelH0, sample.cov = powerReg$Sigma, sample.nobs = powerReg$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerReg <- semPower.powerRegression(type = 'post-hoc', slopes = c(.2, .3), corXX = .4, nullWhich = 1, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerReg <- semPower.powerRegression(type = 'compromise', slopes = c(.2, .3), corXX = .4, nullWhich = 1, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), abratio = .05, N = 500) # same as above, but ask for the required N to detect that the slope of X2 is zero powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 2, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but define unstandardized slopes powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 2, standardized = FALSE, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerReg <- semPower.powerRegression(type = 'a-priori', comparison = 'saturated', slopes = c(.2, .3), corXX = .4, nullWhich = 2, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but provide a reduced loading matrix defining # three indicators with loadings of .7, .6, .5 on the first factor (Y), # four indicators with loadings of .5, .6, .4, .8 on the second factor (X1), and # three indicators with loadings of .8, .7, .8 on the third factor (X2). powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 2, loadings = list( c(.7, .6, .5), c(.5, .6, .4, .8), c(.8, .7, .8)), alpha = .05, beta = .05) # latent regression of the form `Y = .2*X1 + .3*X2 + .4*X3`, # providing the predictor intercorrelation matrix, # and ask for the required N to detect that the first slope differs from zero. corXX <- matrix(c( # X1 X2 X3 c(1.00, 0.20, 0.30), # X1 c(0.20, 1.00, 0.10), # X2 c(0.30, 0.10, 1.00) # X3 ), ncol = 3,byrow = TRUE) powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3, .4), corXX = corXX, nullWhich = 1, nIndicator = c(4, 3, 5, 4), loadM = c(.5, .5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for the required N to detect that # the slope for X1 (b = .2) and the slope for X2 (b = .3) differ from each other powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3, .4), corXX = corXX, nullEffect = 'slopeX = slopeZ', nullWhich = c(1, 2), nIndicator = c(4, 3, 5, 4), loadM = c(.5, .5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for the required N to reject the hypothesis that # all three slopes are equal to each other powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3, .4), corXX = corXX, nullEffect = 'slopeX = slopeZ', nullWhich = c(1, 2, 3), nIndicator = c(4, 3, 5, 4), loadM = c(.5, .5, .6, .7), alpha = .05, beta = .05) # get required N to detect that # the slope for X2 group 1 (of b2 = .3) differs from the slope for X2 in group 2 (of b = .0). # The remaining slopes are equal in both groups (b1 = .2, b3 = .4). # The measurement model is identical in both groups: # The criterion (Y) is measured by 4 indicators loading by .5 each, # Predictors X1 and X3 are both measured by 5 indicators loading by .6 each, # Predictor X2 is measured by 3 indicators loading by .7 each. # Both groups are sized equally (N = list(1, 1)). powerReg <- semPower.powerRegression(type = 'a-priori', slopes = list(c(.2, .3, .4), c(.2, .0, .4)), corXX = corXX, nullEffect = 'slopeA = slopeB', nullWhich = 2, nIndicator = c(4, 5, 3, 5), loadM = c(.5, .6, .7, .6), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications # to detect that the slope of X1 differs from zero. set.seed(300121) powerReg <- semPower.powerRegression(type = 'post-hoc', slopes = c(.2, .1), nullWhich = 1, nIndicator = c(4, 3, 3), loadM = .5, alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
## Not run: # latent regression of the form `Y = .2*X1 + .3*X2`, where X1 and X2 correlate by .4 # obtain required N to reject the hypothesis that the slope of X1 is zero # with a power of 95% on alpha = 5%, # where Y is measured by 3 indicators loading by .5 each, # X1 by 5 indicators loading by .6 each, and # X2 by 4 indicators loading by .7 each. powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 1, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # show summary summary(powerReg) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerReg$modelH1, sample.cov = powerReg$Sigma, sample.nobs = powerReg$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerReg$modelH0, sample.cov = powerReg$Sigma, sample.nobs = powerReg$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerReg <- semPower.powerRegression(type = 'post-hoc', slopes = c(.2, .3), corXX = .4, nullWhich = 1, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerReg <- semPower.powerRegression(type = 'compromise', slopes = c(.2, .3), corXX = .4, nullWhich = 1, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), abratio = .05, N = 500) # same as above, but ask for the required N to detect that the slope of X2 is zero powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 2, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but define unstandardized slopes powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 2, standardized = FALSE, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerReg <- semPower.powerRegression(type = 'a-priori', comparison = 'saturated', slopes = c(.2, .3), corXX = .4, nullWhich = 2, nIndicator = c(3, 5, 4), loadM = c(.5, .6, .7), alpha = .05, beta = .05) # same as above, but provide a reduced loading matrix defining # three indicators with loadings of .7, .6, .5 on the first factor (Y), # four indicators with loadings of .5, .6, .4, .8 on the second factor (X1), and # three indicators with loadings of .8, .7, .8 on the third factor (X2). powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3), corXX = .4, nullWhich = 2, loadings = list( c(.7, .6, .5), c(.5, .6, .4, .8), c(.8, .7, .8)), alpha = .05, beta = .05) # latent regression of the form `Y = .2*X1 + .3*X2 + .4*X3`, # providing the predictor intercorrelation matrix, # and ask for the required N to detect that the first slope differs from zero. corXX <- matrix(c( # X1 X2 X3 c(1.00, 0.20, 0.30), # X1 c(0.20, 1.00, 0.10), # X2 c(0.30, 0.10, 1.00) # X3 ), ncol = 3,byrow = TRUE) powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3, .4), corXX = corXX, nullWhich = 1, nIndicator = c(4, 3, 5, 4), loadM = c(.5, .5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for the required N to detect that # the slope for X1 (b = .2) and the slope for X2 (b = .3) differ from each other powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3, .4), corXX = corXX, nullEffect = 'slopeX = slopeZ', nullWhich = c(1, 2), nIndicator = c(4, 3, 5, 4), loadM = c(.5, .5, .6, .7), alpha = .05, beta = .05) # same as above, but ask for the required N to reject the hypothesis that # all three slopes are equal to each other powerReg <- semPower.powerRegression(type = 'a-priori', slopes = c(.2, .3, .4), corXX = corXX, nullEffect = 'slopeX = slopeZ', nullWhich = c(1, 2, 3), nIndicator = c(4, 3, 5, 4), loadM = c(.5, .5, .6, .7), alpha = .05, beta = .05) # get required N to detect that # the slope for X2 group 1 (of b2 = .3) differs from the slope for X2 in group 2 (of b = .0). # The remaining slopes are equal in both groups (b1 = .2, b3 = .4). # The measurement model is identical in both groups: # The criterion (Y) is measured by 4 indicators loading by .5 each, # Predictors X1 and X3 are both measured by 5 indicators loading by .6 each, # Predictor X2 is measured by 3 indicators loading by .7 each. # Both groups are sized equally (N = list(1, 1)). powerReg <- semPower.powerRegression(type = 'a-priori', slopes = list(c(.2, .3, .4), c(.2, .0, .4)), corXX = corXX, nullEffect = 'slopeA = slopeB', nullWhich = 2, nIndicator = c(4, 5, 3, 5), loadM = c(.5, .6, .7, .6), alpha = .05, beta = .05, N = list(1, 1)) # request a simulated post-hoc power analysis with 500 replications # to detect that the slope of X1 differs from zero. set.seed(300121) powerReg <- semPower.powerRegression(type = 'post-hoc', slopes = c(.2, .1), nullWhich = 1, nIndicator = c(4, 3, 3), loadM = .5, alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
Convenience function for performing power analysis on effects in a random intercept cross-lagged panel model (RI-CLPM). This requires the lavaan package.
semPower.powerRICLPM( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, crossedEffects = NULL, rXY = NULL, rBXBY = NULL, waveEqual = NULL, nullEffect = NULL, nullWhichGroups = NULL, nullWhich = NULL, standardized = TRUE, metricInvariance = TRUE, autocorResiduals = TRUE, ... )
semPower.powerRICLPM( type, comparison = "restricted", nWaves = NULL, autoregEffects = NULL, crossedEffects = NULL, rXY = NULL, rBXBY = NULL, waveEqual = NULL, nullEffect = NULL, nullWhichGroups = NULL, nullWhich = NULL, standardized = TRUE, metricInvariance = TRUE, autocorResiduals = TRUE, ... )
type |
type of power analysis, one of |
comparison |
comparison model, one of |
nWaves |
number of waves, must be >= 3. |
autoregEffects |
vector of the autoregressive effects of X and Y (constant across waves), or a list of vectors of autoregressive effects for X and Y from wave to wave, e.g. |
crossedEffects |
vector of crossed effects of X on Y (X -> Y) and vice versa (both constant across waves), or a list of vectors of crossed effects giving the crossed effect of X on Y (and vice versa) for each wave, e.g. |
rXY |
vector of (residual-)correlations between X and Y for each wave. If |
rBXBY |
correlation between random intercept factors. If |
waveEqual |
parameters that are assumed to be equal across waves in both the H0 and the H1 model. Valid are |
nullEffect |
defines the hypothesis of interest. Valid are the same arguments as in |
nullWhichGroups |
for hypothesis involving cross-groups comparisons, vector indicating the groups for which equality constrains should be applied, e.g. |
nullWhich |
used in conjunction with |
standardized |
whether the autoregressive and cross-lagged parameters should be treated as standardized ( |
metricInvariance |
whether metric invariance over waves is assumed ( |
autocorResiduals |
whether the residuals of the indicators of latent variables are autocorrelated over waves ( |
... |
mandatory further parameters related to the specific type of power analysis requested, see |
This function performs a power analysis to reject various hypotheses arising in a random intercept crossed-lagged panel model (RI-CLPM).
In a standard RI-CLPM implemented here, two variables X and Y are repeatedly assessed at three or more different time points (nWaves
),
yielding autoregressive effects (X1 -> X2
, X2 -> X3
, Y1 -> Y2
, Y2 -> Y3
), synchronous effects (X1 <-> Y1
, X2 <-> Y2
, X3 <-> Y3
), and cross-lagged effects (X1 -> Y2
, X2 -> Y3
, Y1 -> X2
, Y2 -> X3
).
RI-CLPMs are typically implemented assuming that the parameters are constant across waves (waveEqual
), and usually omit lag-2 effects (e.g., X1 -> Y3
).
RI-CLPMs based on latent factors usually assume at least metric invariance of the factors over waves (metricInvariance
).
Relevant hypotheses in arising in a RI-CLPM are:
autoregX = 0
and autoregY = 0
: Tests the hypothesis that the autoregressive effect of X and Y, respectively, is zero.
crossedX = 0
and crossedY = 0
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) and Y on X (crossedY
), respectively, is zero.
autoregX = autoregY
: Tests the hypothesis that the autoregressive effect of X and Y are equal.
crossedX = crossedY
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) and Y on X (crossedY
) are equal.
autoregX
and autoregY
: Tests the hypothesis that the autoregressive effect of X and Y, respectively, is equal across waves.
crossedX
and crossedY
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) and Y on X (crossedY
), respectively, is equal across waves.
corXY
: Tests the hypothesis that the (residual-)correlations between X and Y are equal across waves.
corBXBY = 0
: Tests the hypothesis that the correlation between the random intercept factors of X and Y is zero.
autoregXA = autoregXB
and autoregYA = autoregYB
: Tests the hypothesis that the autoregressive effect of either X or Y are equal across groups.
crossedXA = crossedXB
and crossedYA = crossedYB
: Tests the hypothesis that the crossed effect of X on Y (crossedX
) or of Y on X (crossedY
), respectively, is equal across groups.
corBXBYA = corBXBYB
: Tests the hypothesis that the correlation between the random intercept factors is equal across groups.
For hypotheses regarding the traditional CLPM, see semPower.powerCLPM()
.
Beyond the arguments explicitly contained in the function call, additional arguments are required specifying the factor model and the requested type of power analysis.
Additional arguments related to the definition of the factor model:
Lambda
: The factor loading matrix (with the number of columns equaling 2 times the number of waves). Columns should be in order X1, Y1, X2, Y2, ..., X_nWaves, Y_nWaves.
loadings
: Can be used instead of Lambda
: Defines the primary loadings for each factor in a list structure ordered by wave, e.g., list(c(.2, .2, .2), c(.4, .4, .4, .4), c(.2, .2, .2), c(.4, .4, .4, .4), c(.2, .2, .2), c(.4, .4, .4, .4)) defines loadings of .2 for the three indicators of X at waves 1-3 and loadings of .4 for the four indicators of Y at waves 1-3. Must not contain secondary loadings.
nIndicator
: Can be used instead of Lambda
: Used in conjunction with loadM
. Defines the number of indicators for each factor ordered by wave, e.g. c(3, 4, 3, 4, 3, 4) defines three indicators for X at waves 1-3 and four indicators for Y at waves 1-3.
loadM
: Can be used instead of Lambda
: Used in conjunction with nIndicator
. Defines the loading either for all indicators (if a single number is provided) or separately for each factor at each wave (if a vector is provided), e. g. loadM = c(.5, .6, .5, .6, .5, .6)
defines mean loadings of .5 for X at waves 1-3 and mean loadings of .6 for Y at waves 1-3.
So either Lambda
, or loadings
, or nIndicator
and loadM
need to be defined.
If the model contains observed variables only, use Lambda = diag(x)
where x
is the number of variables.
Note that the order of the factors is (X1, Y1, X2, Y2, ..., X_nWaves, Y_nWaves), i. e., the first factor is treated as the first measurement of X, the second as the first measurement of Y, the third as the second measurement of X, etc..
Additional arguments related to the requested type of power analysis:
alpha
: The alpha error probability. Required for type = 'a-priori'
and type = 'post-hoc'
.
Either beta
or power
: The beta error probability and the statistical power (1 - beta), respectively. Only for type = 'a-priori'
.
N
: The sample size. Always required for type = 'post-hoc'
and type = 'compromise'
. For type = 'a-priori'
and multiple group analysis, N
is a list of group weights.
abratio
: The ratio of alpha to beta. Only for type = 'compromise'
.
If a simulated power analysis (simulatedPower = TRUE
) is requested, optional arguments can be provided as a list to simOptions
:
nReplications
: The targeted number of simulation runs. Defaults to 250, but larger numbers greatly improve accuracy at the expense of increased computation time.
minConvergenceRate
: The minimum convergence rate required, defaults to .5. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RC'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of MCAR
(the default), MAR
, or NMAR
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doSNOW
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
a list. Use the summary
method to obtain formatted results. Beyond the results of the power analysis and a number of effect size measures, the list contains the following components:
Sigma |
the population covariance matrix. A list for multiple group models. |
mu |
the population mean vector or |
SigmaHat |
the H0 model implied covariance matrix. A list for multiple group models. |
muHat |
the H0 model implied mean vector or |
modelH0 |
|
modelH1 |
|
simRes |
detailed simulation results when a simulated power analysis ( |
semPower.genSigma()
semPower.aPriori()
semPower.postHoc()
semPower.compromise()
## Not run: # Determine required N in a 3-wave RI-CLPM # to detect crossed effects of X (X1 -> Y2 and X2 -> Y3) of >= .2 # with a power of 95% on alpha = 5%, where # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .4 each, and # there is no synchronous correlation between X and Y (rXY = NULL), # the correlation between the random intercept factors of X and Y (rBXBY) is .1, # the autoregressive effects of X are .8 (equal across waves), # the autoregressive effects of Y are .7 (equal across waves), and # the crossed effects of Y (Y1 -> X2 and Y2 -> X3) are .1 (equal across waves). powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # show summary summary(powerRICLPM) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerRICLPM$modelH1, sample.cov = powerRICLPM$Sigma, sample.nobs = powerRICLPM$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerRICLPM$modelH0, sample.cov = powerRICLPM$Sigma, sample.nobs = powerRICLPM$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerRICLPM <- semPower.powerRICLPM(type = 'post-hoc', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerRICLPM <- semPower.powerRICLPM(type = 'compromise', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerRICLPM <- semPower.powerRICLPM(type = 'compromise', comparison = 'saturated', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), abratio = 1, N = 500) # same as above, but assume only observed variables powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', Lambda = diag(6), alpha = .05, beta = .05) # same as above, but provide reduced loadings matrix to define that # X1, X2, and X3 are measured by 5 indicators each loading by .5, .4, .5, .4, .3 # Y1, Y2, and Y3 are measured by 3 indicators each loading by .4, .3, .2 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', loadings = list( c(.5, .4, .5, .4, .3), # X1 c(.4, .3, .2), # Y1 c(.5, .4, .5, .4, .3), # X2 c(.4, .3, .2), # Y2 c(.5, .4, .5, .4, .3), # X3 c(.4, .3, .2) # Y3 ), alpha = .05, beta = .05) # same as above, but do not assume metric invariance across waves powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), metricInvariance = FALSE, alpha = .05, beta = .05) # same as above, but determine N to detect that the crossed effect of Y # (Y1 -> X2 and Y2 -> X3) is >= .1. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedY = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that the autoregressive effect # of X (X1 -> X2 and X2 -> X3) is >= .8. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'autoregX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that the autoregressive effect # of Y (Y1 -> Y2) is >= .7. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'autoregY = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed effect of X (X1 -> Y2) of .2 differs from # the crossed effect of Y (Y1 -> X2) of .1 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = crossedY', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the autoregressive effect of X (X1 -> X2) of .8 differs from # the autoregressive effect of Y (Y1 -> Y2) of .7 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'autoregX = autoregY', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that the correlation between the # random intercept factors is >= .1 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'corBXBY = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but assume that the synchronous (residual-)correlations between # X and Y are equal across waves, # namely a synchronous correlation of .05 at the first wave and residual correlations # of .05 at the second and third wave, # and determine N to detect a crossed effect of X (X1 -> Y2 and X2 -> Y3) of >= .2 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY', 'corXY'), rXY = c(.05, .05, .05), rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but assume that the synchronous correlation between X and Y # is .3 at the first wave, and the respective residual correlations are .2 at # the second wave and .3 at the third wave, # and determine N to detect that the synchronous residual correlation at wave 2 is => .2. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = c(.3, .2, .3), rBXBY = .1, nullEffect = 'corXY = 0', nullWhich = 2, nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # Determine required N in a 3-wave RI-CLPM to detect that # the crossed effect of X at wave 1 (X1 -> Y2) of .20 is equal to the # the crossed effect of X at wave 2 (X2 -> Y3) of .05 # with a power of 95% on alpha = 5%, where # the autoregressive effects of X and Y are equal over waves, # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .4 each, and # the synchronous correlation between X and Y are .2, .3, and .4 at the first, # second, and third wave, # the correlation between the random intercept factors of X and Y is .1, and # the autoregressive effect of X is .8 across all three waves, # the autoregressive effect of Y is .7 across all three waves, and # the crossed effects of Y (Y1 -> X2, and Y2 -> Y3) are both .1 # (but freely estimated for each wave). powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( # X Y c(.20, .10), # wave 1 -> wave 2 c(.05, .10)), # wave 2 -> wave 3 waveEqual = c('autoregX', 'autoregY'), rXY = c(.2, .3, .4), rBXBY = .1, nullEffect = 'crossedX', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed effect of X at wave 2 is >= .05. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( # X Y c(.20, .10), # wave 1 -> wave 2 c(.05, .10)), # wave 2 -> wave 3 waveEqual = c('autoregX', 'autoregY'), rXY = c(.2, .3, .4), rBXBY = .1, nullEffect = 'crossedX = 0', nullWhich = 2, nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the residual correlation between X and Y at wave 2 (of .3) differs from # the residual correlation between X and Y at wave 3 (of .4). powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( # X Y c(.20, .10), # wave 1 -> wave 2 c(.05, .10)), # wave 2 -> wave 3 waveEqual = c('autoregX', 'autoregY'), rXY = c(.2, .3, .4), rBXBY = .1, nullEffect = 'corXY', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # multigroup example # Determine the achieved power N in a 3-wave RI-CLPM to detect that # the crossed effect of X at wave 1 (X1 -> Y2) in group 1 of .25 differs # from the crossed effect of X at wave 1 (X1 -> Y2) in group 2 of .15, # where both groups comprise 500 observations and alpha = 5%, and # the measurement model is equal for both groups, and # the crossed effects of X (X1 -> Y2, and X2 -> Y3) are .25 and .10 in the first group, # the crossed effects of X (X1 -> Y2, and X2 -> Y3) are .15 and .05 in the second group, # the crossed effects of Y (Y1 -> X2, and Y2 -> X3) are .05 and .15 in the first group, # the crossed effects of Y (Y1 -> X2, and Y2 -> X3) are .01 and .10 in the second group, and # the autoregressive effects of X (of .5) and Y (of .4) are equal over waves and over groups # (but freely estimated in each group). powerRICLPM <- semPower.powerRICLPM(type = 'post-hoc', alpha = .05, N = list(500, 500), nWaves = 3, autoregEffects = c(.5, .4), # group and wave constant crossedEffects = list( # group 1 list( c(.25, .10), # X c(.05, .15) # Y ), # group 2 list( c(.15, .05), # X c(.01, .10) # Y ) ), rXY = NULL, # identity rBXBY = NULL, # identity nullEffect = 'crossedXA = crossedXB', nullWhich = 1, nIndicator = rep(3, 6), loadM = c(.5, .6, .5, .6, .5, .6), metricInvariance = TRUE, waveEqual = c('autoregX', 'autoregY') ) # Request a simulated post-hoc power analysis with 500 replications # to detect crossed effects of X (X1 -> Y2 and X2 -> Y3) of >= .2 # with a power of 95% on alpha = 5% in a RI-CLPM with 3 waves, # where there are only observed variables and # there is no synchronous correlation between X and Y (rXY = NULL), # and no correlation between the random intercept factors of X and Y (rBXBY = NULL), # the autoregressive effects of X are .8 (equal across waves), # the autoregressive effects of Y are .7 (equal across waves), and # the crossed effects of Y (Y1 -> X2 and Y2 -> X3) are .1 (equal across waves). set.seed(300121) powerRICLPM <- semPower.powerRICLPM(type = 'post-hoc', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = NULL, nullEffect = 'crossedX = 0', Lambda = diag(6), alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
## Not run: # Determine required N in a 3-wave RI-CLPM # to detect crossed effects of X (X1 -> Y2 and X2 -> Y3) of >= .2 # with a power of 95% on alpha = 5%, where # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .4 each, and # there is no synchronous correlation between X and Y (rXY = NULL), # the correlation between the random intercept factors of X and Y (rBXBY) is .1, # the autoregressive effects of X are .8 (equal across waves), # the autoregressive effects of Y are .7 (equal across waves), and # the crossed effects of Y (Y1 -> X2 and Y2 -> X3) are .1 (equal across waves). powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # show summary summary(powerRICLPM) # optionally use lavaan to verify the model was set-up as intended lavaan::sem(powerRICLPM$modelH1, sample.cov = powerRICLPM$Sigma, sample.nobs = powerRICLPM$requiredN, sample.cov.rescale = FALSE) lavaan::sem(powerRICLPM$modelH0, sample.cov = powerRICLPM$Sigma, sample.nobs = powerRICLPM$requiredN, sample.cov.rescale = FALSE) # same as above, but determine power with N = 500 on alpha = .05 powerRICLPM <- semPower.powerRICLPM(type = 'post-hoc', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, N = 500) # same as above, but determine the critical chi-square with N = 500 so that alpha = beta powerRICLPM <- semPower.powerRICLPM(type = 'compromise', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), abratio = 1, N = 500) # same as above, but compare to the saturated model # (rather than to the less restricted model) powerRICLPM <- semPower.powerRICLPM(type = 'compromise', comparison = 'saturated', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), abratio = 1, N = 500) # same as above, but assume only observed variables powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', Lambda = diag(6), alpha = .05, beta = .05) # same as above, but provide reduced loadings matrix to define that # X1, X2, and X3 are measured by 5 indicators each loading by .5, .4, .5, .4, .3 # Y1, Y2, and Y3 are measured by 3 indicators each loading by .4, .3, .2 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', loadings = list( c(.5, .4, .5, .4, .3), # X1 c(.4, .3, .2), # Y1 c(.5, .4, .5, .4, .3), # X2 c(.4, .3, .2), # Y2 c(.5, .4, .5, .4, .3), # X3 c(.4, .3, .2) # Y3 ), alpha = .05, beta = .05) # same as above, but do not assume metric invariance across waves powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), metricInvariance = FALSE, alpha = .05, beta = .05) # same as above, but determine N to detect that the crossed effect of Y # (Y1 -> X2 and Y2 -> X3) is >= .1. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedY = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that the autoregressive effect # of X (X1 -> X2 and X2 -> X3) is >= .8. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'autoregX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that the autoregressive effect # of Y (Y1 -> Y2) is >= .7. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'autoregY = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed effect of X (X1 -> Y2) of .2 differs from # the crossed effect of Y (Y1 -> X2) of .1 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'crossedX = crossedY', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the autoregressive effect of X (X1 -> X2) of .8 differs from # the autoregressive effect of Y (Y1 -> Y2) of .7 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'autoregX = autoregY', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that the correlation between the # random intercept factors is >= .1 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = .1, nullEffect = 'corBXBY = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but assume that the synchronous (residual-)correlations between # X and Y are equal across waves, # namely a synchronous correlation of .05 at the first wave and residual correlations # of .05 at the second and third wave, # and determine N to detect a crossed effect of X (X1 -> Y2 and X2 -> Y3) of >= .2 powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY', 'corXY'), rXY = c(.05, .05, .05), rBXBY = .1, nullEffect = 'crossedX = 0', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but assume that the synchronous correlation between X and Y # is .3 at the first wave, and the respective residual correlations are .2 at # the second wave and .3 at the third wave, # and determine N to detect that the synchronous residual correlation at wave 2 is => .2. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = c(.3, .2, .3), rBXBY = .1, nullEffect = 'corXY = 0', nullWhich = 2, nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # Determine required N in a 3-wave RI-CLPM to detect that # the crossed effect of X at wave 1 (X1 -> Y2) of .20 is equal to the # the crossed effect of X at wave 2 (X2 -> Y3) of .05 # with a power of 95% on alpha = 5%, where # the autoregressive effects of X and Y are equal over waves, # X1, X2, and X3 are measured by 5 indicators loading by .5 each, and # Y1, Y2, and Y3 are measured by 3 indicators loading by .4 each, and # the synchronous correlation between X and Y are .2, .3, and .4 at the first, # second, and third wave, # the correlation between the random intercept factors of X and Y is .1, and # the autoregressive effect of X is .8 across all three waves, # the autoregressive effect of Y is .7 across all three waves, and # the crossed effects of Y (Y1 -> X2, and Y2 -> Y3) are both .1 # (but freely estimated for each wave). powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( # X Y c(.20, .10), # wave 1 -> wave 2 c(.05, .10)), # wave 2 -> wave 3 waveEqual = c('autoregX', 'autoregY'), rXY = c(.2, .3, .4), rBXBY = .1, nullEffect = 'crossedX', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the crossed effect of X at wave 2 is >= .05. powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( # X Y c(.20, .10), # wave 1 -> wave 2 c(.05, .10)), # wave 2 -> wave 3 waveEqual = c('autoregX', 'autoregY'), rXY = c(.2, .3, .4), rBXBY = .1, nullEffect = 'crossedX = 0', nullWhich = 2, nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # same as above, but determine N to detect that # the residual correlation between X and Y at wave 2 (of .3) differs from # the residual correlation between X and Y at wave 3 (of .4). powerRICLPM <- semPower.powerRICLPM(type = 'a-priori', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = list( # X Y c(.20, .10), # wave 1 -> wave 2 c(.05, .10)), # wave 2 -> wave 3 waveEqual = c('autoregX', 'autoregY'), rXY = c(.2, .3, .4), rBXBY = .1, nullEffect = 'corXY', nIndicator = c(5, 3, 5, 3, 5, 3), loadM = c(.5, .4, .5, .4, .5, .4), alpha = .05, beta = .05) # multigroup example # Determine the achieved power N in a 3-wave RI-CLPM to detect that # the crossed effect of X at wave 1 (X1 -> Y2) in group 1 of .25 differs # from the crossed effect of X at wave 1 (X1 -> Y2) in group 2 of .15, # where both groups comprise 500 observations and alpha = 5%, and # the measurement model is equal for both groups, and # the crossed effects of X (X1 -> Y2, and X2 -> Y3) are .25 and .10 in the first group, # the crossed effects of X (X1 -> Y2, and X2 -> Y3) are .15 and .05 in the second group, # the crossed effects of Y (Y1 -> X2, and Y2 -> X3) are .05 and .15 in the first group, # the crossed effects of Y (Y1 -> X2, and Y2 -> X3) are .01 and .10 in the second group, and # the autoregressive effects of X (of .5) and Y (of .4) are equal over waves and over groups # (but freely estimated in each group). powerRICLPM <- semPower.powerRICLPM(type = 'post-hoc', alpha = .05, N = list(500, 500), nWaves = 3, autoregEffects = c(.5, .4), # group and wave constant crossedEffects = list( # group 1 list( c(.25, .10), # X c(.05, .15) # Y ), # group 2 list( c(.15, .05), # X c(.01, .10) # Y ) ), rXY = NULL, # identity rBXBY = NULL, # identity nullEffect = 'crossedXA = crossedXB', nullWhich = 1, nIndicator = rep(3, 6), loadM = c(.5, .6, .5, .6, .5, .6), metricInvariance = TRUE, waveEqual = c('autoregX', 'autoregY') ) # Request a simulated post-hoc power analysis with 500 replications # to detect crossed effects of X (X1 -> Y2 and X2 -> Y3) of >= .2 # with a power of 95% on alpha = 5% in a RI-CLPM with 3 waves, # where there are only observed variables and # there is no synchronous correlation between X and Y (rXY = NULL), # and no correlation between the random intercept factors of X and Y (rBXBY = NULL), # the autoregressive effects of X are .8 (equal across waves), # the autoregressive effects of Y are .7 (equal across waves), and # the crossed effects of Y (Y1 -> X2 and Y2 -> X3) are .1 (equal across waves). set.seed(300121) powerRICLPM <- semPower.powerRICLPM(type = 'post-hoc', nWaves = 3, autoregEffects = c(.8, .7), crossedEffects = c(.2, .1), waveEqual = c('autoregX', 'autoregY', 'crossedX', 'crossedY'), rXY = NULL, rBXBY = NULL, nullEffect = 'crossedX = 0', Lambda = diag(6), alpha = .05, N = 500, simulatedPower = TRUE, simOptions = list(nReplications = 500)) ## End(Not run)
Shows a plot showing central and non-central chi-square distribution.
semPower.showPlot(chiCrit, ncp, df, linewidth = 1, showLabels = TRUE)
semPower.showPlot(chiCrit, ncp, df, linewidth = 1, showLabels = TRUE)
chiCrit |
critical chi-square, e. g. |
ncp |
non-centrality parameter under H1 |
df |
degrees of freedom |
linewidth |
linewidth |
showLabels |
whether to add labels |
Estimates empirical power using a simulation approach.
simulate( modelH0 = NULL, modelH1 = NULL, Sigma = NULL, mu = NULL, N = NULL, alpha = NULL, simOptions = list(nReplications = 500, minConvergenceRate = 0.75, type = "normal", missingVars = NULL, missingVarProp = 0, missingProp = 0, missingMechanism = "MCAR", nCores = 1), lavOptions = NULL, lavOptionsH1 = lavOptions, returnFmin = TRUE )
simulate( modelH0 = NULL, modelH1 = NULL, Sigma = NULL, mu = NULL, N = NULL, alpha = NULL, simOptions = list(nReplications = 500, minConvergenceRate = 0.75, type = "normal", missingVars = NULL, missingVarProp = 0, missingProp = 0, missingMechanism = "MCAR", nCores = 1), lavOptions = NULL, lavOptionsH1 = lavOptions, returnFmin = TRUE )
modelH0 |
|
modelH1 |
|
Sigma |
population covariance matrix. |
mu |
population means. |
N |
sample size |
alpha |
alpha error probability |
simOptions |
a list of additional options specifying simulation details, see details. |
lavOptions |
a list of additional options passed to |
lavOptionsH1 |
lavoptions when fitting |
returnFmin |
whether to return the mean unbiased Fmin over replications (i. e., |
The details of the simulation are specified in simOptions
, which is a list that may have the following components:
nReplications
: The targeted number of valid simulation runs, defaults to 500.
minConvergenceRate
: The minimum convergence rate required, defaults to .75. The maximum actual simulation runs are increased by a factor of 1/minConvergenceRate.
type
: specifies whether the data should be generated from a population assuming multivariate normality ('normal'
; the default), or based on an approach generating non-normal data ('IG'
, 'mnonr'
, 'RK'
, or 'VM'
).
The approaches generating non-normal data require additional arguments detailed below.
missingVars
: vector specifying the variables containing missing data (defaults to NULL
).
missingVarProp
: can be used instead of missingVars
: The proportion of variables containing missing data (defaults to zero).
missingProp
: The proportion of missingness for variables containing missing data (defaults to zero), either a single value or a vector giving the probabilities for each variable.
missingMechanism
: The missing data mechanism, one of 'MCAR'
(the default), 'MAR'
, or 'NMAR'
.
nCores
: The number of cores to use for parallel processing. Defaults to 1 (= no parallel processing). This requires the doFuture
package.
type = 'IG'
implements the independent generator approach (IG, Foldnes & Olsson, 2016) approach
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors. This requires the covsim
package.
type = 'mnonr'
implements the approach suggested by Qu, Liu, & Zhang (2020) and requires provision of Mardia's multivariate skewness (skewness
) and kurtosis (kurtosis
), where
skewness must be non-negative and kurtosis must be at least 1.641 skewness + p (p + 0.774), where p is the number of variables. This requires the mnonr
package.
type = 'RK'
implements the approach suggested by Ruscio & Kaczetow (2008) and requires provision of the population distributions
of each variable (distributions
). distributions
must be a list (if all variables shall be based on the same population distribution) or a list of lists.
Each component must specify the population distribution (e.g. rchisq
) and additional arguments (list(df = 2)
).
type = 'VM'
implements the third-order polynomial method (Vale & Maurelli, 1983)
specifying third and fourth moments of the marginals, and thus requires that skewness (skewness
) and excess kurtosis (kurtosis
) for each variable are provided as vectors.
Foldnes, N. & Olsson, U. H. (2016) A Simple Simulation Technique for Nonnormal Data with Prespecified Skewness, Kurtosis, and Covariance Matrix. Multivariate Behavioral Research, 51, 207-219. doi: 10.1080/00273171.2015.1133274
Qu, W., Liu, H., & Zhang, Z. (2020). A method of generating multivariate non-normal random numbers with desired multivariate skewness and kurtosis. Behavior Research Methods, 52, 939-946. doi: 10.3758/s13428-019-01291-5
Ruscio, J., & Kaczetow, W. (2008). Simulating multivariate nonnormal data using an iterative algorithm. Multivariate Behavioral Research, 43, 355-381. doi: 10.1080/00273170802285693
Vale, C. & Maurelli, V. (1983). Simulating multivariate nonnormal distributions. Psychometrika, 48, 465-471.
Returns empirical power: sum(p < alpha) / nReplications
or a list (if returnFmin = TRUE
) with the following components:
ePower |
the empirical power. |
meanFmin |
the estimated mean unbiased Fmin over replications (i. e., |
meanFminGroups |
the estimated mean unbiased Fmin by groups given as a vector, assuming the df spread equally over groups. Therefore, |
df |
the model df. |
nrep |
the number of successful replications. |
convergenceRate |
the convergence rate of the H0 model. |
bChiSq |
median chi-square bias of the H1 model |
bLambda |
average median bias in lambda in the H1 model |
bPhi |
average median bias in phi in the H1 model |
bPsi |
average median bias in psi in the H1 model |
bBeta |
average median bias in beta in the H1 model |
## Not run: # create Sigma and modelH0 using powerCFA powerCFA <- semPower.powerCFA(type = 'a-priori', alpha = .05, beta = .05, comparison = 'saturated', Phi = .2, loadings = list(rep(.5, 3), rep(.7, 3))) # perform simulated power analysis using defaults simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE) # same with additional options simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(nReplications = 500, minConvergenceRate = .80, nCores = 8)) # same with IG as data generation routine simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(type = 'IG', skewness = c(0, 1, -2, 6, 5, 4), kurtosis = c(-3, 6, 9, 0, 2, -2))) # same with mnonr as data generation routine simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(type = 'mnonr', skewness = 1, kurtosis = 50)) # same with RK as data generation routine distributions <- list( list('rnorm', list(mean = 0, sd = 10)), list('runif', list(min = 0, max = 1)), list('rbeta', list(shape1 = 1, shape2 = 2)), list('rexp', list(rate = 1)), list('rpois', list(lambda = 4)), list('rbinom', list(size = 1, prob = .5)) ) simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(type = 'RK', distributions = distributions)) ## End(Not run)
## Not run: # create Sigma and modelH0 using powerCFA powerCFA <- semPower.powerCFA(type = 'a-priori', alpha = .05, beta = .05, comparison = 'saturated', Phi = .2, loadings = list(rep(.5, 3), rep(.7, 3))) # perform simulated power analysis using defaults simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE) # same with additional options simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(nReplications = 500, minConvergenceRate = .80, nCores = 8)) # same with IG as data generation routine simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(type = 'IG', skewness = c(0, 1, -2, 6, 5, 4), kurtosis = c(-3, 6, 9, 0, 2, -2))) # same with mnonr as data generation routine simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(type = 'mnonr', skewness = 1, kurtosis = 50)) # same with RK as data generation routine distributions <- list( list('rnorm', list(mean = 0, sd = 10)), list('runif', list(min = 0, max = 1)), list('rbeta', list(shape1 = 1, shape2 = 2)), list('rexp', list(rate = 1)), list('rpois', list(lambda = 4)), list('rbinom', list(size = 1, prob = .5)) ) simulate(modelH0 = powerCFA$modelH0, Sigma = powerCFA$Sigma, N = powerCFA$requiredN, alpha = .05, simulatedPower = TRUE, simOptions = list(type = 'RK', distributions = distributions)) ## End(Not run)
provide summary of a-priori power analyses
## S3 method for class 'semPower.aPriori' summary(object, ...)
## S3 method for class 'semPower.aPriori' summary(object, ...)
object |
result object from semPower.aPriori |
... |
other |
provide summary of compromise post-hoc power analyses
## S3 method for class 'semPower.compromise' summary(object, ...)
## S3 method for class 'semPower.compromise' summary(object, ...)
object |
result object from semPower.compromise |
... |
other |
provide summary of post-hoc power analyses
## S3 method for class 'semPower.postHoc' summary(object, ...)
## S3 method for class 'semPower.postHoc' summary(object, ...)
object |
result object from semPower.posthoc |
... |
other |
Validates input for power functions.
validateInput( power.type = NULL, effect = NULL, effect.measure = NULL, alpha = NULL, beta = NULL, power = NULL, abratio = NULL, N = NULL, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, power.min = alpha, power.max = 0.999, effect.min = NULL, effect.max = NULL, steps = 50, linewidth = 1 )
validateInput( power.type = NULL, effect = NULL, effect.measure = NULL, alpha = NULL, beta = NULL, power = NULL, abratio = NULL, N = NULL, df = NULL, p = NULL, SigmaHat = NULL, Sigma = NULL, muHat = NULL, mu = NULL, fittingFunction = "ML", simulatedPower = FALSE, modelH0 = NULL, power.min = alpha, power.max = 0.999, effect.min = NULL, effect.max = NULL, steps = 50, linewidth = 1 )
power.type |
type of power analyses, one of |
effect |
effect size specifying the discrepancy between H0 and H1 |
effect.measure |
type of effect, one of |
alpha |
alpha error |
beta |
beta error |
power |
power (= 1 - beta) |
abratio |
ratio alpha/beta |
N |
the number of observations |
df |
the model degrees of freedom |
p |
the number of observed variables, required for |
SigmaHat |
model implied covariance matrix |
Sigma |
observed (or population) covariance matrix |
muHat |
model implied mean vector |
mu |
observed (or population) mean vector |
fittingFunction |
whether to use |
simulatedPower |
whether to perform a simulated ( |
modelH0 |
for simulated power: |
power.min |
for plotting: minimum power |
power.max |
for plotting: maximum power |
effect.min |
for plotting: minimum effect |
effect.max |
for plotting: maximum effect |
steps |
for plotting: number of sampled points |
linewidth |
for plotting: linewidth |