Skip to content

Commit e6f0525

Browse files
committed
Refactor syntax creation for indirect paths with moderators
1 parent 81b5b67 commit e6f0525

File tree

1 file changed

+71
-31
lines changed

1 file changed

+71
-31
lines changed

R/classicProcess.R

Lines changed: 71 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -958,42 +958,33 @@ ClassicProcess <- function(jaspResults, dataset = NULL, options) {
958958
return(modOut)
959959
}
960960

961-
.procMedEffectsSyntaxModPars <- function(pathEdge, sourceNode, contrFacVars, graph, modProbes) {
961+
.procMedEffectsSyntaxModPars <- function(pathEdge, sourceNode, contrFacVars, graph) {
962962
# Get moderator parameters for two-way interactions
963963
modPars <- lapply(pathEdge$modVars[[1]], function(v) {
964964
# Get edge for two way interaction between X and M
965965
twoWayEdge <- igraph::E(graph)[paste(sourceNode, v, sep = "__") %--% pathEdge$target]$parName
966966

967-
# Concatenate two way edge parName with moderator probes
968-
return(apply(expand.grid(
969-
twoWayEdge,
970-
format(modProbes[[v]], digits = 3)
971-
), 1, paste, collapse = "*"))
967+
# Concatenate two way edge parName with moderator
968+
return(paste(twoWayEdge, v, sep = "*"))
972969
})
973970

974971
# Concatenate dummy variables for factor moderators
975972
modPars <- .procMedEffectsSyntaxMergeFacMods(pathEdge$modVars[[1]], contrFacVars, modPars, sep = " + ")
976973

977-
# Get all possible combinations of probes from different moderators
978-
modPars <- apply(expand.grid(modPars), 1, paste, collapse = " + ")
979-
980974
# Get name of potential three-way interaction
981975
threeWayInt <- paste(c(pathEdge$source, pathEdge$modVars[[1]]), collapse = "__")
982976

983977
if (length(pathEdge$modVars[[1]]) > 1 && threeWayInt %in% igraph::E(graph)$source) { # If three-way int
984978
# Get edge of three way interaction X x M1 x M2
985979
threeWayEdge <- igraph::E(graph)[threeWayInt %--% pathEdge$target]
986-
# Combine three way int parName with moderator probes
980+
# Combine three way int parName with moderator
987981
threeWayModPars <- paste(
988982
threeWayEdge$parName,
989-
apply(
990-
expand.grid(lapply(pathEdge$modVars[[1]], function(v) format(modProbes[[v]], digits = 3))),
991-
1, paste, collapse = "*"
992-
),
983+
paste(pathEdge$modVars[[1]], collapse = "*"),
993984
sep = "*"
994985
)
995-
# Add to previous moderator probes
996-
modPars <- paste(modPars, threeWayModPars, sep = "+")
986+
# Add to previous moderator terms
987+
modPars <- append(modPars, threeWayModPars)
997988
}
998989
return(modPars)
999990
}
@@ -1067,8 +1058,11 @@ ClassicProcess <- function(jaspResults, dataset = NULL, options) {
10671058
sourceFacVars <- numeric(0)
10681059
}
10691060

1061+
rhs <- c()
1062+
uniqueMods <- c()
1063+
10701064
# Right hand side of lavaan syntax
1071-
rhs <- lapply(2:length(path), function(i) {
1065+
for (i in 2:length(path)) {
10721066
# Get edge from path[-1] to path[i]
10731067
if (any(sourceInContrFacVars) && names(path)[i-1] %in% sourceFacVars) {
10741068
# Get all vars with factor levels as source nodes
@@ -1081,24 +1075,70 @@ ClassicProcess <- function(jaspResults, dataset = NULL, options) {
10811075
# Edge from previous node to current node
10821076
pathEdge <- igraph::E(graph)[sourceNode %--% names(path)[i]]
10831077

1078+
modVars <- unlist(pathEdge$modVars)
1079+
10841080
# If no moderators on edge, return only parName
1085-
if(any(is.na(unlist(pathEdge$modVars)))) return(pathEdge$parName)
1081+
if(any(is.na(modVars))) {
1082+
pathEdgeRhs <- pathEdge$parName
10861083

1087-
# Get pars from moderators
1088-
modPars <- .procMedEffectsSyntaxModPars(pathEdge, sourceNode, contrFacVars, graph, modProbes)
1089-
1090-
# If indirect path add parentheses
1091-
if (i > 1) {
1092-
return(paste0("(", pathEdge$parName, " + ", modPars, ")"))
1084+
if (length(rhs) > 0) {
1085+
# Multiply effects on indirect paths
1086+
rhs <- paste(rhs, pathEdgeRhs, sep = "*")
1087+
} else {
1088+
rhs <- pathEdgeRhs
1089+
}
1090+
} else {
1091+
# Get pars from moderators
1092+
modPars <- .procMedEffectsSyntaxModPars(pathEdge, sourceNode, contrFacVars, graph)
1093+
1094+
# Get sum of moderator terms
1095+
modPars <- .doCallPaste(modPars, sep = " + ")
1096+
1097+
# If indirect path add parentheses
1098+
if (i > 1) {
1099+
pathEdgeRhs <- paste0("(", pathEdge$parName, " + ", unlist(modPars), ")")
1100+
} else {
1101+
pathEdgeRhs <- paste(pathEdge$parName, unlist(modPars), sep = " + ")
1102+
}
1103+
1104+
if (length(rhs) > 0) {
1105+
# Get all possible combinations with new moderators
1106+
if (all(!modVars %in% uniqueMods)) {
1107+
rhs <- apply(expand.grid(rhs, pathEdgeRhs), 1, paste, collapse = "*")
1108+
} else {
1109+
rhs <- paste(rhs, pathEdgeRhs, sep = "*")
1110+
uniqueMods <- c(uniqueMods, modVars)
1111+
}
1112+
} else {
1113+
rhs <- pathEdgeRhs
1114+
}
10931115
}
1094-
# Concanenate path edge parName with moderator probes
1095-
return(paste(pathEdge$parName, modPars, sep = " + "))
1096-
})
1097-
1098-
# If indirect paths, multiply their steps
1099-
rhs <- .doCallPaste(rhs, sep = "*")
1116+
}
11001117

1101-
return(rhs)
1118+
# Substitute moderator variables with probe values
1119+
rhsProbes <- c()
1120+
1121+
for (i in 1:length(rhs)) { # Path edges
1122+
# Get moderators on path
1123+
modInPath <- sapply(names(modProbes), function(v) grepl(v, rhs[i]))
1124+
if (any(modInPath)) {
1125+
modGrid <- expand.grid(modProbes[modInPath])
1126+
pathEdgeRhsProbes <- c()
1127+
for (j in 1:nrow(modGrid)) { # Probe combinations
1128+
rowRhs <- rhs[i]
1129+
for (p in 1:ncol(modGrid)) { # Moderator vars
1130+
# Subsitute variables with probe values
1131+
rowRhs <- gsub(colnames(modGrid)[p], format(modGrid[j, p], digits = 3), rowRhs)
1132+
}
1133+
pathEdgeRhsProbes <- c(pathEdgeRhsProbes, rowRhs)
1134+
}
1135+
} else {
1136+
pathEdgeRhsProbes <- rhs[i]
1137+
}
1138+
rhsProbes <- c(rhsProbes, pathEdgeRhsProbes)
1139+
}
1140+
1141+
return(rhsProbes)
11021142
}
11031143

11041144
.procMedEffectsSyntaxSinglePath <- function(path, graph, modProbes, contrasts) {

0 commit comments

Comments
 (0)