Alignment Procedure for Linking under Approximate Invariance
invariance.alignment.RdThe function invariance.alignment performs alignment under approximate
invariance for \(G\) groups and \(I\) items
(Asparouhov & Muthen, 2014; Byrne & van de Vijver, 2017; DeMars, 2020; Finch, 2016;
Fischer & Karl, 2019; Flake & McCoach, 2018; Kim et al., 2017; Marsh et al., 2018;
Muthen & Asparouhov, 2014, 2018; Pokropek, Davidov & Schmidt, 2019).
It is assumed that item loadings and intercepts are
previously estimated as a unidimensional factor model under the assumption of a factor
with zero mean and a variance of one.
The function invariance_alignment_constraints postprocesses the output of the
invariance.alignment function and estimates item parameters under equality
constraints for prespecified absolute values of parameter tolerance.
The function invariance_alignment_simulate simulates a one-factor model
for multiple groups for given matrices of \(\nu\) and \(\lambda\) parameters of
item intercepts and item slopes (see Example 6).
The function invariance_alignment_cfa_config estimates one-factor
models separately for each group as a preliminary step for invariance
alignment (see Example 6). Sampling weights are accommodated by the
argument weights. The computed variance matrix vcov by this function
can be used to obtain standard errors in the invariance.alignment function
if it is supplied as the argument vcov.
Usage
invariance.alignment(lambda, nu, wgt=NULL, align.scale=c(1, 1),
align.pow=c(.5, .5), eps=1e-3, psi0.init=NULL, alpha0.init=NULL, center=FALSE,
optimizer="optim", fixed=NULL, meth=1, vcov=NULL, eps_grid=seq(0,-10, by=-.5),
num_deriv=FALSE, ...)
# S3 method for invariance.alignment
summary(object, digits=3, file=NULL, ...)
invariance_alignment_constraints(model, lambda_parm_tol, nu_parm_tol )
# S3 method for invariance_alignment_constraints
summary(object, digits=3, file=NULL, ...)
invariance_alignment_simulate(nu, lambda, err_var, mu, sigma, N, output="data",
groupwise=FALSE, exact=FALSE)
invariance_alignment_cfa_config(dat, group, weights=NULL, model="2PM", verbose=FALSE, ...)Arguments
- lambda
A \(G \times I\) matrix with item loadings
- nu
A \(G \times I\) matrix with item intercepts
- wgt
A \(G \times I\) matrix for weighing groups for each item
- align.scale
A vector of length two containing scale parameter \(a_\lambda\) and \(a_\nu\) (see Details)
- align.pow
A vector of length two containing power \(p_\lambda\) and \(p_\nu\) (see Details)
- eps
A parameter in the optimization function
- psi0.init
An optional vector of initial \(\psi_0\) parameters
- alpha0.init
An optional vector of initial \(\alpha_0\) parameters
- center
Logical indicating whether estimated means and standard deviations should be centered.
- optimizer
Name of the optimizer chosen for alignment. Options are
"optim"(usingstats::optim) or"nlminb"(usingstats::nlminb).- fixed
Logical indicating whether SD of first group should be fixed to one. If
fixed=FALSE, the product of all SDs is set to one. IfNULL, thenfixedis automatically chosen by default. For many groups,fixed=FALSEis chosen.- meth
Type of method used for optimization function.
meth=1is the default and the optimization function used in Mplus.meth=2uses logarithmized item loadings in alignment. The choicemeth=4uses the constraint \(\prod_g \psi_g=1\) and adds the penalty \(\lambda \sum_g \alpha_g^2\) for a fixed value \(\lambda\) that depends on the weightswgt(similar to Mplus' free method). The choicemeth=3only uses the constraint \(\prod_g \psi_g=1\) (similar to Mplus' FIXED method).- vcov
Variance matrix produced by
invariance_alignment_cfa_configfor standard error computation. If a matrix is provided, standard errors are computed.- eps_grid
Grid of logarithmized epsilon values in optimization
- num_deriv
Logical indicating whether numerical derivatives should be used
- object
Object of class
invariance.alignment- digits
Number of digits used for rounding
- file
Optional file name in which summary should be sunk
- ...
Further optional arguments to be passed
- model
Model of class
invariance.alignment. Forinvariance_alignment_cfa_config: Model type:"2PM"for two-parameter model with unequal loadings and"1PM"with equal loadings and equal residual variances- lambda_parm_tol
Parameter tolerance for \(\lambda\) parameters
- nu_parm_tol
Parameter tolerance for \(\nu\) parameters
- err_var
Error variance
- mu
Vector of means
- sigma
Vector of standard deviations
- N
Vector of sample sizes per group
- output
Specifies output type:
"data"for dataset and"suffstat"for sufficient statistics (i.e., means and covariance matrices)- groupwise
Logical indicating whether group-wise output is requested
- exact
Logical indicating whether distributions should be exactly preserved in simulated data
- dat
Dataset with items or a list containing sufficient statistics
- group
Vector containing group indicators
- weights
Optional vector of sampling weights
- verbose
Logical indicating whether progress should be printed
Details
For \(G\) groups and \(I\) items, item loadings \(\lambda_{ig0}\) and intercepts \(\nu_{ig0}\) are available and have been estimated in a 1-dimensional factor analysis assuming a standardized factor.
The alignment procedure searches means \(\alpha_{g0}\) and standard deviations \(\psi_{g0}\) using an alignment optimization function \(F\). This function is defined as $$F=\sum_i \sum_{ g_1 < g_2} w_{i,g1} w_{i,g2} f_\lambda( \lambda_{i g_1,1} - \lambda_{i g_2,1} ) + \sum_i \sum_{ g_1 < g_2} w_{i,g1} w_{i,g2} f_\nu( \nu_{i g_1,1} - \nu_{i g_2,1} ) $$ where the aligned item parameters \(\lambda_{i g,1}\) and \(\nu_{i g,1}\) are defined such that
$$ \lambda_{i g,1}=\lambda_{i g 0} / \psi_{g0} \qquad \mbox{and} \qquad \nu_{i g,1}=\nu_{i g 0} - \alpha_{g0} \lambda_{ig0} / \psi_{g0} $$ and the optimization functions are defined as $$ f_\lambda (x)=| x/ a_\lambda | ^{p_\lambda} \approx [ ( x/ a_\lambda )^2 + \varepsilon ]^{p_\lambda / 2} \qquad \mbox{and} \qquad f_\nu (x)=| x/ a_\nu ]^{p_\nu} \approx [ ( x/ a_\nu )^2 + \varepsilon ]^{p_\nu / 2} $$ using a small \( \varepsilon > 0\) (e.g. .001) to obtain a differentiable optimization function. For \(p_\nu=0\) or \(p_\lambda=0\), the optimization function essentially counts the number of different parameter and mimicks a \(L_0\) penalty which is zero iff the argument is zero and one otherwise. It is approximated by $$f(x)=x^2 (x^2 + \varepsilon )^{-1} $$ (O'Neill & Burke, 2023).
For identification reasons, the product \(\Pi_g \psi_{g0}\) (meth=0,0.5)
of all group standard deviations or \(\psi_1\) (meth=1,2)
is set to one. The mean
\(\alpha_{g0}\) of the first group is set to zero (meth=0.5,1,2) or
a penalty function is added to the linking function (meth=0).
Note that Asparouhov and Muthen (2014) use \(a_\lambda=a_\nu=1\)
(which can be modified in align.scale)
and \(p_\lambda=p_\nu=0.5\) (which can be modified in align.pow).
In case of \(p_\lambda=2\), the penalty is approximately
\(f_\lambda(x)=x^2 \), in case of \(p_\lambda=0.5\)
it is approximately \(f_\lambda(x)=\sqrt{|x|} \). Note that sirt used a
different parametrization in versions up to 3.5. The \(p\) parameters have to be halved
for consistency with previous versions (e.g., the Asparouhov & Muthen parametrization
corresponds to \(p=.25\); see also Fischer & Karl, 2019, for an application of
the previous parametrization).
Effect sizes of approximate invariance based on \(R^2\) have
been proposed by Asparouhov and Muthen (2014). These are
calculated separately for item loading and intercepts, resulting
in \(R^2_\lambda\) and \(R^2_\nu\) measures which are
included in the output es.invariance. In addition,
the average correlation of aligned item parameters among groups (rbar)
is reported.
Metric invariance means that all aligned item loadings \(\lambda_{ig,1}\) are equal across groups and therefore \(R^2_\lambda=1\). Scalar invariance means that all aligned item loadings \(\lambda_{ig,1}\) and aligned item intercepts \(\nu_{ig,1}\) are equal across groups and therefore \(R^2_\lambda=1\) and \(R^2_\nu=1\) (see Vandenberg & Lance, 2000).
Value
A list with following entries
- pars
Aligned distribution parameters
- itempars.aligned
Aligned item parameters for all groups
- es.invariance
Effect sizes of approximate invariance
- lambda.aligned
Aligned \( \lambda_{i g,1}\) parameters
- lambda.resid
Residuals of \( \lambda_{i g,1}\) parameters
- nu.aligned
Aligned \( \nu_{i g,1}\) parameters
- nu.resid
Residuals of \( \nu_{i g,1}\) parameters
- Niter
Number of iterations for \(f_\lambda\) and \(f_\nu\) optimization functions
- fopt
Minimum optimization value
- align.scale
Used alignment scale parameters
- align.pow
Used alignment power parameters
- vcov
Estimated variance matrix of aligned means and standard deviations
- ...
More values
References
Asparouhov, T., & Muthen, B. (2014). Multiple-group factor analysis alignment. Structural Equation Modeling, 21(4), 1-14. doi:10.1080/10705511.2014.919210
Byrne, B. M., & van de Vijver, F. J. R. (2017). The maximum likelihood alignment approach to testing for approximate measurement invariance: A paradigmatic cross-cultural application. Psicothema, 29(4), 539-551. doi:10.7334/psicothema2017.178
DeMars, C. E. (2020). Alignment as an alternative to anchor purification in DIF analyses. Structural Equation Modeling, 27(1), 56-72. doi:10.1080/10705511.2019.1617151
Finch, W. H. (2016). Detection of differential item functioning for more than two groups: A Monte Carlo comparison of methods. Applied Measurement in Education, 29,(1), 30-45, doi:10.1080/08957347.2015.1102916
Fischer, R., & Karl, J. A. (2019). A primer to (cross-cultural) multi-group invariance testing possibilities in R. Frontiers in Psychology | Cultural Psychology, 10:1507. doi:10.3389/fpsyg.2019.01507
Flake, J. K., & McCoach, D. B. (2018). An investigation of the alignment method with polytomous indicators under conditions of partial measurement invariance. Structural Equation Modeling, 25(1), 56-70. doi:10.1080/10705511.2017.1374187
Kim, E. S., Cao, C., Wang, Y., & Nguyen, D. T. (2017). Measurement invariance testing with many groups: A comparison of five approaches. Structural Equation Modeling, 24(4), 524-544. doi:10.1080/10705511.2017.1304822
Marsh, H. W., Guo, J., Parker, P. D., Nagengast, B., Asparouhov, T., Muthen, B., & Dicke, T. (2018). What to do when scalar invariance fails: The extended alignment method for multi-group factor analysis comparison of latent means across many groups. Psychological Methods, 23(3), 524-545. doi: 10.1037/met0000113
Muthen, B., & Asparouhov, T. (2014). IRT studies of many groups: The alignment method. Frontiers in Psychology | Quantitative Psychology and Measurement, 5:978. doi:10.3389/fpsyg.2014.00978
Muthen, B., & Asparouhov, T. (2018). Recent methods for the study of measurement invariance with many groups: Alignment and random effects. Sociological Methods & Research, 47(4), 637-664. doi:10.1177/0049124117701488
O'Neill, M., & Burke, K. (2023). Variable selection using a smooth information criterion for distributional regression models. Statistics and Computing, 33(3), 71. doi:10.1007/s11222-023-10204-8
Pokropek, A., Davidov, E., & Schmidt, P. (2019). A Monte Carlo simulation study to assess the appropriateness of traditional and newer approaches to test for measurement invariance. Structural Equation Modeling, 26(5), 724-744. doi:10.1080/10705511.2018.1561293
Vandenberg, R. J., & Lance, C. E. (2000). A review and synthesis of the measurement invariance literature: Suggestions, practices, and recommendations for organizational research. Organizational Research Methods, 3, 4-70. doi:10.1177/109442810031002 s
See also
For IRT linking see also linking.haberman or
TAM::tam.linking.
For modeling random item effects for loadings and intercepts
see mcmc.2pno.ml.
Examples
#############################################################################
# EXAMPLE 1: Item parameters cultural activities
#############################################################################
data(data.activity.itempars, package="sirt")
lambda <- data.activity.itempars$lambda
nu <- data.activity.itempars$nu
Ng <- data.activity.itempars$N
wgt <- matrix( sqrt(Ng), length(Ng), ncol(nu) )
#***
# Model 1: Alignment using a quadratic loss function
mod1 <- sirt::invariance.alignment( lambda, nu, wgt, align.pow=c(2,2) )
summary(mod1)
#****
# Model 2: Different powers for alignment
mod2 <- sirt::invariance.alignment( lambda, nu, wgt, align.pow=c(.5,1),
align.scale=c(.95,.95))
summary(mod2)
# compare means from Models 1 and 2
plot( mod1$pars$alpha0, mod2$pars$alpha0, pch=16,
xlab="M (Model 1)", ylab="M (Model 2)", xlim=c(-.3,.3), ylim=c(-.3,.3) )
lines( c(-1,1), c(-1,1), col="gray")
round( cbind( mod1$pars$alpha0, mod2$pars$alpha0 ), 3 )
round( mod1$nu.resid, 3)
round( mod2$nu.resid,3 )
# L0 penalty
mod2b <- sirt::invariance.alignment( lambda, nu, wgt, align.pow=c(0,0),
align.scale=c(.3,.3))
summary(mod2b)
#****
# Model 3: Low powers for alignment of scale and power
# Note that setting increment.factor larger than 1 seems necessary
mod3 <- sirt::invariance.alignment( lambda, nu, wgt, align.pow=c(.5,.75),
align.scale=c(.55,.55), psi0.init=mod1$psi0, alpha0.init=mod1$alpha0 )
summary(mod3)
# compare mean and SD estimates of Models 1 and 3
plot( mod1$pars$alpha0, mod3$pars$alpha0, pch=16)
plot( mod1$pars$psi0, mod3$pars$psi0, pch=16)
# compare residuals for Models 1 and 3
# plot lambda
plot( abs(as.vector(mod1$lambda.resid)), abs(as.vector(mod3$lambda.resid)),
pch=16, xlab="Residuals lambda (Model 1)",
ylab="Residuals lambda (Model 3)", xlim=c(0,.1), ylim=c(0,.1))
lines( c(-3,3),c(-3,3), col="gray")
# plot nu
plot( abs(as.vector(mod1$nu.resid)), abs(as.vector(mod3$nu.resid)),
pch=16, xlab="Residuals nu (Model 1)", ylab="Residuals nu (Model 3)",
xlim=c(0,.4),ylim=c(0,.4))
lines( c(-3,3),c(-3,3), col="gray")
if (FALSE) {
#############################################################################
# EXAMPLE 2: Comparison 4 groups | data.inv4gr
#############################################################################
data(data.inv4gr)
dat <- data.inv4gr
miceadds::library_install("semTools")
model1 <- "
F=~ I01 + I02 + I03 + I04 + I05 + I06 + I07 + I08 + I09 + I10 + I11
F ~~ 1*F
"
res <- semTools::measurementInvariance(model1, std.lv=TRUE, data=dat, group="group")
## Measurement invariance tests:
##
## Model 1: configural invariance:
## chisq df pvalue cfi rmsea bic
## 162.084 176.000 0.766 1.000 0.000 95428.025
##
## Model 2: weak invariance (equal loadings):
## chisq df pvalue cfi rmsea bic
## 519.598 209.000 0.000 0.973 0.039 95511.835
##
## [Model 1 versus model 2]
## delta.chisq delta.df delta.p.value delta.cfi
## 357.514 33.000 0.000 0.027
##
## Model 3: strong invariance (equal loadings + intercepts):
## chisq df pvalue cfi rmsea bic
## 2197.260 239.000 0.000 0.828 0.091 96940.676
##
## [Model 1 versus model 3]
## delta.chisq delta.df delta.p.value delta.cfi
## 2035.176 63.000 0.000 0.172
##
## [Model 2 versus model 3]
## delta.chisq delta.df delta.p.value delta.cfi
## 1677.662 30.000 0.000 0.144
##
# extract item parameters separate group analyses
ipars <- lavaan::parameterEstimates(res$fit.configural)
# extract lambda's: groups are in rows, items in columns
lambda <- matrix( ipars[ ipars$op=="=~", "est"], nrow=4, byrow=TRUE)
colnames(lambda) <- colnames(dat)[-1]
# extract nu's
nu <- matrix( ipars[ ipars$op=="~1" & ipars$se !=0, "est" ], nrow=4, byrow=TRUE)
colnames(nu) <- colnames(dat)[-1]
# Model 1: least squares optimization
mod1 <- sirt::invariance.alignment( lambda=lambda, nu=nu )
summary(mod1)
## Effect Sizes of Approximate Invariance
## loadings intercepts
## R2 0.9826 0.9972
## sqrtU2 0.1319 0.0526
## rbar 0.6237 0.7821
## -----------------------------------------------------------------
## Group Means and Standard Deviations
## alpha0 psi0
## 1 0.000 0.965
## 2 -0.105 1.098
## 3 -0.081 1.011
## 4 0.171 0.935
# Model 2: sparse target function
mod2 <- sirt::invariance.alignment( lambda=lambda, nu=nu, align.pow=c(.5,.5) )
summary(mod2)
## Effect Sizes of Approximate Invariance
## loadings intercepts
## R2 0.9824 0.9972
## sqrtU2 0.1327 0.0529
## rbar 0.6237 0.7856
## -----------------------------------------------------------------
## Group Means and Standard Deviations
## alpha0 psi0
## 1 -0.002 0.965
## 2 -0.107 1.098
## 3 -0.083 1.011
## 4 0.170 0.935
#############################################################################
# EXAMPLE 3: European Social Survey data.ess2005
#############################################################################
data(data.ess2005)
lambda <- data.ess2005$lambda
nu <- data.ess2005$nu
# Model 1: least squares optimization
mod1 <- sirt::invariance.alignment( lambda=lambda, nu=nu, align.pow=c(2,2) )
summary(mod1)
# Model 2: sparse target function and definition of scales
mod2 <- sirt::invariance.alignment( lambda=lambda, nu=nu, control=list(trace=2) )
summary(mod2)
#############################################################################
# EXAMPLE 4: Linking with item parameters containing outliers
#############################################################################
# see Help file in linking.robust
# simulate some item difficulties in the Rasch model
I <- 38
set.seed(18785)
itempars <- data.frame("item"=paste0("I",1:I) )
itempars$study1 <- stats::rnorm( I, mean=.3, sd=1.4 )
# simulate DIF effects plus some outliers
bdif <- stats::rnorm(I, mean=.4, sd=.09) +
(stats::runif(I)>.9 )*rep( 1*c(-1,1)+.4, each=I/2 )
itempars$study2 <- itempars$study1 + bdif
# create input for function invariance.alignment
nu <- t( itempars[,2:3] )
colnames(nu) <- itempars$item
lambda <- 1+0*nu
# linking using least squares optimization
mod1 <- sirt::invariance.alignment( lambda=lambda, nu=nu )
summary(mod1)
## Group Means and Standard Deviations
## alpha0 psi0
## study1 -0.286 1
## study2 0.286 1
# linking using powers of .5
mod2 <- sirt::invariance.alignment( lambda=lambda, nu=nu, align.pow=c(1,1) )
summary(mod2)
## Group Means and Standard Deviations
## alpha0 psi0
## study1 -0.213 1
## study2 0.213 1
# linking using powers of .25
mod3 <- sirt::invariance.alignment( lambda=lambda, nu=nu, align.pow=c(.5,.5) )
summary(mod3)
## Group Means and Standard Deviations
## alpha0 psi0
## study1 -0.207 1
## study2 0.207 1
#############################################################################
# EXAMPLE 5: Linking gender groups with data.math
#############################################################################
data(data.math)
dat <- data.math$data
dat.male <- dat[ dat$female==0, substring( colnames(dat),1,1)=="M" ]
dat.female <- dat[ dat$female==1, substring( colnames(dat),1,1)=="M" ]
#*************************
# Model 1: Linking using the Rasch model
mod1m <- sirt::rasch.mml2( dat.male )
mod1f <- sirt::rasch.mml2( dat.female )
# create objects for invariance.alignment
nu <- rbind( mod1m$item$thresh, mod1f$item$thresh )
colnames(nu) <- mod1m$item$item
rownames(nu) <- c("male", "female")
lambda <- 1+0*nu
# mean of item difficulties
round( rowMeans(nu), 3 )
# Linking using least squares optimization
res1a <- sirt::invariance.alignment( lambda, nu, align.scale=c( .3, .5 ) )
summary(res1a)
# Linking using optimization with absolute value function (pow=.5)
res1b <- sirt::invariance.alignment( lambda, nu, align.scale=c( .3, .5 ),
align.pow=c(1,1) )
summary(res1b)
#-- compare results with Haberman linking
I <- ncol(dat.male)
itempartable <- data.frame( "study"=rep( c("male", "female"), each=I ) )
itempartable$item <- c( paste0(mod1m$item$item), paste0(mod1f$item$item) )
itempartable$a <- 1
itempartable$b <- c( mod1m$item$b, mod1f$item$b )
# estimate linking parameters
res1c <- sirt::linking.haberman( itempars=itempartable )
#-- results of sirt::equating.rasch
x <- itempartable[ 1:I, c("item", "b") ]
y <- itempartable[ I + 1:I, c("item", "b") ]
res1d <- sirt::equating.rasch( x, y )
round( res1d$B.est, 3 )
## Mean.Mean Haebara Stocking.Lord
## 1 0.032 0.032 0.029
#*************************
# Model 2: Linking using the 2PL model
I <- ncol(dat.male)
mod2m <- sirt::rasch.mml2( dat.male, est.a=1:I)
mod2f <- sirt::rasch.mml2( dat.female, est.a=1:I)
# create objects for invariance.alignment
nu <- rbind( mod2m$item$thresh, mod2f$item$thresh )
colnames(nu) <- mod2m$item$item
rownames(nu) <- c("male", "female")
lambda <- rbind( mod2m$item$a, mod2f$item$a )
colnames(lambda) <- mod2m$item$item
rownames(lambda) <- c("male", "female")
res2a <- sirt::invariance.alignment( lambda, nu, align.scale=c( .3, .5 ) )
summary(res2a)
res2b <- sirt::invariance.alignment( lambda, nu, align.scale=c( .3, .5 ),
align.pow=c(1,1) )
summary(res2b)
# compare results with Haberman linking
I <- ncol(dat.male)
itempartable <- data.frame( "study"=rep( c("male", "female"), each=I ) )
itempartable$item <- c( paste0(mod2m$item$item), paste0(mod2f$item$item ) )
itempartable$a <- c( mod2m$item$a, mod2f$item$a )
itempartable$b <- c( mod2m$item$b, mod2f$item$b )
# estimate linking parameters
res2c <- sirt::linking.haberman( itempars=itempartable )
#############################################################################
# EXAMPLE 6: Data from Asparouhov & Muthen (2014) simulation study
#############################################################################
G <- 3 # number of groups
I <- 5 # number of items
# define lambda and nu parameters
lambda <- matrix(1, nrow=G, ncol=I)
nu <- matrix(0, nrow=G, ncol=I)
# define size of noninvariance
dif <- 1
#- 1st group: N(0,1)
lambda[1,3] <- 1+dif*.4; nu[1,5] <- dif*.5
#- 2nd group: N(0.3,1.5)
gg <- 2 ; mu <- .3; sigma <- sqrt(1.5)
lambda[gg,5] <- 1-.5*dif; nu[gg,1] <- -.5*dif
nu[gg,] <- nu[gg,] + mu*lambda[gg,]
lambda[gg,] <- lambda[gg,] * sigma
#- 3nd group: N(.8,1.2)
gg <- 3 ; mu <- .8; sigma <- sqrt(1.2)
lambda[gg,4] <- 1-.7*dif; nu[gg,2] <- -.5*dif
nu[gg,] <- nu[gg,] + mu*lambda[gg,]
lambda[gg,] <- lambda[gg,] * sigma
# define alignment scale
align.scale <- c(.2,.4) # Asparouhov and Muthen use c(1,1)
# define alignment powers
align.pow <- c(.5,.5) # as in Asparouhov and Muthen
#*** estimate alignment parameters
mod1 <- sirt::invariance.alignment( lambda, nu, eps=.01, optimizer="optim",
align.scale=align.scale, align.pow=align.pow, center=FALSE )
summary(mod1)
#--- find parameter constraints for prespecified tolerance
cmod1 <- sirt::invariance_alignment_constraints(model=mod1, nu_parm_tol=.4,
lambda_parm_tol=.2 )
summary(cmod1)
#############################################################################
# EXAMPLE 7: Similar to Example 6, but with data simulation and CFA estimation
#############################################################################
#--- data simulation
set.seed(65)
G <- 3 # number of groups
I <- 5 # number of items
# define lambda and nu parameters
lambda <- matrix(1, nrow=G, ncol=I)
nu <- matrix(0, nrow=G, ncol=I)
err_var <- matrix(1, nrow=G, ncol=I)
# define size of noninvariance
dif <- 1
#- 1st group: N(0,1)
lambda[1,3] <- 1+dif*.4; nu[1,5] <- dif*.5
#- 2nd group: N(0.3,1.5)
gg <- 2 ;
lambda[gg,5] <- 1-.5*dif; nu[gg,1] <- -.5*dif
#- 3nd group: N(.8,1.2)
gg <- 3
lambda[gg,4] <- 1-.7*dif; nu[gg,2] <- -.5*dif
#- define distributions of groups
mu <- c(0,.3,.8)
sigma <- sqrt(c(1,1.5,1.2))
N <- rep(1000,3) # sample sizes per group
#* simulate data
dat <- sirt::invariance_alignment_simulate(nu, lambda, err_var, mu, sigma, N)
head(dat)
#--- estimate CFA models
pars <- sirt::invariance_alignment_cfa_config(dat[,-1], group=dat$group)
print(pars)
#--- invariance alignment
# define alignment scale
align.scale <- c(.2,.4)
# define alignment powers
align.pow <- c(.5,.5)
mod1 <- sirt::invariance.alignment( lambda=pars$lambda, nu=pars$nu, eps=.01,
optimizer="optim", align.scale=align.scale, align.pow=align.pow, center=FALSE)
#* find parameter constraints for prespecified tolerance
cmod1 <- sirt::invariance_alignment_constraints(model=mod1, nu_parm_tol=.4,
lambda_parm_tol=.2 )
summary(cmod1)
#--- estimate CFA models with sampling weights
#* simulate weights
weights <- stats::runif(sum(N), 0, 2)
#* estimate models
pars2 <- sirt::invariance_alignment_cfa_config(dat[,-1], group=dat$group, weights=weights)
print(pars2$nu)
print(pars$nu)
#--- estimate one-parameter model
pars <- sirt::invariance_alignment_cfa_config(dat[,-1], group=dat$group, model="1PM")
print(pars)
#############################################################################
# EXAMPLE 8: Computation of standard errors
#############################################################################
G <- 3 # number of groups
I <- 5 # number of items
# define lambda and nu parameters
lambda <- matrix(1, nrow=G, ncol=I)
nu <- matrix(0, nrow=G, ncol=I)
# define size of noninvariance
dif <- 1
mu1 <- c(0,.3,.8)
sigma1 <- c(1,1.25,1.1)
#- 1st group
lambda[1,3] <- 1+dif*.4; nu[1,5] <- dif*.5
#- 2nd group
gg <- 2
lambda[gg,5] <- 1-.5*dif; nu[gg,1] <- -.5*dif
#- 3nd group
gg <- 3
lambda[gg,4] <- 1-.7*dif; nu[gg,2] <- -.5*dif
dat <- sirt::invariance_alignment_simulate(nu=nu, lambda=lambda, err_var=1+0*lambda,
mu=mu1, sigma=sigma1, N=500, output="data", exact=TRUE)
#* estimate CFA
res <- sirt::invariance_alignment_cfa_config(dat=dat[,-1], group=dat$group )
#- perform invariance alignment
eps <- .001
align.pow <- 0.5*rep(1,2)
lambda <- res$lambda
nu <- res$nu
mod1 <- sirt::invariance.alignment( lambda=lambda, nu=nu, eps=eps, optimizer="optim",
align.pow=align.pow, meth=meth, vcov=res$vcov)
# variance matrix and standard errors
mod1$vcov
sqrt(diag(mod1$vcov))
#############################################################################
# EXAMPLE 9: Comparison 2 groups for dichotomous data | data.pisaMath
#############################################################################
data(data.pisaMath)
dat <- data.pisaMath$data
library("lavaan")
model1 <- "
F=~ M192Q01 + M406Q01 + M406Q02 + M423Q01 + M496Q01 + M496Q02 + M564Q01 +
M564Q02 + M571Q01 + M603Q01 + M603Q02
"
fit.configural <- lavaan::cfa(model1, data=dat, group="female",
ordered=TRUE, std.lv=TRUE, parameterization="theta")
lavaan::summary(fit.configural, standardized=TRUE)
# extract item parameters separate group analyses
ipars <- lavaan::parameterEstimates(fit.configural)
# extract lambda's: groups are in rows, items in columns
lambda <- matrix( ipars[ ipars$op=="=~", "est"], nrow=2, byrow=TRUE)
colnames(lambda) <- colnames(dat)[6:16]
# extract nu's
nu <- matrix( ipars[ ipars$op=="|" & ipars$se !=0, "est" ], nrow=2, byrow=TRUE)
colnames(nu) <- colnames(dat)[6:16]
# Model 1: apply invariance alignment
mod1 <- sirt::invariance.alignment( lambda=lambda, nu=nu )
summary(mod1)
}