Alignment Procedure for Linking under Approximate Invariance
invariance.alignment.Rd
The 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
, thenfixed
is automatically chosen by default. For many groups,fixed=FALSE
is chosen.- meth
Type of method used for optimization function.
meth=1
is the default and the optimization function used in Mplus.meth=2
uses logarithmized item loadings in alignment. The choicemeth=4
uses 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=3
only uses the constraint \(\prod_g \psi_g=1\) (similar to Mplus' FIXED method).- vcov
Variance matrix produced by
invariance_alignment_cfa_config
for 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)
}