::p_load(lme4, nlme, tidyverse, lmerTest, gridExtra, ggplot2) pacman
1 Modelle mit Level-1-Prädiktoren
In diesem Kapitel behandeln wir Hierarchische Lineare Modelle mit Level-1-Prädiktoren. Aufbau und Systematik der Darstellung orientieren sich am Lehrbuch “Statistik und Forschungsmethoden” von Eid, Gollwitzer, und Schmitt (2017).
Es handelt sich um Modelle mit einer 2-Ebenen-Struktur (Individuen genestet in Gruppen), und zunächst werden nur Modelle ohne jede Prädiktorvariable (Intercept-Only-Modell) sowie Modelle mit ausschliesslich Prädiktorvariablen auf Level 1 (Random-Intercept-Modell und Random-Coefficients-Modell) behandelt.
Laden der in diesem Kapitel benötigten Packages:
1.1 HLM Packages
Zu Beginn ein kurzer Überblick über die beiden Packages, die wir in diesem Kurs für Hierarchische Lineare Modelle benutzen werden.
nlme
Dies ist das ursprüngliche HLM- oder Mixed-Model-Package. Es hat mehr Optionen, insbesondere im Hinblick auf die Struktur der Level-1-Fehler bei Daten mit wiederholten Messungen. Wir verwenden nlme
im Kapitel zu HLM-Modellen mit Messwiederholung. Die Syntax-Struktur wird dort behandelt.
lme4
Dieses modernere HLM-Package ist sehr gut geeignet für “normale” Hierarchische Lineare Modelle mit genesteten Gruppen. Wir verwenden es im Folgenden für die Analysen der Modelle mit Level-1- und Level-2-Prädiktoren.
Die “lme4”-Syntax baut auf der model syntax auf, die wir schon von lm()
kennen. Also:
lm(formula = AbhängigeVariable ~ UnabhängigeVariable, data = dataframe)
Bei der Funktion lmer()
(aus dem Package lme4
) kommt die Spezifizierung der Gruppenvariable hinzu, und welche zufälligen Effekte geschätzt werden sollen. Die Syntax in der Klammer unterscheidet die lmer()
-Syntax von der simplen Syntax der lm()
-Funktion. In der Klammer wird links vom |
spezifiziert, welche zufälligen Effekte geschätzt werden sollen. Rechts des |
steht die Variable, die die Gruppenstruktur (Nestungsstruktur) der Daten definiert.
Eine 1
im linken Teil der Klammer bedeutet, dass random intercepts geschätzt werden sollen. Wenn die Unabhängige Variable (also die Prädiktorvariable) auch links vor dem |
steht, bedeutet dies, dass zusätzlich random slopes geschätzt werden.
Was bedeutet also folgende Syntax?
lmer(data = dataframe, AbhängigeVariable ~ UnabhängigeVariable + (1 | Gruppenvariable))
Antwort: die Abhängige Variable wird von der Unabhängigen Variable vorhergesagt. Gleichzeitig wird der Intercept separat für jede Ausprägung der Gruppenvariable geschätzt bzw. die Varianz der Level-2-Residuen des Intercepts ist ein Parameter des Modells.
Diese Syntax wird später noch erweitert.
1.2 Daten laden und aufbereiten
Wir laden die Daten und speichern sie im Objekt df
(für “data frame”). Wir können das Datenfile direkt aus dem Internet (GitHub) herunterladen:
<- read_csv(
df url("https://raw.githubusercontent.com/methodenlehre/data/master/statistik_IV/salary-data.csv")
)
Beschreibung
Bei diesen Daten handelt es sich um Lohn-Daten von 20 Firmen mit je 30 Angestellten (fiktive, simulierte Daten). Zu jedem Angestellten haben wir Informationen zum Gehalt (salary
, in 1000 CHF), bei welcher Firma die Person angestellt ist (company
), und wie lange die Person schon dort arbeitet (experience
). Ausserdem haben wir noch Informationen darüber, in welchem Sektor (public oder privat) die Firma tätig ist (sector
). Mit dieser Variable beschäftigen wir uns aber erst in Übung 2.
Bevor wir uns die Daten anschauen, müssen company
und sector
noch als Faktoren definiert werden.
<- df |>
df mutate(
company = as.factor(company),
sector = as.factor(sector)
)
Jetzt können wir uns den Daten-Frame anschauen:
# Die Funktion "tail()" gibt uns die letzten 6 rows aus.
tail(df)
# A tibble: 6 × 4
company experience salary sector
<fct> <dbl> <dbl> <fct>
1 Company 20 3.58 6.84 Private
2 Company 20 3.18 7.60 Private
3 Company 20 3.39 5.71 Private
4 Company 20 7.12 10.1 Private
5 Company 20 2.98 6.94 Private
6 Company 20 6.45 9.33 Private
# Die "summary()" Funktion gibt uns deskriptive Statistiken
# zum Datensatz aus.
summary(df)
company experience salary sector
Company 01: 30 Min. : 0.000 Min. : 4.587 Private:300
Company 02: 30 1st Qu.: 4.027 1st Qu.: 7.602 Public :300
Company 03: 30 Median : 5.170 Median : 8.564
Company 04: 30 Mean : 5.190 Mean : 8.738
Company 05: 30 3rd Qu.: 6.402 3rd Qu.: 9.840
Company 06: 30 Max. :10.000 Max. :15.418
(Other) :420
1.3 Intercept-Only-Modell (Modell 1)
In diesem Modell ist keine Prädiktorvariable enthalten, es handelt sich also um eine Art Nullmodell, das nur die Variation des Achsenabschnitts zwischen den Gruppen modelliert. Und in einem Modell ohne Prädiktor beziehen sich die Gruppenabschnitte auf die Gruppenmittelwerte (in diesem Fall der 20 Firmen).
Level-1-Modell: \(\boldsymbol {y_{mi}=\beta_{0i}+\varepsilon_{mi}}\)
Level-2-Modell: \(\boldsymbol {\beta_{0i}=\gamma_{00} + \upsilon_{0i}}\)
Gesamtmodell: \(\boldsymbol {y_{mi} = \gamma_{00} + \upsilon_{0i}+\varepsilon_{mi}}\)
1.3.1 Modell berechnen
# Fitten des Modells und Abspeichern in der Variable intercept.only.model
<- lmer(salary ~ 1 + (1 | company), data = df, REML = TRUE)
intercept.only.model
# Abspeichern von Prädiktionen, die dieses Modell macht.
# In diesem Falle ist dies jeweils der durchschnittliche Lohn jeder Firma
# Die Funktion predict() gibt pro Zeile (in diesem Fall pro Angestelltem)
# eine Prädiktion aus, je nachdem, in welcher Firma die Person angestellt ist.
# Wir speichern diese vorhergesagten Werte, um das Modell später mit "ggplot2"
# zu veranschaulichen.
$intercept.only.preds <- predict(intercept.only.model)
df
# Model output anschauen
summary(intercept.only.model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: salary ~ 1 + (1 | company)
Data: df
REML criterion at convergence: 2158
Scaled residuals:
Min 1Q Median 3Q Max
-2.9816 -0.6506 -0.0494 0.5779 4.2131
Random effects:
Groups Name Variance Std.Dev.
company (Intercept) 0.8512 0.9226
Residual 1.9547 1.3981
Number of obs: 600, groups: company, 20
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 8.7376 0.2141 19.0000 40.82 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Mit der Funktion ranef()
kann man sich die einzelnen Random-Effects (Level-2-Residuen des Intercepts, also die \(\upsilon_{0i}\)) ausgeben lassen:
ranef(intercept.only.model)
$company
(Intercept)
Company 01 0.78965416
Company 02 1.10501807
Company 03 1.92302618
Company 04 -1.13650080
Company 05 0.95354595
Company 06 -0.95893185
Company 07 -0.01014627
Company 08 -0.25484048
Company 09 -0.65131802
Company 10 0.76848590
Company 11 -0.50626620
Company 12 0.94040709
Company 13 -0.74284383
Company 14 -0.97545482
Company 15 -1.16136931
Company 16 -0.09768008
Company 17 0.66196052
Company 18 -0.16811195
Company 19 0.35123926
Company 20 -0.82987351
with conditional variances for "company"
1.3.2 Intraklassenkorrelation
Die Intraklassenkorrelation quantifiziert das Ausmass der „Nicht-Unabhängigkeit” zwischen den Messwerten aufgrund systematischer Level-2-Unterschiede im gemessenen Merkmal. Je grösser der Anteil der Level-2-Varianz (Varianz der Gruppenmittelwerte) an der Gesamtvarianz (Summe der Level-2-Varianz und der Level-1-Varianz), desto grösser sind die Ähnlichkeiten innerhalb der Level-2-Einheiten im Vergleich zu zwischen den Level-2-Einheiten.
Die Intraklassenkorrelation ist definiert als: \(\boldsymbol {\rho = \frac{\sigma^2_{Level-2}}{\sigma^2_{Level-2}+ \sigma^2_{Level-1}}}\)
Die Intraklassenkorrelation erhält man bei Schätzung eines Nullmodells (Intercept-Only-Modell, s.o.), bei dem sowohl die (zufällige) Varianz des Intercepts (in einem Modell ohne Prädiktoren also die Varianz der Mittelwerte der Level-2-Einheiten) als auch die Level-1-Residualvarianz ausgegeben wird.
Wenn die Level-2-Varianz sich nicht überzufällig von 0 unterscheidet, spielen die Ähnlichkeiten/Abhängigkeiten innerhalb der Level-2-Einheiten keine Rolle und ein Mehrebenenmodell ist nicht unbedingt notwendig.
Intraklassenkorrelation: \(\hat{\rho} = \frac{\hat{\sigma}^2_{\upsilon_0}}{\hat{\sigma}^2_{\upsilon_0}+ \hat{\sigma}^2_\varepsilon} = \frac {0.8512}{0.8512+1.9547} = 0.303\)
-> ca. 30 % der Gesamtvarianz sind auf Level-2-(Firmen-)Unterschiede zurückzuführen.
1.3.3 Signifikanztest
Signifikanztest für \(\sigma^2_{\upsilon_0}\): Modellvergleich mit absolutem Nullmodell
Wir kennen nun also die Level-2-Varianz, aber wir haben noch keinen Signifikanztest für diesen Parameter. Diesen erhalten wir über einen Modellvergleich (Likelihood-Ratio-Test) des Intercept-Only-Modells mit einem Modell, dass keinen Random-Intercept enthält, d.h. mit einem “normalen” linearen Modell ohne Prädiktor (mit dem Gesamt-Mittelwert \(\gamma_{00}\) als einzigem Modellparameter neben der Level-1-Residualvarianz \(\sigma^2_\varepsilon\)). Dieses Modell kann man auch als “absolutes Nullmodell” bezeichnen. Wir müssen ein solches Modell nicht extra spezifizieren, sondern können die Funktion ranova()
auf das Outputobjekt intercept.only.model
anwenden. ranova()
(aus dem lme4-Hilfspackage lmerTest
) führt automatisch Modellvergleiche (nur) für Random-Effects durch, indem die vorhandenen Random-Effects Schritt für Schritt entfernt werden und das Ausgangsmodell dann mit dem so reduzierten Modell verglichen wird. In diesem Fall (Intercept-Only-Modell als Ausgangsmodell) kann nur ein Random-Effect entfernt werden, nämlich der des Intercepts.
# Vergleich des Intercept-Only-Modells mit dem "absoluten Nullmodell"
ranova(intercept.only.model)
ANOVA-like table for random-effects: Single term deletions
Model:
salary ~ (1 | company)
npar logLik AIC LRT Df Pr(>Chisq)
<none> 3 -1079.0 2164.0
(1 | company) 2 -1157.7 2319.4 157.44 1 < 2.2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Der Vergleich ist signifikant \((p<0.001)\). Wir können den p-Wert sogar noch halbieren, da es sich um einen einseitigen Test handelt. Der zu testende Parameter \(\sigma^2_{\upsilon_0}\) weist nämlich einen bounded parameter space auf (kann nicht kleiner als 0 werden). Damit haben wir eine signifikante Level-2-Varianz des Intercepts und die Verwendung eines hierarchischen linearen Modells für die folgenden Analysen ist damit angezeigt.
Weiter unten werden wir zeigen, wie Modellvergleiche mittels Likelihood-Ratio-Test auch von Hand durchgeführt werden können.
Visuell kann man sich den Vergleich zwischen dem absoluten Nullmodell und dem Intercept-Only-Modell folgendermassen vorstellen:
Code
<- "Experience in years"
xlabel <- "Salary per month"
ylabel
# Visual comparison between the two models
<- lm(salary ~ 1, data = df)
null.model $null.model.preds <- predict(null.model)
df
ggplot(data = df, aes(x = experience, y = null.model.preds)) + # , group=groupVar, colour=groupVar))+
geom_smooth(method = "lm", fullrange = TRUE, se = F, size = .3) +
geom_jitter(aes(group = company, colour = company), show.legend = FALSE, alpha = .2) +
labs(x = xlabel, y = ylabel) +
ggtitle("Absolutes Nullmodell") +
scale_colour_discrete() +
::theme_tufte() ggthemes
Code
$intercept.only.preds <- predict(intercept.only.model)
df
ggplot(data = df, aes(
x = experience,
y = intercept.only.preds,
colour = company
+
)) geom_smooth(method = "lm", fullrange = TRUE, se = F, size = .3) +
geom_jitter(aes(y = salary), alpha = .2) +
labs(x = xlabel, y = ylabel) +
ggtitle("Intercept-Only-Modell") +
scale_colour_discrete() +
geom_abline(intercept = fixef(intercept.only.model), slope = 0) +
::theme_tufte() ggthemes
1.4 Random-Intercept-Modell (Modell 2)
Dieses Modell enthält einen Level-1-Prädiktor (experience)
, der jedoch als fester Effekt konzeptualisiert wird (kein random slope, nur random intercept). Dieses Modell wird insbesondere benötigt, um den Anteil der durch den Level-1-Prädiktor erklärten Varianz zu ermitteln (vgl. Eid, Gollwitzer, und Schmitt 2017).
Level-1-Modell:
\(\boldsymbol {y_{mi}=\beta_{0i} + \beta_{1i} \cdot x_{mi} + \varepsilon_{mi}}\)
Level-2-Modell:
\(\boldsymbol {\beta_{0i}=\gamma_{00} + \upsilon_{0i}}\)
\(\boldsymbol {\beta_{1i}=\gamma_{10}}\)
Gesamtmodell:
\(\boldsymbol {y_{mi}=\gamma_{00} + \gamma_{10} \cdot x_{mi} + \upsilon_{0i}+\varepsilon_{mi}}\)
1.4.1 Modell berechnen
# Fitten und Abspeichern des Modells.
# Wenn eine Prädiktorvariable im Modell ist,
# muss der Intercept (also 1) nicht zusätzlich angegeben werden.
<- lmer(salary ~ experience + (1 | company),
random.intercept.model data = df, REML = TRUE
)
# Abspeichern von Prädiktionen, die dieses Modell macht.
# Wir speichern diese Prädiktionen (vorhergesagten Werte),
# um das Modell später mit "ggplot2" zu veranschaulichen.
$random.intercept.preds <- predict(random.intercept.model)
df
# Modell output anschauen
summary(random.intercept.model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: salary ~ experience + (1 | company)
Data: df
REML criterion at convergence: 1865.4
Scaled residuals:
Min 1Q Median 3Q Max
-2.8109 -0.6884 0.0005 0.5980 3.8833
Random effects:
Groups Name Variance Std.Dev.
company (Intercept) 0.6144 0.7838
Residual 1.1845 1.0883
Number of obs: 600, groups: company, 20
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 5.96418 0.22941 48.00060 26.00 <2e-16 ***
experience 0.53434 0.02721 589.48148 19.64 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
experience -0.615
Die Ergebnisse zeigen, dass der Fixed-Effect von experience
positiv signifikant ist \((\hat\gamma_{10} = 0.534, p < 0.001)\). Im Durchschnitt aller Firmen steigt das vorhergesagte Einkommen (salary)
also mit jedem Jahr Arbeitserfahrung um ca. 0.534 Einheiten (534 CHF) an.
Mit der Funktion ranef()
kann man sich wieder die einzelnen Random-Effects \(\upsilon_{0i}\) ausgeben lassen:
ranef(random.intercept.model)
$company
(Intercept)
Company 01 0.20430372
Company 02 0.64614732
Company 03 1.49200151
Company 04 -0.91078990
Company 05 0.38916512
Company 06 -0.92463977
Company 07 0.57766959
Company 08 -0.51651767
Company 09 -0.63824646
Company 10 0.76848113
Company 11 -0.61955111
Company 12 1.09133530
Company 13 -0.77367207
Company 14 -0.73817926
Company 15 -0.65294087
Company 16 0.05733923
Company 17 0.45805487
Company 18 -0.08938416
Company 19 0.94422822
Company 20 -0.76480474
with conditional variances for "company"
Die Werte scheinen im Vergleich zum Intercept-Only-Modell (s.o.) deutlich kleiner geworden zu sein. Was das bedeutet, sehen wir gleich bei der Berechnung der erklärten Gesamtvarianz durch den Prädiktor experience
.
1.4.2 Varianzerklärung durch Level-1-Prädiktor
Wieviel Level-1-Varianz wurde durch experience
erklärt?
\(R^2_{Level-1} = \frac {\sigma^2_{\varepsilon1} - \sigma^2_{\varepsilon2}}{\sigma^2_{\varepsilon1}} = \frac {{1.9547}-{1.1845}}{1.9547} = {0.394}\)
Wieviel Gesamtvarianz wurde durch experience
erklärt?
\(R^2_{Gesamt} = \frac {(\sigma^2_{\upsilon_01} + \sigma^2_{\varepsilon1}) - (\sigma^2_{\upsilon_02} + \sigma^2_{\varepsilon2})}{\sigma^2_{\upsilon_01} + \sigma^2_{\varepsilon1}} = \frac{({0.8512 + 1.9547}) - ({0.6144 + 1.1845}) } { 0.8512 + 1.9547} = 0.359\)
Wir sehen, dass durch Aufnahme des Level-1 Prädiktors experience
neben der Level-1-Varianz auch die Level-2-Varianz kleiner wurde. Das liegt daran, dass sich die Firmen nicht nur systematisch bezüglich der AV salary
unterscheiden, sondern auch bezüglich des Prädiktors experience
. Wie in einer Kovarianzanalyse verändert sich der Effekt (bzw. die Level-2-Varianz) von company
durch Einbezug einer mit dem Faktor korrelierten Kovariate. Mehr dazu werden wir in der nächsten Übung erfahren.
\(~\)
Code
$random.intercept.preds <- predict(random.intercept.model)
df
ggplot(data = df, aes(
x = experience,
y = random.intercept.preds,
colour = company
+
)) geom_smooth(method = "lm", fullrange = TRUE, se = F, size = .3) +
geom_jitter(aes(y = salary), alpha = .2) +
labs(x = xlabel, y = ylabel) +
ggtitle("Random-Intercept-Modell") +
geom_abline(
intercept = fixef(random.intercept.model)["(Intercept)"],
slope = fixef(random.intercept.model)["experience"]
+
) scale_colour_discrete() +
::theme_tufte() ggthemes
1.5 Random-Coefficients-Modell (Modell 3)
Dieses Modell enthält sowohl einen Random-Intercept, als auch einen Random-Slope. Mit Hilfe dieses Modells kann die Varianz des Level-1-Slopes geschätzt werden. Damit erhalten wir ein Mass für die Unterschiedlichkeit des Effekts (Slope) des Level-1-Prädiktors (X, experience
) auf die AV (Y, salary
) zwischen den Level-2-Einheiten (company)
.
Level-1-Modell:
\(\boldsymbol {y_{mi}=\beta_{0i} + \beta_{1i} \cdot x_{mi} + \varepsilon_{mi}}\)
Level-2-Modell:
\(\boldsymbol {\beta_{0i}=\gamma_{00} + \upsilon_{0i}}\)
\(\boldsymbol {\beta_{1i}=\gamma_{10} + \upsilon_{1i}}\)
Gesamtmodell:
\(\boldsymbol {y_{mi}=\gamma_{00} + \gamma_{10} \cdot x_{mi} + \upsilon_{0i} + \upsilon_{1i} \cdot x_{mi} + \varepsilon_{mi}}\)
1.5.1 Modell berechnen
# Fitten und Abspeichern des Modells.
# Wenn für eine Prädiktorvariable ein Random-Slope im Modell ist, muss der
# Intercept (also 1) nicht mehr zusätzlich im Klammerausdruck für die zufälligen
# Effekte angegeben werden.
<- lmer(salary ~ experience + (experience | company),
random.coefficients.model data = df, REML = TRUE
)
# Abspeichern von Prädiktionen, die dieses Modell macht.
# Wir speichern diese Prädiktionen, um das Modell später mit ggplot2
# zu veranschaulichen.
$random.coefficients.preds <- predict(random.coefficients.model)
df
# Modell output anschauen
summary(random.coefficients.model)
Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: salary ~ experience + (experience | company)
Data: df
REML criterion at convergence: 1855.4
Scaled residuals:
Min 1Q Median 3Q Max
-2.8307 -0.6804 0.0037 0.5999 3.3608
Random effects:
Groups Name Variance Std.Dev. Corr
company (Intercept) 0.72257 0.8500
experience 0.01839 0.1356 -0.51
Residual 1.13629 1.0660
Number of obs: 600, groups: company, 20
Fixed effects:
Estimate Std. Error df t value Pr(>|t|)
(Intercept) 5.93372 0.24038 18.88905 24.68 7.77e-16 ***
experience 0.53085 0.04059 18.95008 13.08 6.20e-11 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Correlation of Fixed Effects:
(Intr)
experience -0.690
Die Ergebnisse zeigen, dass der Fixed-Effect von experience
wiederum positiv signifikant ist \((\hat\gamma_{10} = 0.531, p < 0.001)\) (leicht unterschiedlich im Vergleich zum Random-Intercept-Modell). Das Hauptinteresse im Random-Coefficients-Modell gilt aber der Varianz bzw. Standardabweichung des Random-Slope: \(\hat\sigma^2_{\upsilon_1} = 0.0184\) und damit \(\hat\sigma_{\upsilon_1} = \sqrt{0.0184} = 0.1356\). Die durchschnittliche Abweichung (Level-2-Residuum \(\upsilon_{1i}\)) des experience
-Effekts einer Firma vom mittleren Effekt \(\hat\gamma_{10}\) beträgt also 0.1356 Einheiten (135.6 CHF).
Mit der Funktion ranef()
kann man sich wieder die einzelnen Random-Effects (jetzt Level-2-Residuen des Intercepts \(\upsilon_{0i}\) und des Slopes \(\upsilon_{1i}\)) ausgeben lassen:
ranef(random.coefficients.model)
$company
(Intercept) experience
Company 01 -1.003794102 0.203747776
Company 02 -0.160820541 0.143400958
Company 03 0.705132570 0.139886714
Company 04 -0.611829652 -0.054018876
Company 05 -0.033975063 0.076641659
Company 06 -0.123906149 -0.150704419
Company 07 0.669506844 -0.013616984
Company 08 -0.830781477 0.065813067
Company 09 -1.020757779 0.086008002
Company 10 0.392944052 0.081964065
Company 11 -0.769063062 0.037944670
Company 12 1.248886366 -0.025028992
Company 13 -0.593370830 -0.025453610
Company 14 -0.186191134 -0.109527150
Company 15 0.007222191 -0.150163600
Company 16 0.772829070 -0.140812590
Company 17 0.562032356 -0.011037598
Company 18 0.508160168 -0.112469594
Company 19 1.006168875 -0.006676886
Company 20 -0.538392700 -0.035896609
with conditional variances for "company"
Im Output befindet sich auch eine Angabe zum dritten Random-Effect-Parameter, der in diesem Modell geschätzt wurde, nämlich zur Kovarianz \(\hat\sigma_{\upsilon_0\upsilon_1}\) zwischen den Level-2-Residen des Intercepts und den Level-2-Residuen des Slopes. Allerdings wird nicht die Kovarianz selbst ausgegeben, sondern ihre standardisierte Variante, die Korrelation \(r_{\upsilon_0\upsilon_1} = -0.51\). Diese besagt, dass das durchschnittliche Gehalt eines Berufsanfängers in einer Firma (vorhergesagter Wert von salary
an der Stelle experience = 0)
negativ mit der Steigung von experience
korreliert ist. Zur Interpretation: Wenn schon Berufsanfänger in einer Firma gut verdienen, gibt es offenbar weniger Spielraum für Gehaltssteigerungen als in Firmen mit weniger hohem Einstiegsgehalt.
1.5.2 Signifikanztest für \(\sigma^2_{\upsilon_1}\): Modellvergleich mit Random-Intercept-Modell
Wenn wir dieses Modell mittels LR-Test mit dem Random-Intercept-Modell (s.o.) vergleichen, werden zwei Parameter gleichzeitig getestet: die Level-2-Varianz des Slopes (\(\sigma^2_{\upsilon_1}\)) und die Level-2-Kovarianz zwischen Intercept und Slope (\(\sigma_{\upsilon_0\upsilon_1}\)). Laut gegenwärtigem Forschungsstand ist dies die beste Methode, um zu überprüfen, ob es eine signifikante Slope-Varianz gibt (vgl. Eid, Gollwitzer, und Schmitt 2017).
1.5.2.1 Modellvergleich von Hand
Zunächst benötigen wir die -2-Log-Likelihoods (Devianzen) der beiden zu vergleichenden Modelle. Diese wird im Modelloutput des jeweiligen Modells unter der Bezeichnung “REML criterion at convergence” ausgegeben.
Wir folgen hier ausserdem den Bezeichnungen für uneingeschränkte Modelle \((M_u)\) und für eingeschränkte (restringierte) Modelle \((M_e)\), wie wir sie auch für die Modellvergleiche bei der logistischen Regression in Statistik III verwendet haben. \(M_u\) steht hier für das Random-Coefficients-Modell, das die zu testenden Parameter (Slope-Varianz \(\sigma^2_{\upsilon_1}\) und Intercept-Slope-Kovarianz \(\sigma_{\upsilon_0\upsilon_1}\)) enthält, \(M_e\) für das Random-Intercept-Model, das genau diese Parameter nicht enthält.
-2-Log-Likelihood random.intercept.model
(\(M_e\)): \(-2\cdot ln(L_e) = 1865.4\)
-2-Log-Likelihood random.coefficients.model
(\(M_u\)): \(-2\cdot ln(L_u) = 1855.4\)
\(~\)
Berechnen des Modellvergleichstests \(LR(M_u - M_e)\):
\(\chi^2_{emp} = [-2 \cdot ln(L_e)] - [-2 \cdot ln(L_u)] = 1865.4 - 1855.4 = 10.0\)
Anzahl Parameter \((nPar) \space M_u: \space \textbf{6} \space \space (\gamma_{00},\space\gamma_{10},\space\sigma^2_{\varepsilon}, \space\sigma^2_{\upsilon_0}, \space\sigma^2_{\upsilon_1}, \space\sigma_{\upsilon_0\upsilon_1})\)
Anzahl Parameter \((nPar) \space M_e:\space \textbf{4} \space \space (\gamma_{00}, \space\gamma_{10}, \space\sigma^2_{\varepsilon}, \space\sigma^2_{\upsilon_0})\)
\(LR(M_u - M_e)\) ist \(\chi^2\)-verteilt mit \(df = nPar(M_u) - nPar(M_e) = 6 - 4 = 2\)
Kritischer Wert: \(\chi^2_{(0.95, df = 2)} = 5.9915\)
Aber: Es handelt sich genau genommen um eine Mischverteilung aus \(\chi^2_{df=1}\) und \(\chi^2_{df=2}\), da einer der beiden getesteten Parameter \((\sigma^2_{\upsilon_1})\) einen bounded parameter space aufweist (kann nicht kleiner als 0 werden). Daher ist der korrekte kritische Chi-Quadrat-Wert hier das 95 %-Quantil dieser Mischverteilung und liegt bei (gerundet) 5.14 (vgl. Eid, Gollwitzer, und Schmitt 2017).
Der Test ist signifikant, da \(\chi^2_{emp} \space(=10.0) > \chi^2_{krit} \space(=5.14)\).
Beide Parameter zusammen unterscheiden sich also signifikant von 0. Der Fokus der Interpretation liegt hier aber auf dem Parameter der Slope-Varianz \(\sigma^2_{\upsilon_1}\) (nur wenn dieser > 0 ist, kann auch die Intercept-Slope-Kovarianz \(\sigma_{\upsilon_0\upsilon_1}\) überhaupt ungleich 0 sein).
Inhaltlich bedeutet dies, dass sich die Stärke des Effekts von experience
auf salary
signifikant zwischen den Firmen (company
) unterscheidet. Die oben im Random-Coefficients-Modell geschätzte Slope-Varianz von experience
\((\hat \sigma^2_{\upsilon_1} = 0.0184)\) ist damit als signifikant zu bewerten.
1.5.2.2 Modellvergleich in R
Wie beim Signifikanztest der Random-Intercept-Varianz \(\sigma^2_{\upsilon_0}\) im Intercept-Only-Modell können wir den Modellvergleich hier wieder mit ranova()
vornehmen. Wie oben wird ranova()
auf das uneingeschränkte Modell angewandt, die Angabe eines (eingeschränkten) Vergleichsmodells ist nicht notwendig.
ranova(random.coefficients.model)
ANOVA-like table for random-effects: Single term deletions
Model:
salary ~ experience + (experience | company)
npar logLik AIC LRT Df Pr(>Chisq)
<none> 6 -927.70 1867.4
experience in (experience | company) 4 -932.71 1873.4 10.011 2 0.006699
<none>
experience in (experience | company) **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
\(~\)
Alternativ können wir den Modellvergleich auch mit der uns bereits bekannten Funktion anova()
durchführen, indem wir die beiden zu vergleichenden Modelle explizit angeben:
anova(random.coefficients.model, random.intercept.model, refit = FALSE)
Data: df
Models:
random.intercept.model: salary ~ experience + (1 | company)
random.coefficients.model: salary ~ experience + (experience | company)
npar AIC BIC logLik deviance Chisq Df
random.intercept.model 4 1873.4 1891.0 -932.71 1865.4
random.coefficients.model 6 1867.4 1893.8 -927.70 1855.4 10.011 2
Pr(>Chisq)
random.intercept.model
random.coefficients.model 0.006699 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Das Ergebnis zeigt einen signifikanten LR-Test mit \(\chi^2_{emp} = 10.011\). Der (Rundungs-)Unterschied zum Modellvergleich von Hand ergibt sich wegen der ungenaueren Angabe der Devianzen in den Modelloutputs.
Der angegebene \(p\)-Wert ist allerdings noch nicht ganz korrekt, da einer der beiden Parameter - \(\sigma^2_{\upsilon_1}\) - wie oben bereits festgestellt einen bounded parameter space aufweist. Der korrekte \(p\)-Wert auf Basis der Mischverteilung ist daher noch etwas kleiner als der ausgegebene.
\(~\)
Code
# sal.visualisation$random.intercept.random.slope.plot
$random.coefficients.preds <- predict(random.coefficients.model)
df
ggplot(data = df, aes(x = experience, y = random.coefficients.preds, colour = company)) +
geom_smooth(method = "lm", fullrange = TRUE, se = F, size = .3) +
labs(x = xlabel, y = ylabel) +
geom_jitter(aes(y = salary), alpha = .2) +
geom_abline(
intercept = fixef(random.coefficients.model)["(Intercept)"],
slope = fixef(random.coefficients.model)["experience"]
+
) ggtitle("Random Coefficients Model") +
scale_colour_discrete() +
::theme_tufte() ggthemes
1.6 Übung
Wir möchten (fiktive) Daten zur Pisa-Studie analysieren. Dafür haben wir einen Datensatz mit den Variablen:
id
: Durchnummerierung aller Schüler (1:1000)
name
: Name der Schülerin / des Schülers
grade
: Die durchschnittliche Vornote jedes Schülers (gerundet auf 0.25)
motivation
: Wie motiviert die Schüler für den Pisa-Test sind
class
: Variable der Schulklasse (durchnummeriert, 50 Klassen wurden zufällig ausgewählt)
teacher_salary
: Monatslohn des Lehrers (jede Klasse hat einen anderen Lehrer)
school
: Kategoriale Variable der Schule (10 Schulen wurden zufällig ausgewählt)
pisa
: Erreichte Punktzahl beim Pisa-Test.
Aus jeder der 10 Schulen wurden 5 Klassen ausgesucht. Insgesamt sind es also 50 Klassen. Für die folgenden Aufgaben beachten wir die Nestung der Klassen in den verschiedenen Schulen nicht, da wir dafür ein 3-Ebenen-Modell bräuchten. Unser Sample auf Level-2 sind also die 50 Schulklassen. Die Daten kann man sich etwa so vorstellen (subsample, nur 15 Klassen für die Visualisierung):
Code
<- read_csv(url("https://raw.githubusercontent.com/methodenlehre/data/master/statistik_IV/simulated_school_data.csv"))
school_df
<- school_df[1:300, ]
subsample <- subsample |> mutate(class = as.factor(class))
subsample
ggplot(data = subsample, aes(x = grade, y = pisa, group = class, color = class)) +
geom_smooth(method = "lm", alpha = .5, se = FALSE, show.legend = F, fullrange = TRUE, size = .5) +
geom_point(alpha = .3) +
::theme_tufte() ggthemes
1. Aufbereitung der Daten
- Laden Sie die Daten in R und schauen Sie sich die ersten paar Zeilen des Datensatzes an. Die Daten können entweder zuerst heruntergeladen und im Ordner versorgt werden, oder man kann sie auch direkt von R aus dem Internet laden (weil sie öffentlich im Internet zugänglich sind). Die Daten sind hier:
https://raw.githubusercontent.com/methodenlehre/data/master/statistik_IV/simulated_school_data.csv
Tipp: Verwenden Sie dieselbe Funktion wie weiter oben im Skript um Daten direkt aus dem Internet zu laden.
- Stellen Sie sicher, dass die Variablen im richtigen Format sind. Als Tipp: Überlegen Sie sich, welche Variablen kategorial und welche numerisch sind.
- (optional) Visualisieren Sie die Daten mit der Funktion
plot()
. Als Tipp: Wenn nur numerische Variablen im Datenframe sind, können mit plot(datenframe) direkt die Zusammenhänge der Variablen dargestellt werden.
2. Fragestellung und Intercept-Only-Modell
Wir gehen davon aus, dass die Schulklassen zufällig ausgesucht wurden. Wir sind nicht daran interessiert, wie sich diese spezifischen Klassen voneinander unterscheiden. Uns interessiert vielmehr, ob die Vornote (grade
) sowie die Motivation (motivation
) einen Einfluss auf die Pisa-Werte haben. Die Schulklassen möchten wir als Random-Effect modellieren.
- Berechnen Sie ein Intercept-Only-Modell.
- Testen Sie, ob der Random-Effect (
class
) in diesem Modell tatsächlich Varianz aufweist. Ist die Modellstruktur gerechtfertigt, d.h. benötigen wir überhaupt ein HLM-Modell?
- Wie gross ist die Intraklassenkorrelation?
3. Random-Intercept-Modell
- Berechnen Sie ein Random-Intercept-Modell mit den beiden Prädiktoren
grade
undmotivation
. Sind die fixed effects (\(\hat\gamma_{10}\) und \((\hat\gamma_{20}\)) beider Prädiktoren signifikant?
- Testen Sie, ob ein zusätzlicher Interaktionseffekt zwischen
grade
undmotivation
ins Modell aufgenommen werden sollte. Obwohl wir keine spezifische Moderationshypothese haben, können wir im Sinne eines Vermeidens von Underfitting überprüfen, ob eine bedeutsame Interaktion vorhanden ist.
4. Random-Coefficients-Modell
Zusätzlich zum Random-Intercept können wir auch die Varianzen der Slopes von grade
und motivation
mit ins Modell aufnehmen. Doch “lohnt” sich das überhaupt, d.h. unterscheiden sich die Effekte der beiden Prädiktoren jeweils signifikant zwischen den Klassen?
- Schätzen Sie ein Random-Coefficients Modell mit Random Slopes für
grade
undmotivation
.
- Testen Sie die Signifikanz beider Random Slopes mit
ranova()
.