Skip to contents

This vignette describes how to run power analyses for 2-way interactions that include covariates. It assumes you are already familiar with power analyses for 2-way interactions. If you aren’t, check out our tutorial paper or the main vignette.

Introduction

A two-way interaction analysis with two covariates (for example, but any number is allowable) take the form:

\[ Y \sim \beta_0 + X_1\beta_1 + X_2\beta_2 + X_1X_2\beta_3+ C_1\beta_5 + C_2\beta_6 + C_1X_1\beta_7 + C_1X_2\beta_8 + C_2X_1\beta_9 + C_2X_2\beta_{10} + \epsilon \]

Where \(C_i\) are the covariates, and \(C_iX_i\) are interactions between the covariates and the main variables of interest. The inclusion of the \(C_iX_i\) terms may surprise some users. However, it is well established that failure to include them can lead to false-positive results, because of omitted variable bias. This can occur not only when \(C_iX_i\) is independent predictor of \(Y\), but also simply when \(cor(X_i,C_i)\) is non-zero (i.e., when a covariate is correlated with either of the main interaction terms). A few relevant citations: Hull et al., 1992, Yzerbyt et al., 2004, Keller, 2014, and blogs: Baranger, and Simonsohn.

Running an analysis

First, the function generate.interaction.cov.input() is used to setup the input correlations for the power analysis. The only input is the number of covariates. This generates a named list. All correlations are by default 0 and all reliabilites are 1.

library(InteractionPoweR)
power.input = generate.interaction.cov.input(c.num = 2) # number of covariates
head(power.input$correlations)
## $r.y.x1
## [1] 0
## 
## $r.y.x2
## [1] 0
## 
## $r.y.c1
## [1] 0
## 
## $r.y.c2
## [1] 0
## 
## $r.y.x1x2
## [1] 0
## 
## $r.y.c1x1
## [1] 0
head(power.input$reliability)
## $rel.y
## [1] 1
## 
## $rel.x1
## [1] 1
## 
## $rel.x2
## [1] 1
## 
## $rel.c1
## [1] 1
## 
## $rel.c2
## [1] 1

Modify the list as-needed for your own power analysis:

power.input$correlations$r.y.x1 = .3
power.input$correlations$r.y.x2 = .2
power.input$correlations$r.y.c1 = .1
power.input$correlations$r.y.c2 = .2
power.input$correlations$r.y.x1x2 = seq(0.01,.1,.01) # inputs can be single values or vectors
power.input$correlations$r.x1.x2 = .2
power.input$correlations$r.c1.c2 = .3
power.input$correlations$r.x1.c1 = .1
power.input$correlations$r.x2.c1 = .1

Now we run the power analysis with the power_interaction_r2_covs() function:

pwr.analysis = power_interaction_r2_covs(cov.input =power.input, # our parameters
                          N = c(1000)
                          )
## Performing 10 analyses
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
pwr.analysis
##           pwr r.y.x1 r.y.x2 r.y.c1 r.y.c2 r.y.x1x2 r.y.c1x1 r.y.c1x2 r.y.c2x1
## 1  0.06378639    0.3    0.2    0.1    0.2     0.01        0        0        0
## 2  0.10625113    0.3    0.2    0.1    0.2     0.02        0        0        0
## 3  0.17927387    0.3    0.2    0.1    0.2     0.03        0        0        0
## 4  0.28210473    0.3    0.2    0.1    0.2     0.04        0        0        0
## 5  0.40826630    0.3    0.2    0.1    0.2     0.05        0        0        0
## 6  0.54510518    0.3    0.2    0.1    0.2     0.06        0        0        0
## 7  0.67680533    0.3    0.2    0.1    0.2     0.07        0        0        0
## 8  0.78938929    0.3    0.2    0.1    0.2     0.08        0        0        0
## 9  0.87489380    0.3    0.2    0.1    0.2     0.09        0        0        0
## 10 0.93259046    0.3    0.2    0.1    0.2     0.10        0        0        0
##    r.y.c2x2 r.x1.x2 r.x1.c1 r.x1.c2 r.x1.c1x2 r.x1.c2x2 r.x2.c1 r.x2.c2
## 1         0     0.2     0.1       0         0         0     0.1       0
## 2         0     0.2     0.1       0         0         0     0.1       0
## 3         0     0.2     0.1       0         0         0     0.1       0
## 4         0     0.2     0.1       0         0         0     0.1       0
## 5         0     0.2     0.1       0         0         0     0.1       0
## 6         0     0.2     0.1       0         0         0     0.1       0
## 7         0     0.2     0.1       0         0         0     0.1       0
## 8         0     0.2     0.1       0         0         0     0.1       0
## 9         0     0.2     0.1       0         0         0     0.1       0
## 10        0     0.2     0.1       0         0         0     0.1       0
##    r.x2.c1x1 r.x2.c2x1 r.c1.c2 r.c1.x1x2 r.c1.c2x1 r.c1.c2x2 r.c2.x1x2
## 1          0         0     0.3         0         0         0         0
## 2          0         0     0.3         0         0         0         0
## 3          0         0     0.3         0         0         0         0
## 4          0         0     0.3         0         0         0         0
## 5          0         0     0.3         0         0         0         0
## 6          0         0     0.3         0         0         0         0
## 7          0         0     0.3         0         0         0         0
## 8          0         0     0.3         0         0         0         0
## 9          0         0     0.3         0         0         0         0
## 10         0         0     0.3         0         0         0         0
##    r.c2.c1x1 r.c2.c1x2 rel.y rel.x1 rel.x2 rel.c1 rel.c2 alpha    N
## 1          0         0     1      1      1      1      1  0.05 1000
## 2          0         0     1      1      1      1      1  0.05 1000
## 3          0         0     1      1      1      1      1  0.05 1000
## 4          0         0     1      1      1      1      1  0.05 1000
## 5          0         0     1      1      1      1      1  0.05 1000
## 6          0         0     1      1      1      1      1  0.05 1000
## 7          0         0     1      1      1      1      1  0.05 1000
## 8          0         0     1      1      1      1      1  0.05 1000
## 9          0         0     1      1      1      1      1  0.05 1000
## 10         0         0     1      1      1      1      1  0.05 1000

As always, we can plot the power curve:

plot_power_curve(power_data = pwr.analysis,x = "r.y.x1x2")

And we can estimate where the power curve intersects some desired level of power:

power_estimate(power_data = pwr.analysis,x = "r.y.x1x2",power_target = 0.8)
## [1] 0.08112818

Even though analytic power analyses are fast, with so many parameters we can easily reach a point where the analysis will take a long time to run. Say for instance we are interested in testing out 10 different values of 4 different parameters - that’s 10,000 power analyses. At that point, it can be helpful to run things in parallel. Parallel analyses can be run using the cl flag. cl=4 is probably a reasonable value for most personal computers.