\(~\)

Update: This function has migrated to the rempsyc package (https://github.com/rempsyc/rempsyc).

Let’s first load the demo data. This data set comes with base R (meaning you have it too and can directly type this command into your R console).

head(mtcars)
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

Load the rempsyc package:

library(rempsyc)

Note: If you haven’t installed this package yet, you will need to install it via the following command: devtools::install_github("rempsyc/rempsyc"). Package devtools is necessary for this command. If you haven’t installed devtools yet, install it via install.packages("devtools").

\(~\)

Simple moderation

nice_mod(data = mtcars,
         response = "mpg",
         predictor = "gear",
         moderator = "wt") -> moderations
moderations
##   Dependent Variable Predictor df         b          t          p         sr2
## 1                mpg      gear 28  5.615951  1.9437108 0.06204275 0.028488305
## 2                mpg        wt 28  1.403861  0.4301493 0.67037970 0.001395217
## 3                mpg   gear:wt 28 -1.966931 -2.1551077 0.03989970 0.035022025

If we want it to look nice

(my_table <- nice_table(moderations, highlight = TRUE))

Save table to Word

Let’s save it to word for use in a publication (optional).

save_as_docx(my_table, path = "D:/R treasures/moderations.docx")

Note: The sr2 (semi-partial correlation squared, also known as delta square) allows us to quantify the unique contribution (proportion of variance explained) of an independent variable on the dependent variable, over and above the other variables in the model. sr2 is often considered a better indicator of the practical relevance of a variable.

Simple slopes

Let’s extract the simple slopes now, including the sr2.

nice_slopes(data = mtcars,
            response = "mpg",
            predictor = "gear",
            moderator = "wt") -> slopes
slopes
##   Dependent Variable Predictor (+/-1 SD) df        b        t          p
## 1                mpg       gear (LOW-wt) 28 7.540509 2.010656 0.05408136
## 2                mpg      gear (MEAN-wt) 28 5.615951 1.943711 0.06204275
## 3                mpg      gear (HIGH-wt) 28 3.691393 1.795568 0.08336403
##          sr2
## 1 0.03048448
## 2 0.02848830
## 3 0.02431123
nice_table(slopes, highlight = TRUE)

In this specific case, the interaction is significant but none of the simple slopes. This means that although the two slopes are significantly different from each other, taken individually, the slopes aren’t significantly different from a straight line.

The neat thing is that you can add as many dependent variables at once as you want.

# Moderations
nice_mod(data = mtcars,
         response = c("mpg", "disp", "hp"),
         predictor = "gear",
         moderator = "wt") -> moderations
moderations
##   Model Number Dependent Variable Predictor df          b          t          p
## 1            1                mpg      gear 28   5.615951  1.9437108 0.06204275
## 2            1                mpg        wt 28   1.403861  0.4301493 0.67037970
## 3            1                mpg   gear:wt 28  -1.966931 -2.1551077 0.03989970
## 4            2               disp      gear 28  35.797623  0.6121820 0.54535707
## 5            2               disp        wt 28 160.930043  2.4364098 0.02144867
## 6            2               disp   gear:wt 28 -15.037022 -0.8140664 0.42247646
## 7            3                 hp      gear 28  -7.461189 -0.1554963 0.87754563
## 8            3                 hp        wt 28  11.253239  0.2076235 0.83702568
## 9            3                 hp   gear:wt 28  14.539586  0.9592587 0.34563902
##            sr2
## 1 0.0284883047
## 2 0.0013952173
## 3 0.0350220247
## 4 0.0027372180
## 5 0.0433559718
## 6 0.0048402513
## 7 0.0003885555
## 8 0.0006927326
## 9 0.0147871391
nice_table(moderations, highlight = TRUE)
# Simple slopes
nice_slopes(data = mtcars,
            response = c("mpg", "disp", "hp"),
            predictor = "gear",
            moderator = "wt") -> slopes
slopes
##   Model Number Dependent Variable Predictor (+/-1 SD) df          b          t
## 1            1                mpg       gear (LOW-wt) 28   7.540509  2.0106560
## 2            1                mpg      gear (MEAN-wt) 28   5.615951  1.9437108
## 3            1                mpg      gear (HIGH-wt) 28   3.691393  1.7955678
## 4            2               disp       gear (LOW-wt) 28  50.510710  0.6654856
## 5            2               disp      gear (MEAN-wt) 28  35.797623  0.6121820
## 6            2               disp      gear (HIGH-wt) 28  21.084536  0.5067498
## 7            3                 hp       gear (LOW-wt) 28 -21.687555 -0.3482182
## 8            3                 hp      gear (MEAN-wt) 28  -7.461189 -0.1554963
## 9            3                 hp      gear (HIGH-wt) 28   6.765177  0.1981502
##            p          sr2
## 1 0.05408136 0.0304844847
## 2 0.06204275 0.0284883047
## 3 0.08336403 0.0243112307
## 4 0.51118526 0.0032346367
## 5 0.54535707 0.0027372180
## 6 0.61629796 0.0018755795
## 7 0.73028083 0.0019485684
## 8 0.87754563 0.0003885555
## 9 0.84435922 0.0006309595
nice_table(slopes, highlight = TRUE)

Pro tip: Both the nice_mod() and nice_slopes() functions take the same argument, so you can just copy-paste the first and change the function call to save time!

Covariates

You can also have more complicated models, like with added covariates.

# Moderations
nice_mod(data = mtcars,
         response = "mpg",
         predictor = "gear",
         moderator = "wt",
         covariates = c("am", "vs")) -> moderations
moderations
##   Dependent Variable Predictor df         b          t           p         sr2
## 1                mpg      gear 26  5.840594  2.0773482 0.047786602 0.024922116
## 2                mpg        wt 26  3.433057  1.1692031 0.252929701 0.007894893
## 3                mpg        am 26  1.578465  0.8569286 0.399314133 0.004240876
## 4                mpg        vs 26  3.817509  3.2441426 0.003228614 0.060780767
## 5                mpg   gear:wt 26 -2.096457 -2.5615471 0.016567730 0.037894048
nice_table(moderations, highlight = TRUE)
# Simple slopes
nice_slopes(data = mtcars,
            response = "mpg",
            predictor = "gear",
            moderator = "wt",
            covariates = c("am", "vs")) -> slopes
nice_table(slopes, highlight = TRUE)

In this case, the fist and middle rows are significant, which means that those who are low on the wt variable (below one standard deviation) or those who are average on wt have significantly higher mpg the higher their gear. We can plot this in the more traditional way:

# First need to define model for plot function
mod <- lm(mpg ~ gear * wt + am + vs, data = mtcars)

# Plot the model
library(interactions)
interact_plot(mod, pred = "gear", modx = "wt", interval = TRUE)

Note: If you haven’t installed this package yet, you will need to install it via the following command: install.packages(interactions). Furthermore, know that this plot can be heavily customized with available arguments for publication purposes, but I won’t be going into these details here.

Three-way interaction

Let’s make a three-way interaction for example. Note that for the simple slopes, for now, the second moderator needs to be a dichotomic variable (and the first moderator a continuous variable).

# Moderations
nice_mod(response = "mpg",
         predictor = "gear",
         moderator = "wt",
         moderator2 = "am",
         data = mtcars) -> moderations
moderations
##   Dependent Variable  Predictor df         b         t          p        sr2
## 1                mpg       gear 24  52.97009  1.831564 0.07945785 0.01660219
## 2                mpg         wt 24  42.12157  1.603869 0.12182331 0.01273090
## 3                mpg         am 24 202.38995  2.216085 0.03641826 0.02430490
## 4                mpg    gear:wt 24 -15.09281 -1.729114 0.09663310 0.01479682
## 5                mpg    gear:am 24 -58.83248 -1.992346 0.05782588 0.01964494
## 6                mpg      wt:am 24 -58.67147 -2.053052 0.05112221 0.02086032
## 7                mpg gear:wt:am 24  16.79352  1.854357 0.07601677 0.01701798
nice_table(moderations, highlight = TRUE)
# Simple slopes
nice_slopes(data = mtcars,
            response = "mpg",
            predictor = "gear",
            moderator = "wt",
            moderator2 = "am") -> slopes
slopes
##   Dependent Variable am Predictor (+/-1 SD) df         b          t          p
## 1                mpg  0       gear (LOW-wt) 24 67.737763  1.8085806 0.08306317
## 2                mpg  0      gear (MEAN-wt) 24 52.970093  1.8315641 0.07945785
## 3                mpg  0      gear (HIGH-wt) 24 38.202424  1.8731910 0.07327171
## 4                mpg  1       gear (LOW-wt) 24 -7.526458 -0.9092225 0.37227347
## 5                mpg  1      gear (MEAN-wt) 24 -5.862384 -0.9829465 0.33543976
## 6                mpg  1      gear (HIGH-wt) 24 -4.198309 -1.1312335 0.26913442
##           sr2
## 1 0.016188137
## 2 0.016602191
## 3 0.017365419
## 4 0.004091302
## 5 0.004781684
## 6 0.006333236
nice_table(slopes, highlight = TRUE)

Complex models

For more complicated models not supported by nice_mod, one can define the model in the traditional way and feed it to nice_lm instead. It supports multiple lm models as well.

model1 <- lm(mpg ~ cyl + wt * hp, mtcars)
model2 <- lm(qsec ~ disp + drat * carb, mtcars)
my.models <- list(model1, model2)
(nicelm.table <- nice_lm(my.models))
##   Model Number Dependent Variable Predictor df            b          t
## 1            1                mpg       cyl 27 -0.365239089 -0.7180977
## 2            1                mpg        wt 27 -7.627489287 -5.0146028
## 3            1                mpg        hp 27 -0.108394273 -3.6404181
## 4            1                mpg     wt:hp 27  0.025836594  3.2329593
## 5            2               qsec      disp 27 -0.006222635 -1.9746464
## 6            2               qsec      drat 27  0.227692395  0.1968842
## 7            2               qsec      carb 27  1.154106215  0.7179431
## 8            2               qsec drat:carb 27 -0.477539959 -1.0825727
##               p          sr2
## 1 0.47886516037 0.0021596150
## 2 0.00002928375 0.1053130854
## 3 0.00113640283 0.0555024045
## 4 0.00322175341 0.0437733438
## 5 0.05861684483 0.0702566891
## 6 0.84539274511 0.0006984424
## 7 0.47895897531 0.0092872897
## 8 0.28857203297 0.0211165564
nice_table(nicelm.table, highlight = TRUE)

The same applies to simple slopes, this time we use the nice_lm_slopes function. It supports multiple lm models as well, but the predictor and moderator need to be the same for these models (the dependent variable can change).

model1 <- lm(mpg ~ gear * wt, mtcars)
model2 <- lm(disp ~ gear * wt, mtcars)
my.models <- list(model1, model2)
(lmslopes.table <- nice_lm_slopes(my.models, predictor = "gear", moderator = "wt"))
##   Model Number Dependent Variable Predictor (+/-1 SD) df         b         t
## 1            1                mpg       gear (LOW-wt) 28  7.540509 2.0106560
## 2            1                mpg      gear (MEAN-wt) 28  5.615951 1.9437108
## 3            1                mpg      gear (HIGH-wt) 28  3.691393 1.7955678
## 4            2               disp       gear (LOW-wt) 28 50.510710 0.6654856
## 5            2               disp      gear (MEAN-wt) 28 35.797623 0.6121820
## 6            2               disp      gear (HIGH-wt) 28 21.084536 0.5067498
##            p         sr2
## 1 0.05408136 0.030484485
## 2 0.06204275 0.028488305
## 3 0.08336403 0.024311231
## 4 0.51118526 0.003234637
## 5 0.54535707 0.002737218
## 6 0.61629796 0.001875579
nice_table(lmslopes.table, highlight = TRUE)

\(~\)

\(~\)

Thanks for checking in

Make sure to check out this page again if you use the code after a time or if you encounter errors, as I periodically update or improve the code. Feel free to contact me for comments, questions, or requests to improve this function at https://github.com/rempsyc/rempsyc/issues.

\(~\)

\(~\)

\(~\)

\(~\)

\(~\)


Updated 2022-04-20 (added demos of nice_lm and nice_lm_slopes functions)

\(~\)

\(~\)

\(~\)

\(~\)

\(~\)

\(~\)