The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
ShortForm is an R package for constructing short-form assessments from larger item banks using reproducible, optimization-based workflows.
It provides implementations of three metaheuristic search algorithms to automate item selection while preserving prespecified psychometric properties (such as model fit):
antColony())
– adapted from Leite, Huang, &
Marcoulides (2008)simulatedAnnealing()) – following Kirkpatrick et
al. (1983)tabuSearch(), and the
lower-level tabu.sem()) – based on Marcoulides &
Falk (2018)All three search over candidate short forms of a lavaan
model, evaluating each candidate’s fit and keeping the best one found.
This vignette gives a quick tour of all three; see the dedicated
vignettes (vignette("antColony"),
vignette("simulatedAnnealing"),
vignette("tabuSearch")) for a deeper look at each one.
set.seed(58310)
result_ACO <- antColony(
data = lavaan::HolzingerSwineford1939,
ants = 2, evaporation = 0.7,
initialModel = " visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9 ",
itemsPerFactor = c(3, 3, 3),
steps = 2, fit.indices = c("cfi"), fit.statistics.test = "(cfi > 0.6)",
maxIterations = 2, parallel = FALSE, verbose = FALSE
)
result_ACO
#> Algorithm: Ant Colony Optimization
#> Total Run Time: 0.181 secs
#>
#> Function call:
#> antColony(data = lavaan::HolzingerSwineford1939, ants = 2, evaporation = 0.7,
#> initialModel = " visual =~ x1 + x2 + x3\n textual =~ x4 + x5 + x6\n speed
#> =~ x7 + x8 + x9 ", itemsPerFactor = c(3, 3, 3), steps = 2, fit.indices =
#> c("cfi"), fit.statistics.test = "(cfi > 0.6)", maxIterations = 2, parallel =
#> FALSE, verbose = FALSE, sample.cov = NULL, sample.nobs = NULL, items = NULL,
#> bifactor = NULL, lavaan.model.specs = list(model.type = "cfa", estimator
#> = "default", ordered = NULL, int.ov.free = TRUE, int.lv.free = FALSE,
#> auto.fix.first = TRUE, auto.fix.single = TRUE, auto.var = TRUE, auto.cov.lv.x
#> = TRUE, auto.th = TRUE, auto.delta = TRUE, auto.cov.y = TRUE, std.lv = FALSE,
#> group = NULL, group.label = NULL, group.equal = "loadings", group.partial =
#> NULL, group.w.free = FALSE), pheromone.calculation = "gamma")
#>
#> Final Model Syntax:
#> visual =~ x1 + x2 + x3
#> textual =~ x4 + x5 + x6
#> speed =~ x7 + x8 + x9
#>
#> Fit Indices: cfi
#> Fit Test: (cfi > 0.6)
#> Final Model Values: cfi = 0.931set.seed(58310)
result_SA <- suppressWarnings(simulatedAnnealing(
initialModel = " visual =~ x1 + x2 + x3
textual =~ x4 + x5 + x6
speed =~ x7 + x8 + x9 ",
originalData = lavaan::HolzingerSwineford1939,
maxIterations = 3,
criterion = "cfi", negateCriterion = TRUE,
itemsPerFactor = c(2, 2, 2),
items = paste0("x", 1:9)
))
#> Initializing short form creation.
#> The initial short form is:
#> visual =~ x2 + x1
#> textual =~ x6 + x4
#> speed =~ x8 + x7
#>
#> Using the short form randomNeighbor function.
#> Finished initializing short form options.
#> Current Progress:
#> Old Fit: 0.97 New Fit: 0.985 Current Step = 2 of a maximum 3. Current Step = 3 of a maximum 3.
result_SA
#> Algorithm: Simulated Annealing
#> Total Run Time: 0.061 secs using 1 chains.
#>
#> Function call:
#> simulatedAnnealing(initialModel = " visual =~ x1 + x2 + x3\n textual =~ x4 + x5
#> + x6\n speed =~ x7 + x8 + x9 ", originalData = lavaan::HolzingerSwineford1939,
#> maxIterations = 3, criterion = "cfi", negateCriterion = TRUE, itemsPerFactor
#> = c(2, 2, 2), items = paste0("x", 1:9), temperature = "linear", Kirkpatrick
#> = TRUE, randomNeighbor = TRUE, lavaan.model.specs = list(model.type = "cfa",
#> auto.var = TRUE, estimator = "default", ordered = NULL, int.ov.free = TRUE,
#> int.lv.free = FALSE, std.lv = TRUE, auto.fix.first = FALSE, auto.fix.single
#> = TRUE, auto.cov.lv.x = TRUE, auto.th = TRUE, auto.delta = TRUE, auto.cov.y =
#> TRUE), maxChanges = 5, restartCriteria = "consecutive", maximumConsecutive =
#> 25, bifactor = NULL, setChains = 1, shortForm = T)
#>
#> Final Model Syntax:
#> visual =~ x3 + x1
#> textual =~ x5 + x4
#> speed =~ x8 + x9
#>
#>
#>
#> Criterion: "cfi" (maximized)
#> Final Model Value: 0.985set.seed(58310)
shortAntModel <- "
Ability =~ Item1 + Item2 + Item3 + Item4 + Item5 + Item6 + Item7 + Item8
Ability ~ Outcome
"
result_TS <- tabuSearch(
initialModel = shortAntModel,
originalData = simulated_test_data, itemsPerFactor = 7,
maxIterations = 3, tabu.size = 3, parallel = FALSE
)
#> Running iteration 1 of 3. Running iteration 2 of 3. Running iteration 3 of 3.
result_TS
#> Algorithm: Tabu Search
#> Total Run Time: 0.464 secs
#>
#> Function call:
#> tabuSearch(originalData = simulated_test_data, initialModel = shortAntModel,
#> itemsPerFactor = 7, maxIterations = 3, tabu.size = 3, parallel = FALSE,
#> items = NULL, criterion = "cfi", negateCriterion = TRUE, lavaan.model.specs =
#> list(int.ov.free = TRUE, int.lv.free = FALSE, std.lv = TRUE, auto.fix.first =
#> FALSE, auto.fix.single = TRUE, auto.var = TRUE, auto.cov.lv.x = TRUE, auto.th
#> = TRUE, auto.delta = TRUE, auto.cov.y = TRUE, ordered = NULL, model.type =
#> "cfa", estimator = "default"), bifactor = NULL, verbose = FALSE)
#>
#> Final Model Syntax:
#> Ability =~ Item1 + Item6 + Item3 + Item4 + Item5 + Item7 + Item8
#> Ability ~ Outcome
#>
#> Criterion: "cfi" (maximized)
#> Final Model Value: 1There’s no universally “best” choice – all three are heuristic searches, so it’s reasonable to try more than one and compare results. A few practical differences:
setChains) gives several
independent searches to compare.Every algorithm returns an S4 object with:
show()/print() – a compact summary: run
time, the selected criterion and its final-model value, the function
call, and the final model syntaxsummary() – the above plus the full lavaan
fit outputplot() – a visualization of how the search progressed
(fit over iterations/steps, or ACO’s pheromone/regression
diagnostics)These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.