Skip to content

Commit 4e59a5b

Browse files
authored
Fix invariance error (#318)
1 parent 8e3f79e commit 4e59a5b

File tree

7 files changed

+102
-92
lines changed

7 files changed

+102
-92
lines changed

R/common.R

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ lavBootstrap <- function(fit, samples = 1000, standard = FALSE, typeStd = NULL,
4242
startProgressbar(samples + 1)
4343

4444
if (!standard) {
45-
bootres <- lavaan::bootstrapLavaan(object = fit, R = samples, FUN = coefWithCallback, iseed = iseed)
45+
bootres <- lavaan::bootstrapLavaan(object = fit, R = samples, FUN = coefWithCallback, iseed = iseed, type = "nonparametric")
4646
} else {
47-
bootres <- lavaan::bootstrapLavaan(object = fit, R = samples, FUN = coefWithCallbackStd, typeStd = typeStd, iseed = iseed)
47+
bootres <- lavaan::bootstrapLavaan(object = fit, R = samples, FUN = coefWithCallbackStd, typeStd = typeStd, iseed = iseed, type = "nonparametric")
4848
}
4949

5050
# Add the bootstrap samples to the fit object
@@ -59,24 +59,26 @@ lavBootstrap <- function(fit, samples = 1000, standard = FALSE, typeStd = NULL,
5959

6060
# we actually need the SEs from the bootstrap not the SEs from ML or some other estimator
6161
N <- nrow(fit@boot$coef)
62+
P <- ncol(fit@boot$coef)
63+
freePars <- which(fit@ParTable$free != 0)
6264

63-
# we multiply the var by (n-1)/n because lavaan actually uses n for the variance instead of n-1
6465
if (!standard) {
6566
# for unstandardized
66-
fit@ParTable$se[fit@ParTable$free != 0] <- apply(fit@boot$coef, 2, sd) * sqrt((N-1)/N)
67+
fit@ParTable$se[freePars] <- apply(fit@boot$coef, 2, sd)
6768
} else {
68-
fit@ParTable$se <- apply(fit@boot$coef, 2, sd) * sqrt((N-1)/N)
69-
# the standardized solution gives all estimates not only the unconstrained, so we need to change
70-
# the free prameters in the partable and also change the estimate
71-
fit@ParTable$free <- seq_len(ncol(fit@boot$coef))
69+
# we replace 1:P because the boot coef output contains also the constrained parameters
70+
fit@ParTable$se[1:P] <- apply(fit@boot$coef, 2, sd)
71+
fit@boot$coef <- fit@boot$coef[, freePars, drop = FALSE]
7272
std <- lavaan::standardizedSolution(fit, type = typeStd)
73-
fit@ParTable$est <- std$est.std
73+
# for the standardized output we also replace some constrained elements
74+
fit@ParTable$est[1:P] <- std$est.std
7475
}
7576

7677
return(fit)
7778
}
7879

7980

81+
8082
# Function to create a misfit plot
8183
.resCorToMisFitPlot <- function(rescor) {
8284
ggmisfit <- reshape2::melt(abs(t(rescor)))

R/mediationanalysis.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ MediationAnalysisInternal <- function(jaspResults, dataset, options, ...) {
115115
mimic = options$emulation,
116116
estimator = options$estimator,
117117
missing = miss
118-
))
118+
))
119119

120120
if (inherits(medResult, "try-error")) {
121121
errmsg <- gettextf("Estimation failed\nMessage:\n%s", attr(medResult, "condition")$message)

inst/qml/MediationAnalysis.qml

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,34 +27,39 @@ Form
2727
{
2828
VariablesForm
2929
{
30-
AvailableVariablesList
31-
{
32-
name: "availableVariables"
33-
}
34-
AssignedVariablesList
35-
{
36-
title: qsTr("Predictors")
37-
name: "predictors"
38-
allowedColumns: []
39-
}
40-
AssignedVariablesList
41-
{
42-
title: qsTr("Mediators")
43-
name: "mediators"
44-
allowedColumns: ["scale", "ordinal"]
45-
}
46-
AssignedVariablesList
47-
{
48-
title: qsTr("Outcome")
49-
name: "outcomes"
50-
allowedColumns: ["scale", "ordinal"]
51-
}
52-
AssignedVariablesList
53-
{
54-
title: qsTr("Background confounders")
55-
name: "confounds"
56-
allowedColumns: []
57-
}
30+
AvailableVariablesList
31+
{
32+
name: "availableVariables"
33+
}
34+
AssignedVariablesList
35+
{
36+
title: qsTr("Predictors")
37+
name: "predictors"
38+
id: predictors
39+
}
40+
AssignedVariablesList
41+
{
42+
title: qsTr("Mediators")
43+
name: "mediators"
44+
allowedColumns: ["scale", "ordinal"]
45+
allowTypeChange: true
46+
id: mediators
47+
48+
}
49+
AssignedVariablesList
50+
{
51+
title: qsTr("Outcome")
52+
name: "outcomes"
53+
allowedColumns: ["scale", "ordinal"]
54+
allowTypeChange: true
55+
id: outcomes
56+
}
57+
AssignedVariablesList
58+
{
59+
title: qsTr("Background confounders")
60+
name: "confounds"
61+
id: confounds
62+
}
5863
}
5964

6065
Section
@@ -86,9 +91,10 @@ Form
8691
CheckBox { label: qsTr("Path coefficients"); name: "pathCoefficient"; checked: true }
8792
}
8893
}
89-
94+
// create a string with all variables types to pass to the error calc elements
95+
// property bool ordinal:
9096
Common.ErrorCalculation{}
91-
97+
9298
}
9399

94100
Section

inst/qml/SEM.qml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,9 @@ Form
248248
label: qsTr(" Type")
249249
name: "bootstrapCiType"
250250
values: [
251-
{ label: qsTr("Bias-corrected percentile"), value: "percentileBiasCorrected" },
252-
{ label: qsTr("Percentile"), value: "percentile" },
253-
{ label: qsTr("Normal theory"), value: "normalTheory" }
251+
{ label: qsTr("Bias-corrected percentile"), value: "percentileBiasCorrected" },
252+
{ label: qsTr("Percentile"), value: "percentile" },
253+
{ label: qsTr("Normal theory"), value: "normalTheory" }
254254
]
255255
}
256256

@@ -338,10 +338,10 @@ Form
338338
name: "standardizedEstimate"; label: qsTr("Standardized estimates");
339339
RadioButtonGroup
340340
{
341-
name: "standardizedEstimateType"
342-
RadioButton { value: "all"; label: qsTr("All"); checked: true }
343-
RadioButton { value: "latents"; label: qsTr("Latents") }
344-
RadioButton { value: "nox"; label: qsTr("Except exogenous covariates") }
341+
name: "standardizedEstimateType"
342+
RadioButton { value: "all"; label: qsTr("All"); checked: true }
343+
RadioButton { value: "latents"; label: qsTr("Latents") }
344+
RadioButton { value: "nox"; label: qsTr("Except exogenous covariates") }
345345
}
346346
}
347347
CheckBox

inst/qml/common/ErrorCalculation.qml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ import QtQuick.Layouts
2121
import JASP.Controls
2222
import JASP
2323

24+
2425
Group
2526
{
27+
2628
CIField {
27-
text: qsTr("Confidence intervals")
29+
text: qsTr("Confidence intervals" )
2830
name: "ciLevel"
2931
info: qsTr("Set the confidence level for the interval estimates")
3032
}
@@ -59,9 +61,9 @@ Group
5961
label: qsTr("Type")
6062
name: "bootstrapCiType"
6163
values: [
62-
{ label: qsTr("Bias-corrected percentile"), value: "percentileBiasCorrected" },
63-
{ label: qsTr("Percentile"), value: "percentile" },
64-
{ label: qsTr("Normal theory"), value: "normalTheory" }
64+
{ label: qsTr("Bias-corrected percentile"), value: "percentileBiasCorrected" },
65+
{ label: qsTr("Percentile"), value: "percentile" },
66+
{ label: qsTr("Normal theory"), value: "normalTheory" }
6567
]
6668
info: qsTr("Select the type of bootstrap confidence interval to compute")
6769
}

tests/testthat/test-mediationanalysis.R

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -187,42 +187,42 @@ options$bootstrapCiType <- "percentileBiasCorrected"
187187
options$naAction <- "fiml"
188188

189189
set.seed(1)
190-
results <- jaspTools::runAnalysis("MediationAnalysis", "test.csv", options)
190+
results <- jaspTools::runAnalysis("MediationAnalysis", "test.csv", options, makeTests = F)
191191

192192
test_that("Direct effects table results match", {
193193
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_dir"]][["data"]]
194194
jaspTools::expect_equal_tables(table,
195-
list(0.0761400441342019, 0.671443275931248, 0.257757843176866, "contcor1",
196-
"<unicode>", 0.0589199802205698, "contNormal", 0.136467182830779,
197-
1.88878994810415))
195+
list(0.0761400418471621, 0.67144328199062, 0.257757843176866, "contcor1",
196+
"<unicode>", 0.0602005168476014, "contNormal", 0.137154686851546,
197+
1.87932216604351))
198198
})
199199

200200
test_that("Indirect effects table results match", {
201201
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_ind"]][["data"]]
202202
jaspTools::expect_equal_tables(table,
203-
list(-0.299720825954233, 0.073293678485771, -0.0893136104463747, "contcor2",
204-
"<unicode>", "<unicode>", 0.321618931630391, 0.0901123208859354,
205-
"contcor1", "contNormal", -0.991136501294072))
203+
list(-0.299720820153127, 0.0732936772629952, -0.0893136104463748, "contcor2",
204+
"<unicode>", "<unicode>", 0.321618931631225, 0.0901123208860908,
205+
"contcor1", "contNormal", -0.991136501292364))
206206
})
207207

208208
test_that("Path coefficients table results match", {
209209
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_path"]][["data"]]
210210
jaspTools::expect_equal_tables(table,
211-
list(-0.475862353202892, 0.110585521838546, -0.136980447123533, "contcor2",
212-
"<unicode>", 0.306661780077382, "contNormal", 0.133998745278152,
213-
-1.02225171466488, 0.0761400441342019, 0.671443275931248, 0.257757843176866,
214-
"contcor1", "<unicode>", 0.0589199802205698, "contNormal", 0.136467182830779,
215-
1.88878994810415, 0.481651777938874, 0.754639896102554, 0.652017220865318,
216-
"contcor1", "<unicode>", 0, "contcor2", 0.06513006081573, 10.0110027950081
217-
))
211+
list(-0.475862350312371, 0.11058551725881, -0.136980447123533, "contcor2",
212+
"<unicode>", 0.309092736100577, "contNormal", 0.1346738091268,
213+
-1.01712759156134, 0.0761400418471621, 0.67144328199062, 0.257757843176866,
214+
"contcor1", "<unicode>", 0.0602005168476014, "contNormal", 0.137154686851546,
215+
1.87932216604351, 0.481651772564286, 0.75463988878285, 0.652017220865318,
216+
"contcor1", "<unicode>", 0, "contcor2", 0.0654581731453709,
217+
9.960822148478))
218218
})
219219

220220
test_that("Total effects table results match", {
221221
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_tot"]][["data"]]
222222
jaspTools::expect_equal_tables(table,
223-
list(-0.00126714302930483, 0.440665080716848, 0.168444232730491, "contcor1",
224-
"<unicode>", 0.102761008345243, "contNormal", 0.103237850067971,
225-
1.63161314013793))
223+
list(-0.00126713143815475, 0.440665080659029, 0.168444232730491, "contcor1",
224+
"<unicode>", 0.102761008340492, "contNormal", 0.103237850066545,
225+
1.63161314016047))
226226
})
227227

228228

@@ -247,35 +247,35 @@ results <- jaspTools::runAnalysis("MediationAnalysis", "test.csv", options, make
247247
test_that("Direct effects table results match", {
248248
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_dir"]][["data"]]
249249
jaspTools::expect_equal_tables(table,
250-
list(0.00203607928291166, 0.515217977105027, 0.246415337256947, "contcor1",
251-
"<unicode>", 0.0454269308884425, "contNormal", 0.123165817830769,
252-
2.0006795846192))
250+
list(0.00203609861592261, 0.515217972956754, 0.246415337277754, "contcor1",
251+
"<unicode>", 0.0465192566969286, "contNormal", 0.123786300663823,
252+
1.99065111370413))
253253
})
254254

255255
test_that("Indirect effects table results match", {
256256
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_ind"]][["data"]]
257257
jaspTools::expect_equal_tables(table,
258-
list(-0.285927353530278, 0.072679544829816, -0.085383409360225, "contcor2",
259-
"<unicode>", "<unicode>", 0.323289823674984, 0.086444958200602,
260-
"contcor1", "contNormal", -0.987719945009244))
258+
list(-0.285927353547018, 0.0726795446582816, -0.0853834093674345, "contcor2",
259+
"<unicode>", "<unicode>", 0.325721157816279, 0.0868804491259142,
260+
"contcor1", "contNormal", -0.982768968467117))
261261
})
262262

263263
test_that("Path coefficients table results match", {
264264
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_path"]][["data"]]
265265
jaspTools::expect_equal_tables(table,
266-
list(-0.423032428335729, 0.125618203679588, -0.129957536543631, "contcor2",
267-
"<unicode>", 0.299640536185824, "contNormal", 0.12529595637462,
268-
-1.03720455395283, 0.00203607928291166, 0.515217977105027, 0.246415337256947,
269-
"contcor1", "<unicode>", 0.0454269308884425, "contNormal", 0.123165817830769,
270-
2.0006795846192, 0.514802944243485, 0.794776932027742, 0.657010063679986,
271-
"contcor1", "<unicode>", 0, "contcor2", 0.0623901955114432,
272-
10.5306620422352))
266+
list(-0.42303242765298, 0.125618203587476, -0.129957536548202, "contcor2",
267+
"<unicode>", 0.302069524845541, "contNormal", 0.125927170167018,
268+
-1.0320055344358, 0.00203609861592261, 0.515217972956754, 0.246415337277754,
269+
"contcor1", "<unicode>", 0.0465192566969286, "contNormal", 0.123786300663823,
270+
1.99065111370413, 0.514802945031706, 0.794776935427497, 0.657010063712354,
271+
"contcor1", "<unicode>", 0, "contcor2", 0.0627045055841268,
272+
10.4778764714265))
273273
})
274274

275275
test_that("Total effects table results match", {
276276
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_parest"]][["collection"]][["modelContainer_parest_tot"]][["data"]]
277277
jaspTools::expect_equal_tables(table,
278-
list(-0.0364757008466789, 0.347861388237319, 0.161031927896722, "contcor1",
279-
"<unicode>", 0.0988448047762278, "contNormal", 0.0975667259740126,
280-
1.65047997961533))
278+
list(-0.0364756940559679, 0.347861392970991, 0.161031927910319, "contcor1",
279+
"<unicode>", 0.100547140107636, "contNormal", 0.0980582478184411,
280+
1.6422068667643))
281281
})

tests/testthat/test-sem.R

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -626,12 +626,12 @@ test_that("Residual covariances table results match", {
626626
test_that("Regression coefficients table results match", {
627627
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_params"]][["collection"]][["modelContainer_params_reg"]][["data"]]
628628
jaspTools::expect_equal_tables(table,
629-
list(0.268681455197478, 0.452255911056787, 0.355178159312481, "x1",
630-
1.14885878588211e-12, "x2", 0.0499449599194705, 7.1113914173754,
631-
-0.0227477243021426, 0.150803629695307, 0.0779182588187377,
632-
"x1", 0.0916339727882085, "x3", 0.046191827943223, 1.68684077440086,
633-
-0.000464738405957426, 0.0538034631716805, 0.0306885890333795,
634-
"x1", 0.022389186917765, "y1", 0.0134381019141957, 2.28369967941387
629+
list(0.268681455197478, 0.452255911056786, 0.355178159312481, "x1",
630+
1.48658862997308e-12, "x2", 0.0501965734037228, 7.07574512020654,
631+
-0.0227477243021424, 0.150803629695307, 0.0779182588187374,
632+
"x1", 0.0932718899905223, "x3", 0.0464245338299794, 1.67838537925006,
633+
-0.000464738405957442, 0.0538034631716805, 0.0306885890333796,
634+
"x1", 0.0230712646597004, "y1", 0.0135058006046709, 2.27225248851713
635635
))
636636
})
637637

@@ -650,8 +650,8 @@ test_that("Total effects table results match", {
650650
test_that("Residual variances table results match", {
651651
table <- results[["results"]][["modelContainer"]][["collection"]][["modelContainer_params"]][["collection"]][["modelContainer_params_var"]][["data"]]
652652
jaspTools::expect_equal_tables(table,
653-
list(0.0692094432457097, 0.123114077566912, "x1", 0.0973808537831692,
654-
"", "x1", 1.02584607475364e-13, 0.0130929931392748, 7.43763116250766,
653+
list(0.0692094432457098, 0.123114077566911, "x1", 0.0973808537831693,
654+
"", "x1", 1.35891298214119e-13, 0.013158953231437, 7.40034956203999,
655655
2.25167664969696, 2.25167664969696, "x2", 2.25167664969696,
656656
"", "x2", "", 0, "", 1.949678538072, 1.949678538072, "x3", 1.949678538072,
657657
"", "x3", "", 0, "", 6.78685155555555, 6.78685155555555, "y1",

0 commit comments

Comments
 (0)