Skip to content

Commit d1484a1

Browse files
committed
adjust the overall model fit table
1 parent 9fb7230 commit d1484a1

File tree

4 files changed

+70
-60
lines changed

4 files changed

+70
-60
lines changed

R/plssem.R

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -309,29 +309,11 @@ checkCSemModel <- function(model, availableVars) {
309309
.plsSemFitTab <- function(modelContainer, dataset, options, ready) {
310310
# create model fit table
311311
if (!is.null(modelContainer[["fittab"]])) return()
312-
313-
fittab <- createJaspTable(title = gettext("Model Fit"))
314-
fittab$dependOn(optionsFromObject = modelContainer,
315-
options = c("group", "bollenStineBootstrapSamples", "significanceLevel", "saturatedStructuralModel"))
316-
fittab$position <- 0
317-
318-
if (options[["group"]] != "")
319-
fittab$addColumnInfo(name = "group", title = gettext("Group"), type = "string", combine = TRUE)
320-
321-
fittab$addColumnInfo(name = "measure", title = gettext("Distance Measure"), type = "string" )
322-
fittab$addColumnInfo(name = "statistic", title = gettext("Test Statistic"), type = "number" )
323-
fittab$addColumnInfo(name = "critValue", title = gettext("Critical Value"), type = "number" )
324-
325-
modelContainer[["fittab"]] <- fittab
326-
327312
if (!ready) return()
328313

329314
# fill model fit table
330315
plsSemResults <- .plsSemComputeResults(modelContainer, dataset, options)
331-
332-
if (modelContainer$getError()) return()
333-
334-
# we need this for a lot of other tables
316+
# we need this for a lot of other tables so we do this once here:
335317
results <- plsSemResults[[1]]
336318
msc <- .withWarnings(.computeMSC(results, dataset, options))
337319
#create jasp state and store msc for additional output tables
@@ -340,33 +322,51 @@ checkCSemModel <- function(model, availableVars) {
340322
modSelCriteria$dependOn(optionsFromObject = modelContainer)
341323
modSelCriteria$object <- msc
342324

325+
if (modelContainer$getError() || !options[["overallModelFit"]]) return()
326+
327+
fittab <- createJaspTable(title = gettext("Model Fit"))
328+
fittab$dependOn(optionsFromObject = modelContainer,
329+
options = c("group", "omfBootstrapSamples", "omfSignificanceLevel", "saturatedStructuralModel"))
330+
fittab$position <- 0
331+
332+
if (options[["group"]] != "")
333+
fittab$addColumnInfo(name = "group", title = gettext("Group"), type = "string", combine = TRUE)
334+
335+
fittab$addColumnInfo(name = "measure", title = gettext("Distance Measure"), type = "string" )
336+
fittab$addColumnInfo(name = "statistic", title = gettext("Test Statistic"), type = "number" )
337+
fittab$addColumnInfo(name = "critValue", title = gettextf("Critical Value (1-%s)", options[["omfSignificanceLevel"]]), type = "number" )
338+
343339
vv <- cSEM::verify(plsSemResults[[1]])
344340
if (any(unlist(vv))) {
345341
fittab$setError(gettext("At least one result is inadmissible."))
346342
return()
347343
}
348344

349345
omf <- .withWarnings(cSEM::testOMF(.object = plsSemResults[[1]],
350-
.alpha = options[["significanceLevel"]],
351-
.R = options[["bollenStineBootstrapSamples"]],
346+
.alpha = options[["omfSignificanceLevel"]],
347+
.R = options[["omfBootstrapSamples"]],
352348
.saturated = options[["saturatedStructuralModel"]],
353349
.seed = if (options[["setSeed"]]) options[["seed"]]))
354350
fit <- omf$value
355351

356352
if (options[["group"]] == "") {
357-
stat <- fit$Test_statistic
353+
stat <- fit$Test_statistic
358354
fittab[["measure"]] <- names(stat)
359355
fittab[["statistic"]] <- stat
360356
fittab[["critValue"]] <- fit$Critical_value
361357

362358
} else {
363-
stats <- sapply(fit, function(x) x$Test_statistic)
359+
stats <- sapply(fit, function(x) x$Test_statistic)
364360
fittab[["group"]] <- rep(names(fit), each = nrow(stats))
365361
fittab[["measure"]] <- rep(rownames(stats), ncol(stats))
366362
fittab[["statistic"]] <- c(stats)
367363
fittab[["critValue"]] <- c(sapply(fit, function(x) x$Critical_value))
368364
}
369365

366+
modelContainer[["fittab"]] <- fittab
367+
368+
return()
369+
370370
}
371371

372372
# compute model selection criteria/ fit measures

inst/help/PLSSEM.md

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,33 @@ This document explains how to perform Partial Least Squares Structural Equation
44

55
## 1. Model Setup
66
---
7-
In the **Model** section, you can specify the structural equation model using lavaan syntax. The following operators can be used: =~ to specify a latent variable
8-
measured by a set of indicators; <~ to specify a composite/emergent variable that is made up of a set of indicators; and ~ to specify the structural model, i.e., the relationships
9-
between the latent variables and the composites. In specifying the relationships between the latent variables and the composites,
10-
they must not be isolated in the structural model. In addition, no indicator may be connected to more than one latent variable/composite.
11-
Furthermore, the structural model may not include any observed variables, i.e., to include observed variables in the structural model they must be specified as
12-
a single-indicator construct. Finally, a grouping variable can be selected. In this case, the model is estimated separately for each group.
13-
14-
- **Grouping Variable**: You can select the grouping variable for multi-group analysis. The grouping variable is optional and can be left empty if not required.
7+
In the **Model** section, you can specify the structural equation model using lavaan syntax.
8+
The following operators can be used: =~ to specify a latent variable
9+
measured by a set of indicators; <~ to specify a composite/emergent variable that is made up of a set of indicators;
10+
and ~ to specify the structural model, i.e., the relationships
11+
between the latent variables and the composites. In specifying
12+
the relationships between the latent variables and the composites,
13+
they must not be isolated in the structural model. In addition,
14+
no indicator may be connected to more than one latent variable/composite.
15+
Furthermore, the structural model may not include any observed variables, i.e.,
16+
to include observed variables in the structural model they must be specified as
17+
a single-indicator construct. Finally, a grouping variable can be selected.
18+
In this case, the model is estimated separately for each group.
19+
20+
- **Grouping Variable**: You can select the grouping variable for multi-group analysis.
21+
The grouping variable is optional and can be left empty if not required.
1522

1623
## 2. Estimation Options
1724
---
1825
In the **Estimation** section, the following options are available:
1926

20-
- **Consistent Partial Least Squares**: Enables the option to use consistent partial least squares (PLSc), which, in contrast to traditional PLS, produces consistent estimates for latent variable models (=~). In this case, Mode A weights are transformed to obtain consistent factor loadings.
21-
In addition, the correlations between latent variables and other variables of the structural model are corrected for attenuation before they are used to estimate the parameters of the structural model.
27+
- **Consistent partial least squares**: Enables the option to use consistent partial least squares (PLSc), which,
28+
in contrast to traditional PLS, produces consistent estimates for latent variable models (=~).
29+
In this case, Mode A weights are transformed to obtain consistent factor loading estimates.
30+
In addition, the correlations between latent variables and other variables of the structural model are corrected
31+
for attenuation before they are used to estimate the parameters of the structural model.
2232

23-
- **Inner Weighting Scheme**: Choose from the following options to calculate inner weights used in the PLS algorithm:
33+
- **Inner weighting scheme**: Choose from the following options to calculate inner weights used in the PLS algorithm:
2434
- Path weighting scheme
2535
- Centroid weighting scheme
2636
- Factorial weighting scheme
@@ -36,13 +46,11 @@ In case of centroid and factorial inner weighting schemes, the structural model
3646

3747
- **Error calculation method**: Choose from the following options to calculate the standard errors and confidence intervals of the parameter estimates:
3848
- None
39-
- Robust: Use one of the following resample techniques:
40-
- Bootstrap
41-
- Jackknife
49+
- Bootstrap
4250

4351
**Samples**: The number of bootstrap runs can be specified.
4452

45-
**Repeatabilty**: A seed can be set, to make the analysis reproducible.
53+
**Repeatability**: A seed can be set, to make the analysis reproducible.
4654

4755

4856
## 3. Output Options
@@ -59,6 +67,20 @@ The **Output** section includes options to customize the output you want to gene
5967
- **Observed construct correlations**: Enable output of the construct correlation matrix.
6068
- **Implied construct correlations**: Enable output of the model-implied construct correlation matrix.
6169

70+
- **Overall model fit** Enables the option to assess the overall fit of the model.
71+
In particular, bootstrap in combination with various distance measures, i.e., the geodesic distance (dG),
72+
the standardized root mean square residual (SRMR), the squared Euclidean distance (dL),
73+
and the distance of the ML fit function (dML) is used to assess
74+
the discrepancy between the sample correlation matrix and the model-implied counterpart.
75+
In the literature, this approach is also known as Bollen-Stine bootstrap. If the test statistic value
76+
is below the critical value the discrepancy is so small that equality between the model-implied
77+
and the sample correlation matrix can be assumed, that is, the model is a good representation of the structure
78+
in the population.
79+
- Bootstrap runs: Specify the number of bootstrap runs
80+
- significance level: Specify the significance level for the bootstrap test.
81+
The significance level is used to determine the critical value.
82+
The critical value is determined as 1-alpha quantile of the bootstrap distance measures.
83+
- Saturated structural model: Enables the option to assess the overall fit of a model with a saturated structural model.
6284

6385
You can also add **construct scores** to the dataset for further analysis.
6486

inst/qml/PLSSEM.qml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,7 @@ Form
143143
RadioButton { value: "drop"; label: qsTr("Drop") }
144144
}
145145
}
146-
Group
147-
{
148-
title: qsTr("Overall Model Fit")
149-
IntegerField { name: "bollenStineBootstrapSamples"; label: qsTr("Bollen-Stine bootstrap samples"); fieldWidth: 60; defaultValue: 499; min: 100 }
150-
CIField { text: qsTr("Significance level"); name: "significanceLevel"; defaultValue: 5 }
151-
CheckBox { name: "saturatedStructuralModel"; label: qsTr("Saturated structural model") }
152-
}
146+
153147
SetSeed {}
154148

155149
}
@@ -174,6 +168,14 @@ Form
174168
CheckBox { name: "impliedConstructCorrelation"; label: qsTr("Implied construct correlations") }
175169
}
176170

171+
Group
172+
{
173+
CheckBox { name: "overallModelFit"; label: qsTr("Overall model fit") ; id: omf}
174+
IntegerField { visible:omf.checked; name: "omfBootstrapSamples"; label: qsTr("Bootstrap samples"); fieldWidth: 60; defaultValue: 499; min: 100 }
175+
CIField { visible: omf.checked; text: qsTr("Significance level"); name: "omfSignificanceLevel"; defaultValue: 5 }
176+
CheckBox { visible: omf.checked; name: "saturatedStructuralModel"; label: qsTr("Saturated structural model") }
177+
}
178+
177179
CheckBox
178180
{
179181
name: "addConstructScores"

tests/testthat/test-plssem.R

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ options$models <- list(list(name = "Model1", syntax = list(model = model, column
1414
options$group <- ""
1515
options$innerWeightingScheme <- "path"
1616
options$convergenceCriterion <- "absoluteDifference"
17+
options$overallModelFit <- TRUE
1718
options$setSeed <- TRUE
1819
options$seed <- 123
1920
results <- jaspTools::runAnalysis("PLSSEM", testthat::test_path("poldem_grouped.csv"), options, makeTests = F)
@@ -348,14 +349,6 @@ options$seed <- 123
348349
results <- jaspTools::runAnalysis("PLSSEM", testthat::test_path("poldem_grouped.csv"), options, makeTests = F)
349350

350351

351-
test_that("Model Fit table results match", {
352-
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_fittab"]][["data"]]
353-
jaspTools::expect_equal_tables(table,
354-
list(0.43026588019435, "dG", 0.295547730720455, 0.0560152218904532,
355-
"SRMR", 0.0529946519222452, 0.207096082194422, "dL", 0.185356586735755,
356-
1.97158372315007, "dML", 1.67522948035842))
357-
})
358-
359352
test_that("Loadings table results match", {
360353
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_params"]][["collection"]][["modelContainer_params_loading"]][["data"]]
361354
jaspTools::expect_equal_tables(table,
@@ -491,13 +484,6 @@ test_that("Additional Fit Measures table results match", {
491484
))
492485
})
493486

494-
test_that("Model Fit table results match", {
495-
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_fittab"]][["data"]]
496-
jaspTools::expect_equal_tables(table,
497-
list(0.323791481284916, "dG", 0.64934321996922, 0.0528204560328008,
498-
"SRMR", 0.0939687096223916, 0.705870543876173, "dL", 2.23401995218863,
499-
1.59241569142443, "dML", 2.92193232413733))
500-
})
501487

502488
test_that("Mardia's coefficients table results match", {
503489
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_mardiasTable"]][["data"]]

0 commit comments

Comments
 (0)