Willkommen bei Stats by Randolph. Hier geht es zur Hauptseite mit weiteren Informationen und Inhalten.

Autor:innen dieser Seite: An den Inhalten dieser Seite haben mitgearbeitet: Markus Janczyk und Valentin Koob. Der Inhalt dieser Seite wird in der Lehre in den Studiengängen Psychologie von der AG Psychologische Forschungsmethoden und Kognitive Psychologie an der Universität Bremen verwendet, steht aber allen Interessierten zur Verfügung. Rückmeldungen/Fehler/Vorschläge können gesendet werden an .

Versionshistory:

  • v1.0: erste online-gestellte Version (16.12.2024)

1 Fixed effect Korrelation im Mixed-Model

1.1 Simulation von Daten

Wir beginnen mit der Simulation eines Datensatzes, so wie wir es im Haupttext auch getan haben:

set.seed(1)                 # um die Simulation reproduzierbar zu machen
n_subjects <- 50            # Wieviele Versuchspersonen?
n_items <- 50               # Wieviele Items?
conditions <- c(-0.5, 0.5)  # Wir benennen die beiden Bedingungen mit -0.5 und 0.5
                            # damit der fixed effect nachher den generellen RT Unterschied
                            # zwischen beiden Bedingungen darstellt. Die beiden Bedingungen
                            # könnten auch, wie im Beispiel, kongruente und inkongruente
                            # Zuordnungen von Stimuli zu Tasten sein
sigma_residual <- 20        # SD der Residuen

# fixed effects
beta_0 <- 800               # Intercept
beta_1 <- 100               # Slope

# Varianzkomponenten subject random factor
SD_0s <- 30                 # Intercept
SD_1s <- 200                # Slope
COV_01s <- 4000             # Kovarianz Intercept-Slope

# Varianzkomponenten item random factor
SD_0i <- 20                 # Intercept
SD_1i <- 40                 # Slope
COV_01i <- 200              # Kovarianz Intercept-Slope

# Kovarianzmatrix für subject random factor
CovMatrixSubject <- matrix(c(SD_0s^2, COV_01s,
                             COV_01s, SD_1s^2),
                           nrow = 2, ncol = 2,
                           byrow = TRUE)

# Kovarianzmatrix für item random factor                          
CovMatrixItems <- matrix(c(SD_0i^2, COV_01i,
                           COV_01i, SD_1i^2),
                         nrow = 2, ncol = 2,
                         byrow = TRUE)

# Wir beginnen mit Intercept und Slope für den subject random factor
# simulieren der Daten gemäß der oben spezifizirten Kovarianzmatrix und mit einem
# Erwartungswert 0
randomEffects_Subjects <- MASS::mvrnorm(n = n_subjects,
                                        mu = c(0, 0),
                                        Sigma = CovMatrixSubject,
                                        empirical = TRUE)
# Die simulierten Werte und die Labels für die Versuchspersonen in ein DataFrame...
randomEffects_Subjects <- data.frame(Subject = c(1:n_subjects),
                                     round(randomEffects_Subjects))
# ...und passende Namen geben
names(randomEffects_Subjects)[2:3] <- c("Intercept_Subject", "Slope_Subject")

# Das gleiche machen wir dann für den item random factor
randomEffects_Items <- MASS::mvrnorm(n = n_items,
                                     mu = c(0, 0),
                                     Sigma = CovMatrixItems,
                                     empirical = TRUE)
randomEffects_Items <- data.frame(Item = c(1:n_items),
                                  round(randomEffects_Items))
names(randomEffects_Items)[2:3] <- c("Intercept_Item", "Slope_Item")

# Zunächst legen wir den DataFrame und entsprechende Variablen für Subject, 
# Condition und Item an.
data <- data.frame(Subject = rep(c(1:n_subjects), each = 2*n_items),
                   Condition = c(-0.5, 0.5),
                   Item = rep(rep(c(1:n_items), each = 2), times = n_subjects))
# Dann fügen wir die Werte für die fixed effects hinzu, die ja für alle Versuchspersonen 
# und Item gelten sollen.
data$beta_0 <- beta_0
data$beta_1 <- beta_1                  
# Nun fügen wir dem DataFrame die Intercepts und Slopes des item random factors hinzu...
data <- merge(data, randomEffects_Items,
              by = "Item")
# ...und danach das Ganze noch für den subject random factor.
data <- merge(data, randomEffects_Subjects,
              by = "Subject")
# Als letzter Schritt wird eine Variable mit den Residuen hinzugefügt.
data$residual <- round(rnorm(n = 2*n_subjects*n_items,
                             mean = 0,
                             sd = sigma_residual))

data$RT <- data$beta_0 + data$Condition*data$beta_1 + 
           data$Intercept_Item + data$Condition*data$Slope_Item +
           data$Intercept_Subject + data$Condition*data$Slope_Subject +
           data$residual

Insgesamt sieht der Datensatz nun wie folgt aus:

car::some(data) 

Auf diese Daten wenden wir nun das Mixed-Model an:

M1 <- lmerTest::lmer(RT ~ Condition + (Condition | Subject) + (Condition | Item),
                     data = data)
summary(M1)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: RT ~ Condition + (Condition | Subject) + (Condition | Item)
##    Data: data
## 
## REML criterion at convergence: 45458.2
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.4572 -0.6370 -0.0087  0.6635  3.7238 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr
##  Subject  (Intercept)   915.2   30.25       
##           Condition   39991.2  199.98   0.66
##  Item     (Intercept)   409.9   20.25       
##           Condition    1661.7   40.76   0.24
##  Residual               420.4   20.50       
## Number of obs: 5000, groups:  Subject, 50; Item, 50
## 
## Fixed effects:
##             Estimate Std. Error      df t value Pr(>|t|)    
## (Intercept)  799.849      5.156  85.135 155.123  < 2e-16 ***
## Condition     98.755     28.869  53.040   3.421  0.00121 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##           (Intr)
## Condition 0.565

Wir sehen, dass hier eine Korrelation der fixed effects, also des Intercepts und des Slopes von \(0.565\) ausgegeben wird.

1.2 Bedeutung der fixed effects Korrelation

Diese Korrelation mag auf den ersten Blick komisch erscheinen, da die fixed effects ja einzelne Werte, die auch von summary() ausgegeben werden. Allerdings werden ja auch Standardfehler der fixed effects ausgegeben, was also schon einmal bedeutet, dass die Schätzungen nicht immer konstant sein können. Insbesondere würden wir, und das ist auch der Hauptpunkt der Interpretation bereits, andere Schätzungen der fixed effects erhalten, wenn wir das Mixed-Model an einer anderen Zufallsstichprobe schätzen. Mit jeder solchen weiteren Schätzung erhalten wir aber wieder einen Intercept und einen Slope und die genannte Korrelation ist nichts anderes als die Schätzung der Korrelation dieser Werte, wenn wir immer und immer wieder das Modell auf eine neue Zufallsstichprobe anwenden.

Dies können wir uns anhand einer kleinen Simulation anschauen:

set.seed(1)
# Wir simulieren 100 Datensätze gemäß der Stuktur von M1. Das Resultat ist
# ein DataFrame mit 100 Spalten (für jede Simulation) und 5000 Zeilen (so wie 
# im oben simulierten Ausgangsdatensatz)
simulierteWerte <- simulate(M1,
                            nsim = 100)

# Die folgende Funktion schätzt mit den simulierten Daten (eine Spalte von 
# simulierteWerte) das Mixed-Model
LMM_Auswertung <- function(response)lme4::lmer(response ~ Condition +
                                                 (Condition | Subject) +
                                                 (Condition | Item),
                                               data = data)
# Anwendung der Funktion auf das DataFrame (dauert ein wenig...)
ergebnisse <- lapply(X = sim,
                     FUN = LMM_Auswertung)

# In einem nächsten Schritt extrahieren wir die fixed effects der Mixed-Models...
fixedEffects <- lapply(X = ergebnisse, 
                       FUN = lme4::fixef)
# ...und erstellen daraus eine Matrix  mit den Werten für Intercept und Slope
fixedEffects <- do.call(rbind, fixedEffects)
head(fixedEffects) # Anzeigen der ersten sechs Fälle

Nun können wir die Korrelation der beiden Spalten der Matrix berechnen und wir sehen, dass der erhaltene Wert in die Richtung des oben angezeigten Wertes geht:

cor(fixedEffects[,1], fixedEffects[,2])
## [1] 0.5104151

2 Korrelationen im Allgemeinen Linearen Modell (ALM)

Tatsächlich ist eine Korrelation der fixed effects kein Spezifikum von Mixed-Models, sondern die gleiche Logik gilt auch z.B. bei Standardregressionen im Rahmen des ALM. Typischerweise werden sie dort aber nicht von summary() ausgegeben (und bei Mixed-Models könnte ihre Ausgabe mit corr = FALSE auch unterdrückt werden).

Zur Illustration schauen wir uns die Situation im ALM daher auch kurz an. Wir simulieren daher 100 Werte, die als Prädiktor \(X\) und als Kriterium \(Y\) dienen sollen und mit \(r=0.5\) korreliert sind:

# Kovarianzmatrix die r = 0.5 impliziert
CovMatrix <- matrix(c(40, 20,
                      20, 40),
                    nrow = 2, ncol = 2,
                    byrow = TRUE)

# Simulation der Daten
simulierteDaten <- round(MASS::mvrnorm(n = 100,
                                       mu = c(0, 0),
                                       Sigma = CovMatrix,
                                       empirical = TRUE))
simulierteDaten <- data.frame(simulierteDaten)
names(simulierteDaten) <- c("X","Y")

cor(simulierteDaten$X, simulierteDaten$Y) # tatsächliche Korrelation
## [1] 0.4958333

Im nächsten Schritt führen wir eine ganz normale Regression mit lm() durch und extrahieren den geschätzte Wert der Korrelation der beiden Parameter des Modells, also des Intercepts und des Slopes (oder \(\hat{\beta_0}\) bzw. \(\hat{\beta_1}\)):

ALM_Regression <- lm(Y ~ X,
                     data = simulierteDaten)
cov2cor(vcov(ALM_Regression))[1, 2]    # geschätzte Korrelation der beiden Parameter
## [1] 0.004814349

Die Logik ist nun die gleiche wie oben beschrieben, daher fassen wir uns hier etwas kürzer. Da die Berechnung mit lm() nicht annähernd solange dauert wie im Fall eines Mixed-Models, simulieren wir hier direkt 10000 Datensätze:

set.seed(1)
# Daten (Y) simulieren
simulierteWerte_LM <- simulate(ALM_Regression,
                               nsim = 10000)

# Funktion zur Auswertung
LM_Auswertung <- function(response)lm(response ~ X,
                                               data = simulierteDaten)
ergebnisse <- lapply(X = simulierteWerte_LM,
                     FUN = LM_Auswertung)

# Koeffizienten extrahieren...
Koeffizienten <- lapply(X = ergebnisse, 
                        FUN = coef)
# ...und in eine Matrix packen
Koeffizienten <- do.call(rbind, Koeffizienten)
head(Koeffizienten)
##       (Intercept)         X
## sim_1   0.5705466 0.5809363
## sim_2  -0.2455490 0.4622317
## sim_3   0.1293851 0.5008570
## sim_4   0.2495444 0.4575279
## sim_5  -0.2529207 0.4613596
## sim_6  -0.2808386 0.5250193

Nun können wir uns die Korrelation ausrechnen und sehen, dass die simulierte Korrelation in die Richtung der vorab aus dem Modell extrahierten Schätzung geht:, also quasi keine Korrelation der Parameter vorliegt:

cor(Koeffizienten[,1], Koeffizienten[,2])
## [1] -0.00078855