setwd("C:/Work Files/Collaboration/Andi")
Andi R&R power analysis
I am using two packages to create a simulation in which to test the power of a 2-level model with level-1: students (n=450) and level=2: schools (n=10). The simulated model assumes approximately 45 students per school.
library(simr)
Warning: package 'simr' was built under R version 4.4.2
Loading required package: lme4
Warning: package 'lme4' was built under R version 4.4.2
Loading required package: Matrix
Attaching package: 'simr'
The following object is masked from 'package:lme4':
getData
library(lme4)
library(lmerTest)
Attaching package: 'lmerTest'
The following object is masked from 'package:lme4':
lmer
The following object is masked from 'package:stats':
step
First I am generating a simulated data set that will serve as the population model for the Monte Carlo power simulation. This data set has 1-outcome, 1-student predictor, and 1-school level effect, all of which are on a standard scale ~N(0,1). I chose a moderate student level effect of \(\beta = 0.3\). I can also change the random effect standard deviations to make them narrower or wider depending on how you want to model the precision of the estimates.
set.seed(123) # Reproducibility
# Parameters
<- 450 # Level 1 sample size
n_students <- 10 # Level 2 sample size
n_schools <- n_students / n_schools # Average students per school
students_per_school
# Generate school-level (random intercepts)
<- rep(1:n_schools, each = students_per_school)
school_id
# Level-1 covariates (e.g., student scores)
<- rnorm(n_students, mean = 0, sd = 1) # Predictor
student_covariate
# Fixed effect of student covariate (moderate effect size ~ 0.3)
<- 0.3
beta
# Random effects (school-level variability)
<- rnorm(n_schools, mean = 0, sd = .8)
school_effect <- school_effect[school_id]
random_intercept
# Generate outcome variable (Y)
<- rnorm(n_students, mean = 0, sd = 1) # Residual error
epsilon <- 2 + random_intercept + beta * student_covariate + epsilon
y
# Combine into a data frame
<- data.frame(
data school_id = factor(school_id),
student_covariate = student_covariate,
y = y
)
This block of code provides a summary of the simulated data confirming the population model. The summary(model) output uses the Satterthwaite method for d.f. and the anova output uses the Kenward-Roger adjusted d.f.
# Model: Random intercept for schools
<- lmer(y ~ student_covariate + (1 | school_id), data = data)
model
# Summarize the model
summary(model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: y ~ student_covariate + (1 | school_id)
Data: data
REML criterion at convergence: 1313
Scaled residuals:
Min 1Q Median 3Q Max
-2.66062 -0.65156 0.02398 0.66852 2.70787
Random effects:
Groups Name Variance Std.Dev.
school_id (Intercept) 0.9938 0.9969
Residual 0.9889 0.9944
Number of obs: 450, groups: school_id, 10
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 2.22712 0.31871 8.99964 6.988 6.41e-05 ***
student_covariate 0.27133 0.04827 439.10443 5.621 3.38e-08 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
studnt_cvrt -0.001
anova(model, type=2, ddf = "Kenward-Roger")
Type II Analysis of Variance Table with Kenward-Roger's method
Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
student_covariate 31.24 31.24 1 439.1 31.592 3.386e-08 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
This last block of code uses the coefficients from the above simulated population data to estimate the power across a 1,000 random draws from the population data. There is ample power here
# Extend the model for power simulation
<- extend(model, along = "school_id", n = n_schools)
model_ext
# Power analysis for the random effect at the school level
<- powerSim(model_ext, test = ranef, nsim = 1000) power_results_school
Simulating: | |Simulating: |= |Simulating: |== |Simulating: |=== |Simulating: |==== |Simulating: |===== |Simulating: |====== |Simulating: |======= |Simulating: |======== |Simulating: |========= |Simulating: |========== |Simulating: |=========== |Simulating: |============ |Simulating: |============= |Simulating: |============== |Simulating: |=============== |Simulating: |================ |Simulating: |================= |Simulating: |================== |Simulating: |=================== |Simulating: |==================== |Simulating: |===================== |Simulating: |====================== |Simulating: |======================= |Simulating: |======================== |Simulating: |========================= |Simulating: |========================== |Simulating: |=========================== |Simulating: |============================ |Simulating: |============================= |Simulating: |============================== |Simulating: |=============================== |Simulating: |================================ |Simulating: |================================= |Simulating: |================================== |Simulating: |=================================== |Simulating: |==================================== |Simulating: |===================================== |Simulating: |====================================== |Simulating: |======================================= |Simulating: |======================================== |Simulating: |========================================= |Simulating: |========================================== |Simulating: |=========================================== |Simulating: |============================================ |Simulating: |============================================= |Simulating: |============================================== |Simulating: |=============================================== |Simulating: |================================================ |Simulating: |================================================= |Simulating: |================================================== |Simulating: |=================================================== |Simulating: |==================================================== |Simulating: |===================================================== |Simulating: |====================================================== |Simulating: |======================================================= |Simulating: |======================================================== |Simulating: |========================================================= |Simulating: |========================================================== |Simulating: |=========================================================== |Simulating: |============================================================ |Simulating: |============================================================= |Simulating: |============================================================== |Simulating: |=============================================================== |Simulating: |================================================================ |Simulating: |================================================================= |Simulating: |==================================================================|
Warning in observedPowerWarning(sim): This appears to be an "observed power"
calculation
# Power analysis for the fixed effect of student_covariate
<- powerSim(model_ext, test = fixed("student_covariate"), nsim = 1000) power_results_students
Simulating: | |Simulating: |= |Simulating: |== |Simulating: |=== |Simulating: |==== |Simulating: |===== |Simulating: |====== |Simulating: |======= |Simulating: |======== |Simulating: |========= |Simulating: |========== |Simulating: |=========== |Simulating: |============ |Simulating: |============= |Simulating: |============== |Simulating: |=============== |Simulating: |================ |Simulating: |================= |Simulating: |================== |Simulating: |=================== |Simulating: |==================== |Simulating: |===================== |Simulating: |====================== |Simulating: |======================= |Simulating: |======================== |Simulating: |========================= |Simulating: |========================== |Simulating: |=========================== |Simulating: |============================ |Simulating: |============================= |Simulating: |============================== |Simulating: |=============================== |Simulating: |================================ |Simulating: |================================= |Simulating: |================================== |Simulating: |=================================== |Simulating: |==================================== |Simulating: |===================================== |Simulating: |====================================== |Simulating: |======================================= |Simulating: |======================================== |Simulating: |========================================= |Simulating: |========================================== |Simulating: |=========================================== |Simulating: |============================================ |Simulating: |============================================= |Simulating: |============================================== |Simulating: |=============================================== |Simulating: |================================================ |Simulating: |================================================= |Simulating: |================================================== |Simulating: |=================================================== |Simulating: |==================================================== |Simulating: |===================================================== |Simulating: |====================================================== |Simulating: |======================================================= |Simulating: |======================================================== |Simulating: |========================================================= |Simulating: |========================================================== |Simulating: |=========================================================== |Simulating: |============================================================ |Simulating: |============================================================= |Simulating: |============================================================== |Simulating: |=============================================================== |Simulating: |================================================================ |Simulating: |================================================================= |Simulating: |==================================================================|
Warning in observedPowerWarning(sim): This appears to be an "observed power"
calculation
# Display results
print(power_results_school)
Power [user defined], (95% confidence interval):
0.00% ( 0.00, 0.37)
Test: [user defined function]
Based on 1000 simulations, (0 warnings, 1000 errors)
alpha = 0.05, nrow = 450
Time elapsed: 0 h 0 m 49 s
nb: result might be an observed power calculation
print(power_results_students)
Power for predictor 'student_covariate', (95% confidence interval):
99.90% (99.44, 100.00)
Test: unknown test
Effect size for student_covariate is 0.27
Based on 1000 simulations, (0 warnings, 0 errors)
alpha = 0.05, nrow = 450
Time elapsed: 0 h 1 m 51 s
nb: result might be an observed power calculation