# Appendix to: Common Practice (misuse of) Moderation in Regression

## Simulate Data

We’ll simulate a tri-variate data set, with two uncorrelated variables that are correlated to a third variable. To start, all variables will be centered at 0 (mu) and scaled to 1 (diagonal of Sigma):

library(tidyverse)
Sigma <- matrix(c(1.0, 0.6, 0.6,
0.6, 1.0, 0.0,
0.6, 0.0, 1.0),
nrow = 3)
data <- MASS::mvrnorm(n = 1000,
mu = rep(0,3),
Sigma = Sigma,
empirical = T) %>% as.data.frame()

Let’s re scale V2 to increase it’s slope when predicting V1:

data <- data %>%
mutate(V2 = 5*V2+10)

Lets look at the correlation matrix (should be the same as Sigma):

knitr::kable(cor(data))
V1 V2 V3
V1 1.0 0.6 0.6
V2 0.6 1.0 0.0
V3 0.6 0.0 1.0

and the covariance matrix (should only be different in the scale of V2):

knitr::kable(cov(data))
V1 V2 V3
V1 1.0 3 0.6
V2 3.0 25 0.0
V3 0.6 0 1.0

# Fit lavaan model

library(lavaan)
my_model <- '
V1 ~ a*V2 + b*V3
diff := a - b
'
fit <- sem(my_model, data = data)

If diff is computed on the standardized coefficients, we expect it to be 0.
If diff is computed on the unstandardized coefficients, we expect it to not 0.

summary(fit, standardized = T)
## lavaan 0.6-5 ended normally after 13 iterations
##
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of free parameters                          3
##
##   Number of observations                          1000
##
## Model Test User Model:
##
##   Test statistic                                 0.000
##   Degrees of freedom                                 0
##
## Parameter Estimates:
##
##   Information                                 Expected
##   Information saturated (h1) model          Structured
##   Standard errors                             Standard
##
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   V1 ~
##     V2         (a)    0.120    0.003   35.857    0.000    0.120    0.600
##     V3         (b)    0.600    0.017   35.857    0.000    0.600    0.600
##
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .V1                0.280    0.013   22.361    0.000    0.280    0.280
##
## Defined Parameters:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##     diff             -0.480    0.017  -28.128    0.000   -0.480    0.000

We can see that the Estimate of diff is non-zero, implying that it was computed on the non-standardized coefficients. BUT we also see that the Std.all of diff is 0, implying that it was computed on the standardized coefficients.
parameterEstimates(fit)[7,] %>% knitr::kable()
standardizedSolution(fit)[7,] %>% knitr::kable()
We can see that we get two different $$z$$-tests, depending on the type of estimates we get. It seems that the test results returned from summary() are based on the standardizedSolution() function, and thus based on the unstandardized results.