congruence() reports the congruence
coefficient rc for every pair of constructs as a square table, laid out
the way seminr prints HTMT so the two read alike in a chapter that shows
both. It is deterministic — one pass over the estimated model, no
resampling — so it returns immediately rather than re-estimating the
model 2000 times.
rc is an effect size, and congruence()
reports it as one: the coefficients and nothing else. Franke, Sarstedt
and Danks (2021) define congruence as proportionality of two
correlation profiles, which does not require rc to equal 1, and state
that the DIFF and WALD procedures they evaluate do not transfer to
PLS-SEM. No significance test for rc has been validated for PLS-SEM
since. rc is also bounded above by 1, so sampling error can only move an
estimate downwards — testing an estimate against that boundary is not
informative. summary() prints the range and this
caveat.
The formula, the reliability diagonal and the construct set are now
shared internals used by both congruence() and
congruence_test(), so the two cannot drift apart.
congruence_test() is unchanged in behaviour — its existing
tests, including the 36-cell characterisation of the corporate
reputation model, pass untouched.
assess_cvpat() and
assess_cvpat_compare() with reps greater than
1 now run the cross-validation on new random folds in every
repetition, compute each observation’s loss within each repetition, and
average the losses over the repetitions. More repetitions therefore
reduce Monte Carlo noise without changing what is estimated. Before,
with seminr 2.5.0 and earlier, every repetition reused the same folds,
so reps = 10 gave the result of a single run. (With seminr
2.6.0, which draws new folds but averages the predictions, the
old code would have scored an ensemble of models, whose loss falls as
repetitions are added, and most for the linear-model benchmark, whose
predictions vary most across folds.) Results with reps
greater than 1 change; reps = NULL or reps = 1
give the same results as before.demo/seminr-primer-v2-chap8.R now uses
seed = 123 for the moderated-mediation bootstrap, replacing
seed = 12345. The PLS-SEM R book uses 123 throughout and
says so explicitly (“Following this convention, we set the seed = 123”),
and the book’s own chapter 8 code box prints 123 — so the demo was the
outlier, and Fig. 8.12 had been generated from it rather than from the
book’s code. The figure is being regenerated to match. No change to any
other seed.
The two index-of-moderated-mediation intervals are now wrapped in
round(., 4). Under seed 123 the COMP upper bound is about
-0.000054, which R renders as -1e-04 — the only piece of
scientific notation in the book, in a screenshot, in the final analysis
of the final chapter. options(scipen = ) does not fix this:
it chooses fixed over scientific notation but not the number of digits,
so it prints -0.00005395743 instead. Rounding is the fix,
and it sets no global state.
demo/seminr-primer-v2-chap4.R now calls
congruence() in place of congruence_test(),
matching the chapter’s revised code box.
demo("seminr-primer-v2-chap3") and
demo("seminr-help-debugging") stopped at their first
deliberate error, because demo() runs a file through
source(), which stops at the first error: the rest of each
demo never ran. The deliberate errors are now wrapped in
try(), which prints the error and continues.
seminr-help-debugging also passed
data = corp_rep, an object that does not exist (the dataset
is corp_rep_data); the syntax error masked this.
demo("seminr-primer-v2-chap2") no longer reinstalls
packages from CRAN every time it runs; the
install.packages() lines are commented out, as in the
chapter 3 demo.
demo/seminr-pls-congruence.R rewritten around
congruence(). Its previous description was also wrong: it
said the coefficient compares “PLS composite weights and bootstrapped
weights”, where in fact it compares two constructs’ correlation
profiles.
congruence_test(nboot = 0) errored with
length of 'dimnames' [3] not equal to array extent. The
bootstrap array was named 1:nboot, which is
c(1, 0) rather than empty when nboot is 0.
Fixing that exposed a second failure: sd() over an empty
slice returns NA, which then reached an if.
Both are fixed, and the inferential columns (Bootstrap SD,
T Stat., the CI bounds) are now NA — the
honest answer when there is no bootstrap distribution. Point estimates
are unchanged and identical to a bootstrapped run’s. This is the fast
path for checking congruence values without paying for 2000
resamples. Found by the new textbook regression tests.Added a textbook regression suite
(test-textbook-*.R) that checks the package still
reproduces numbers printed in the PLS-SEM R book, using
values transcribed by hand from the page proofs as an external oracle.
This closes a real gap: the previous harness only compared one package
version against another, which cannot detect the case where both agree
with each other and neither agrees with the book. It was exactly that
case which let the 1.0.3 reliability default change (rho_C
to rho_A) move every coefficient in Fig. 4.11 unnoticed.
These tests are excluded from CRAN, CI and cron —
skip_on_cran(), skip_on_ci(), plus an explicit
opt-in — because a failure needs a human to decide whether the code
regressed or the figure is due for regeneration. Run them with:
Sys.setenv(SEMINR_TEXTBOOK_TESTS = "true")
devtools::test(filter = "textbook")Coverage: Fig. 4.11 congruence coefficients, Fig. 6.9 CVPAT (both LM and IA benchmarks), the prose claims on p. 143 that quote Fig. 6.9, the argument defaults printed in Tables 6.2/6.3, pair-label ordering, and a static seed audit of the chapter demos.
This version exists so co-authors verifying the PLS-SEM R book can install a build distinguishable from CRAN 1.0.3:
remotes::install_github("sem-in-r/seminrExtras@develop")CRAN submission is on hold until textbook copyediting and errata are resolved.
congruence_test() now excludes interaction
constructs, naming any it drops in a message. An interaction
term’s measurement is fixed by the product method rather than by theory,
so its position in a nomological network is not interpretable — and it
was previously producing coefficients as low as -0.47 in a framework
built around near-redundancy. It is removed from the construct set
entirely rather than only from the pair list, because Eq. 2 sums over
the whole set: coefficients for the remaining pairs change accordingly.
This brings congruence into line with assess_cta(),
assess_pos(), assess_pcm() and
assess_cipma(), which already excluded them.
congruence_test() now refuses higher-order
models with a warning rather than returning a number. Two-stage
estimation replaces the lower-order constructs with a single
higher-order composite, and it has not been established what belongs on
that composite’s diagonal, nor whether a congruence coefficient between
a higher-order and a first-order construct is interpretable. Previously
such models ran and returned results.
congruence_test() gains a reliability
argument selecting which estimate sits on the diagonal of the
construct-correlation matrix: "rhoA", "rhoC",
"cronbach" (Cronbach’s alpha) or "one".
"cronbach" is included chiefly for comparison with
covariance-based SEM, where rho_A is unavailable. Franke, Sarstedt &
Danks (2021, Eq. 2) specify “the reliabilities” without fixing an
estimator, so all four are in specification.
The default is now "rhoA", changed from the
previous "rhoC". This aligns seminrExtras with
SmartPLS: on the simple corporate reputation model the
"rhoA" diagonal reproduces SmartPLS’s published
coefficients to three decimal places on all six construct pairs, and the
estimator choice accounts for the whole of the previous disagreement
between the two programs. Pass reliability = "rhoC" to
reproduce results generated with 1.0.2 or earlier.
The estimators differ only where internal consistency is undefined.
"rhoA", "rhoC" and "cronbach" all
return 1 for single-item constructs, so every option coincides in a
model built entirely from single indicators. They part company on Mode B
constructs: "rhoA" returns 1, while "rhoC" and
"cronbach" compute a value from the indicators. Note this
only affects pairs that involve a Mode B construct — each matrix column
carries exactly one reliability, its own construct’s, so a coefficient
between two reflective constructs is invariant to every other
construct’s diagonal. In a model mixing Mode A and Mode B the
"rhoA" diagonal is therefore set by measurement mode rather
than by the data, which shifts coefficients systematically — on the
extended corporate reputation model, reflective-reflective pairs rise
while formative-formative pairs fall, and the ranking of most-congruent
pairs changes. "one" removes the distinction by treating
every construct alike.
congruence_test() now attaches each congruence
coefficient — and its bootstrap SD, t-statistic, and confidence interval
— to the correct construct pair. Coefficients were generated in
combn() (row-major) order but written into the results
matrix via upper.tri() (column-major) order; the two
orderings diverge for models with four or more constructs, which
mislabelled non-adjacent pairs (e.g. COMP <> CUSL and
LIKE <> CUSA were swapped in the simple
corporate-reputation model, and 10 of 15 pairs were mislabelled in the
six-construct example). The coefficient values themselves were correct;
only their pair labels were wrong. Added a regression test asserting
pair-label correctness against an independent name-indexed
reference.test-cipma-comprehensive.R and
test-fimix.R no longer reach into seminr’s non-exported
internals via seminr:::items_of_construct() and
seminr:::all_endogenous(). They now use seminrExtras’s own
local helpers of the same name. This avoids breakage against forthcoming
seminr 2.5.0, which refactors (and renames) those internal helpers.Composite Overfit Analysis (COA):
assess_coa(), predictive_deviance(),
deviance_tree(), unstable_params(),
group_rules(), competes() for diagnosing
why and for whom PLS models fail to generalise
out-of-sample.
Necessary Condition Analysis (NCA):
assess_nca() with fully internal CE-FDH and CR-FDH
algorithms (no external NCA package dependency).
NCA-ESSE: assess_nca_esse()
implements the effect size sensitivity extension (Becker et al.,
2026).
Combined Importance-Performance Map Analysis
(cIPMA): assess_cipma() integrates IPMA with NCA
to classify constructs into actionable priority quadrants.
assess_ipma() provides an IPMA-only convenience wrapper.
Supports HOC, mediation, and moderation models.
FIMIX-PLS: assess_fimix() and
assess_fimix_compare() for EM-based latent class
segmentation with multi-start initialisation and information criteria
comparison.
PLS-POS: assess_pos(),
assess_pos_compare(), and pos_segments() for
prediction-oriented segmentation that maximises the sum of R-squared
across segments (Becker et al., 2013).
CTA-PLS: assess_cta() for
confirmatory tetrad analysis with automatic indicator borrowing for
constructs with fewer than 4 indicators (Gudergan et al.,
2008).
Predictive Contribution of the Mediator (PCM):
assess_pcm() evaluates whether a mediating construct
improves out-of-sample prediction by comparing DA and EA approaches on
isolated sub-models (Danks, 2021).
assess_cvpat() and
assess_cvpat_compare(): fixed bootstrap test branches, loss
function return types, and reference metadata.
congruence_test(): fixed division guard,
upper-triangular masking, and bootstrap robustness for
nboot = 0.
All features include print(),
summary(), and plot() S3 methods.
Comprehensive test suite (740+ tests).
Demo files for all features:
demo("seminr-pls-<feature>").
Updated vignette with examples for all features.
seminr >= 2.4.0.rpart added to Imports (for COA deviance trees).MASS, paran, psych,
learnr added to Suggests.