PsychoMatic automates bounded psychometric workflows with short syntax while keeping the evidence available for inspection. Automation is not a substitute for construct definition, sampling design, identification, or substantive judgment. Version 1.0.0 makes those boundaries more visible through structured result objects.
The data below are simulated locally and must not be used for population inference.
set.seed(2401)
latent <- matrix(stats::rnorm(300 * 3), ncol = 3)
ordinal_items <- as.data.frame(sapply(seq_len(12), function(j) {
as.integer(cut(0.8 * latent[, ceiling(j / 4)] + stats::rnorm(300, sd = 0.6),
breaks = c(-Inf, -1, -0.3, 0.3, 1, Inf), labels = FALSE))
}))
names(ordinal_items) <- sprintf("item%02d", 1:12)
attr(ordinal_items, "reverse_keys") <- c("item03", "item07", "item11")
ordinal_items[attr(ordinal_items, "reverse_keys")] <-
lapply(ordinal_items[attr(ordinal_items, "reverse_keys")], function(x) 6L - x)
attr(ordinal_items, "factor_structure") <- list(
factor1 = names(ordinal_items)[1:4], factor2 = names(ordinal_items)[5:8],
factor3 = names(ordinal_items)[9:12]
)
ranges <- stats::setNames(rep(list(c(1, 5)), ncol(ordinal_items)), names(ordinal_items))
specification <- PsychoMatic::psychomatic_spec(
ordinal_items,
level = "ordinal",
reverse = attr(ordinal_items, "reverse_keys"),
ranges = ranges,
missing = "available",
language = "eng"
)
summary(specification)$items
#> item measurement_level reverse range_min range_max
#> 1 item01 ordinal FALSE 1 5
#> 2 item02 ordinal FALSE 1 5
#> 3 item03 ordinal TRUE 1 5
#> 4 item04 ordinal FALSE 1 5
#> 5 item05 ordinal FALSE 1 5
#> 6 item06 ordinal FALSE 1 5
#> 7 item07 ordinal TRUE 1 5
#> 8 item08 ordinal FALSE 1 5
#> 9 item09 ordinal FALSE 1 5
#> 10 item10 ordinal FALSE 1 5
#> 11 item11 ordinal TRUE 1 5
#> 12 item12 ordinal FALSE 1 5psychomatic_spec() records item selection, measurement
level, ordered categories, reverse keys, valid ranges, grouping,
metadata, and missing-data intent. Character, unordered factor, and
logical encodings are not assigned an ordinal order silently.
scores <- PsychoMatic::score_scale(
specification,
keys = attr(ordinal_items, "factor_structure"),
reverse = attr(ordinal_items, "reverse_keys"),
min_score = 1,
max_score = 5,
min_valid = 0.80
)
utils::head(scores$scores)
#> factor1 factor2 factor3
#> 1 2.50 2.50 1.25
#> 2 3.50 2.25 4.00
#> 3 4.25 4.50 1.75
#> 4 4.25 3.75 2.50
#> 5 3.00 4.75 1.50
#> 6 3.25 1.00 3.00Incomplete eligible scores are prorated under the documented
min_valid rule, so the scoring policy should be
reported.
Most analytical objects in 1.0.0 inherit from
psychomatic_result. They keep the call, requested and
effective settings, data summary, raw results, structured warnings and
errors, diagnostics, decision log, and conclusion. Numerical fields
retain full precision (raw values); rounding is for display. A
not_evaluable state must not be interpreted as evidence of
no problem.
An integrated workbook or document is created only by an explicit
psychomatic_report() call. Report targets are checked
before writing and existing files are not replaced unless
overwrite = TRUE is chosen.
if (requireNamespace("openxlsx", quietly = TRUE)) {
output <- tempfile("psychomatic-introduction-", fileext = ".xlsx")
PsychoMatic::psychomatic_report(
scores,
format = "excel",
file_name = output,
overwrite = FALSE
)
}The export chunk is not evaluated while building the vignette because it is an optional file-writing demonstration; the installed example script exercises the same path in a temporary directory.