0
$\begingroup$

I'm using the "std2" option for tab_model(), which according to the documentation follows "Gelman's (2008) suggestion, rescaling the estimates by dividing them by two standard deviations instead of just one." That paper is here:

http://www.stat.columbia.edu/~gelman/research/published/standardizing7.pdf

Without a log term in a model I get what I expect for standardized beta based on this, matching the "Std. Beta" column in the tab_model() result.

library(sjPlot)

model = lm(Petal.Length ~ Petal.Width*Sepal.Width*Sepal.Length, data = iris)
tab_model(model, show.std = "std2")

iris2 = iris
iris2$Sepal.Length = (iris2$Sepal.Length - mean(iris2$Sepal.Length))/(2*sd(iris2$Sepal.Length))
iris2$Sepal.Width = (iris2$Sepal.Width - mean(iris2$Sepal.Width))/(2*sd(iris2$Sepal.Width))
iris2$Petal.Width = (iris2$Petal.Width - mean(iris2$Petal.Width))/(2*sd(iris2$Petal.Width))

model2 = lm(Petal.Length ~ Petal.Width*Sepal.Width*Sepal.Length, data = iris2)
summary(model2)

0.5/sd(iris2$Petal.Length)*model2$coefficients[2]
0.5/sd(iris2$Petal.Length)*model2$coefficients[3]
0.5/sd(iris2$Petal.Length)*model2$coefficients[4]

The Gelman paper has a small part about log terms:

"More challenging cases arise in which some inputs have been log transformed and others are not. We have no general solution here, but we would start by centering and rescaling the variables that have not been log transformed. It might also make sense to rescale the variables after the log transformation—for example, in Figure 1, if income had been coded as ‘log (income in dollars),’ we might still consider transforming it."

However, with a log term (I know this doesn't work well for this iris example but this is just for simple reproducibility), I can no longer reproduce the std. beta coefficients based on this logic as I understand it.

model_log = lm(Petal.Length ~ log(Petal.Width)*Sepal.Width*Sepal.Length, data = iris)
tab_model(model_log, show.std = "std2")

iris2$Petal.Width = log(iris$Petal.Width)
iris2$Petal.Width = (iris2$Petal.Width - mean(iris2$Petal.Width))/(2*sd(iris2$Petal.Width))

model_log2 = lm(Petal.Length ~ Petal.Width*Sepal.Width*Sepal.Length, data = iris2)
summary(model_log2)

0.5/sd(iris2$Petal.Length)*model_log2$coefficients[2]
0.5/sd(iris2$Petal.Length)*model_log2$coefficients[3]
0.5/sd(iris2$Petal.Length)*model_log2$coefficients[4]
```
$\endgroup$

1 Answer 1

1
$\begingroup$

When you (or at least I) run this code the following message is shown:

Formula contains log- or sqrt-terms. See help("standardize") for how such terms are standardized.

Checking ?datawizard::standardize.default as suggested elucidates:

When the model's formula contains transformations (e.g. y ~ exp(X)) the transformation effectively takes place after standardization (e.g., exp(scale(X))). Since some transformations are undefined for none positive values, such as log() and sqrt(), the relevel variables are shifted (post standardization) by Z - min(Z) + 1 or Z - min(Z) (respectively).

However, you seem to be quite mistaken in what sjPlot::tab_model does to produce these estimates, which you'll also discover if you try to reproduce the intercept or interaction coefficients using your method in the untransformed model.

Let's start with a probable bug: show.std will only ever perform regular standardization, even if you provide std2 -- you can trivially check that the standardized coefficients won't change if you request them in any way.

Second thing to keep in mind: std.response defaults to TRUE, so if you ask for standardization your response will be standardized too (unless you specifically ask for it not to be).

Combining all of this will let you reproduce the coefficients:

stdize <- function(x) (x - mean(x)) / sd(x)

## Standardize ALL (numeric) variables
iris2 <- dplyr::mutate(iris, dplyr::across(1:4, stdize))

model2 = lm(Petal.Length ~ Petal.Width*Sepal.Width*Sepal.Length, data = iris2)
round(coef(model2), 2)
#> (Intercept)                            0.03
#> Petal.Width                            0.60
#> Sepal.Width                           -0.19
#> Sepal.Length                           0.36
#> Petal.Width:Sepal.Width                0.04
#> Petal.Width:Sepal.Length              -0.05
#> Sepal.Width:Sepal.Length              -0.03
#> Petal.Width:Sepal.Width:Sepal.Length   0.07

As well as the log-transformed results:

## Use previously standardized variables & apply datawizard's log transform
iris3 <- dplyr::mutate(iris2, LPetal.Width = log(Petal.Width - min(Petal.Width) + 1))

model_log2 = lm(Petal.Length ~ LPetal.Width*Sepal.Width*Sepal.Length, data = iris3)
round(coef(model_log2), 2)
#> (Intercept)                            -1.29
#> LPetal.Width                            1.52
#> Sepal.Width                            -0.15
#> Sepal.Length                            0.16
#> LPetal.Width:Sepal.Width                0.00
#> LPetal.Width:Sepal.Length               0.16
#> Sepal.Width:Sepal.Length               -0.13
#> LPetal.Width:Sepal.Width:Sepal.Length   0.14
$\endgroup$
1
  • $\begingroup$ Thanks so much! $\endgroup$
    – abruh
    Commented Mar 28 at 17:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.