library(lme4)
library(marginaleffects)
library(tidyverse)
library(report)
theme_set(theme_minimal())
6 Multilevel-Modelle
Zoizner, A., Sheafer, T., Castro, L., Aalberg, T., Cardenal, A. S., Corbu, N., Vreese, C. de, Esser, F., Hopmann, D. N., Koc-Michalska, K., Matthes, J., Schemer, C., Splendore, S., Stanyer, J., Stępińska, A., Štětka, V., Strömbäck, J., Theocharis, Y., & Van Aelst, P. (2022). The Effects of the COVID-19 Outbreak on Selective Exposure: Evidence from 17 Countries. Political Communication, 39(5), 674–696. https://doi.org/10.1080/10584609.2022.2107745
6.1 Pakete und Daten
Wir laden zunächst wie immer die notwendigen R-Pakete. Für Multilevel-Modelle benötigen wir das lme4
- und das marginaleffects
-Paket. Wie immer laden wir außerdem tidyverse
und report
. Für eine schönere Darstellung der Plots setzen wir außerdem das Theme auf theme_minimal
.
Für die Multilevel-Analyse nutzen wir den Datensatz zoizner_etal.csv
. Die Autor:innen untersuchen, inwieweit Bürger:innen nach dem Ausbruch der Covid19-Pandemie Informationen aus Quellen erhalten haben, deren Inhalte sie normalerweise nicht unbedingt konsumieren. Dazu führten sie eine zweiwellige Panelbefragung in 17 Ländern vor und nach dem Ausbruch der Pandemie durch. Der Datensatz enthält unter anderem die folgenden Variablen: Cross-cutting Exposure in Bezug auf traditionelle Medien (wie häufig werden Personen mit Informationen aus Quellen konfrontiert, deren Inhalte sie normalerweise nicht konsumieren), Besorgnis über die COVID-19-Pandemie und das Land, aus dem die Befragten stammen.
Um die Cross-cutting Exposure zu bestimmen, wurden die Befragten zum einen nach der Häufigkeit der Nutzung bestimmer Medien (nie bis täglich) und ihrer politischen Einstellung (links bis rechts) gefragt. Zum anderen wurden die Medien mit Hilfe von Expert:innen nach ihrer Ideologie (links bis rechts) eingeordnet. Die politische Einstellung der Befragten wurde mit der ideologischen Einordnung der Medien und der Häufigkeit der Mediennutzung korreliert. Die Variable Cross-Cutting Exposure nimmt einen Wert zwischen 0 und 1 an (je höher, desto mehr Cross-Cutting Exposure).
<- read_csv("data/zoizner_etal.csv")
d_zoizner d_zoizner
# A tibble: 14,218 × 36
...1 wave date_W2_dateformat_1day_before cross_cutting_consumption_w2_01
<dbl> <dbl> <date> <dbl>
1 1 2 2020-05-13 0.0333
2 2 2 2020-05-04 0.233
3 3 2 2020-05-04 0
4 4 2 2020-05-11 NA
5 5 2 2020-05-11 NA
# ℹ 14,213 more rows
# ℹ 32 more variables: worried_from_covid_total_01 <dbl>, age <dbl>,
# female <chr>, female_numeric <dbl>, education_numeric <dbl>,
# political_interest_w2 <dbl>, political_knowledge_w2 <dbl>,
# right_ideology_w2 <dbl>, right_ideology_w2_binary <chr>,
# news_consumption_internet_w2 <dbl>, news_consumption_socialmedia_w2 <dbl>, # cross_cutting_consumption_w1_01 <dbl>, …
Multilevel-Modelle werden für die Analyse von hierarchisch geschachtelten Daten verwendet. Diese Datenstruktur liegt hier ebenfalls vor, da Befragte aus unterschiedlichen Ländern enthalten sind. Die Befragten können in Länder geschachtelt werden, sie bilden damit eine Ebene unterhalb der Länder. Entsprechend liegen in unserem Datensatz zwei Ebenen vor: die Länder (Level 2) und die Befragten (Level 1). Unsere abhängige Variable, die Cross-Cutting Exposure zu T2,wurde auf dem Befragtenlevel (Level 1) gemessen.
Wir betrachten zunächst die Level-2-Variable (country), in dem wir uns die Anzahl der Befragten pro Land in unserer Stichprobe ausgeben lassen.
count(d_zoizner, dCountry_W2)
# A tibble: 17 × 2
dCountry_W2 n
<chr> <int>
1 Austria 852
2 Belgium 764
3 Denmark 751
4 France 889
5 Germany 968 # ℹ 12 more rows
Insgesamt sind Befragte aus 17 Ländern in der Stichprobe enthalten.
Wie bei allen Analysen lohnt sich auch bei Mutlilevel-Modellen ein Blick auf die Verteilung der Outcome-Variable, in diesem Fall die Cross-Cutting Exposure zu T2 (Level 1).
|>
d_zoizner select(cross_cutting_consumption_w2_01) |>
::report_sample() report
# Descriptive Statistics
Variable | Summary
------------------------------------------------------- Mean cross_cutting_consumption_w2_01 (SD) | 0.27 (0.26)
Über alle Länder hinweg beträgt die durchschnittliche Cross-Cutting Exposure zum Zeitpunkt T2 .27 (SD = .26).
6.2 Nullmodell und ICC
Zunächst berechnen wir ein Nullmodel, welches Auskunft darüber gibt, wie sich die Varianz auf die verschiedenen Ebenen verteilt. Das Modell schätzt zunächst ohne erklärende Variablen die Durchschnittswerte der Variablen cross_cutting_consumption_w2_01
und berücksichtigt dabei die zufälligen Abweichungen zwischen den Ländern (dCountry_W2
).
<- lmer(cross_cutting_consumption_w2_01 ~ 1 + (1 | dCountry_W2), d_zoizner) m0_cc
Diese Varianzen können wir nutzen, um den Intraklassenkorrelationskoeffizient (ICC) zu berechnen, der einen Hinweis darauf gibt, ob ein Multilevel-Modell überhaupt nötig ist.
::icc(m0_cc) performance
# Intraclass Correlation Coefficient
Adjusted ICC: 0.102 Unadjusted ICC: 0.102
Etwa 10% der Varianz der Cross-Cutting Exposure lässt sich ausschließlich durch Unterschiede zwischen den Ländern erklären.
Wir können uns auch die vorhergesagte Cross-Cutting Exposure für die verschiedenen Länder ausgeben lassen. Dazu berechnen wir Modelvorhersagen mit der Funktion avg_predictions()
.
::avg_predictions(m0_cc, by = "dCountry_W2") |>
marginaleffectsas_tibble()
# A tibble: 17 × 10
rowid dCountry_W2 estimate std.error statistic p.value s.value conf.low
<int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 Netherlands 0.244 0.0202 12.1 1.93e-33 109. 0.204
2 2 Austria 0.311 0.0202 15.4 3.45e-53 174. 0.271
3 3 France 0.172 0.0202 8.49 2.01e-17 55.5 0.132
4 4 Germany 0.152 0.0202 7.53 5.07e-14 44.2 0.113
5 5 Italy 0.303 0.0202 15.0 9.54e-51 166. 0.264
# ℹ 12 more rows # ℹ 2 more variables: conf.high <dbl>, rowid_dedup <int>
Wie wir sehen, gibt es einige Unterschiede zwischen den Ländern, in Schweden und der Schweiz ist die vorhergesagte Cross-Cutting Exposure vergleichsweise hoch, während sie in Ungarn, Deutschland und Frankreich vergleichsweise niedrig ist. Dies können wir uns auch grafisch darstellen lassen:
::avg_predictions(m0_cc, by = "dCountry_W2") |>
marginaleffectsas_tibble() |>
ggplot(aes(
x = reorder(dCountry_W2, estimate), y = estimate,
ymin = conf.low, ymax = conf.high
+
)) geom_pointrange() +
coord_flip() +
labs(x = "", y = "Predicted cross-cutting exposure")
6.3 Varying Intercepts
6.3.1 Modellschätzung
Nun fügen wir dem Nullmodell zwei Prädiktoren auf Level 1 hinzu, also auf Befragtenebene. Zum einen die Cross-Cutting Exposure zu T1 (cross_cutting_consumption_w1_01
zum ersten Messzeitpunkt, also den autoregressiven Effekt), zum anderen die Bersorgnis aufgrund von Covid (worried_from_covid_total_01
) . Das Modell enthält damit wieder eine Lagged Dependent Variable.
<- lmer(cross_cutting_consumption_w2_01 ~ cross_cutting_consumption_w1_01 + worried_from_covid_total_01 +
m1_cc 1 | dCountry_W2), d_zoizner)
(::report_table(m1_cc) report
Parameter | Coefficient | 95% CI | t(8434) | p | Effects | Group | Std. Coef. | Std. Coef. 95% CI | Fit
----------------------------------------------------------------------------------------------------------------------------------------------------
(Intercept) | 0.02 | [ 0.00, 0.03] | 1.73 | 0.083 | fixed | | 2.68e-03 | [-0.04, 0.05] |
cross cutting consumption w1 01 | 0.76 | [ 0.75, 0.78] | 103.32 | < .001 | fixed | | 0.75 | [ 0.73, 0.76] |
worried from covid total 01 | 0.07 | [ 0.05, 0.09] | 7.71 | < .001 | fixed | | 0.06 | [ 0.04, 0.07] |
| 0.02 | | | | random | dCountry_W2 | | |
| 0.16 | | | | random | Residual | | |
| | | | | | | | |
AIC | | | | | | | | | -6814.46
AICc | | | | | | | | | -6814.46
BIC | | | | | | | | | -6779.26
R2 (conditional) | | | | | | | | | 0.59
R2 (marginal) | | | | | | | | | 0.59 Sigma | | | | | | | | | 0.16
Sowohl die Cross-Cutting Exposure zu T1 als auch die Besorgnis um Covid haben einen positiven sig. Effekt auf die Cross-Cutting Exposure zu T2 (p<.001), wobei ersteres wieder nur als Stabilitätskoeffizient zu interpretieren ist.
Auch für dieses Modell können wir Modellvorhersagen berechnen, hier zum Effekt der Cross-Cutting Exposure.
avg_predictions(m1_cc, variables = c("worried_from_covid_total_01", "dCountry_W2")) |>
as_tibble()
# A tibble: 85 × 9
worried_from_covid_total_01 dCountry_W2 estimate std.error statistic p.value
<dbl> <chr> <dbl> <dbl> <dbl> <dbl>
1 0 Netherlands 0.214 0.00865 24.7 3.54e-135
2 0.5 Netherlands 0.250 0.00635 39.3 0
3 0.667 Netherlands 0.261 0.00619 42.2 0
4 0.833 Netherlands 0.273 0.00640 42.7 0
5 1 Netherlands 0.285 0.00696 41.0 0
# ℹ 80 more rows # ℹ 3 more variables: s.value <dbl>, conf.low <dbl>, conf.high <dbl>
Die Modellvorhersagen lassen sich dann auch wieder grafisch darstellen, wobei jedes Land einzeln dargestellt ist.
avg_predictions(m1_cc, variables = c("worried_from_covid_total_01", "dCountry_W2")) |>
as_tibble() |>
ggplot(aes(
x = worried_from_covid_total_01, y = estimate,
color = dCountry_W2, group = dCountry_W2
+
)) geom_line(show.legend = FALSE) +
labs(x = "Covid-related worries T1", y = "Predicted cross-cutting exposure")
Der positive Effekt der Besorgnis über Covid auf die Cross-Cutting Exposure zu T2 ist im vorliegenden Modell in allen Ländern gleich, d.h. in allen Ländern ist der Anstieg identisch, was sich in den parallelen Linien zeigt. Die Länder unterscheiden sich hier nur durch die Varying Intercepts, d.h. durch die unterschiedliche Ausgangswerte. Diese Annahme können wir im nächsten Modell aufheben.
6.3.2 Voraussetzungen
Auch bei Mehrebenenmodellen können wir die klassischen Regressions-Annahmen wie Linearität, Normalverteilung der Residuen, Homoskedastizität und Multikollinearität überprüfen. Hierfür nutzen wir wieder die check_model()
-Funktion aus dem performance
-Paket.
<- performance::check_model(m1_cc, panel = F)
checks plot(checks)
$PP_CHECK
$NCV
$HOMOGENEITY
$OUTLIERS
$VIF
$QQ
[[7]]
6.4 Varying Slopes
6.4.1 Modellschätzung
Multilevel-Modelle können neben Varying Intercepts auch Varying Slopes enthalten. Kurz gesagt bilden Varying Slopes unterschiedliche Effekte einer Variable in den verschiedenen Gruppen (hier: in den Ländern) ab. In der nachfolgenden Analyse nehmen wir an, dass die Besorgnis über Covid und die Cross-Cutting Exposure zu T1 bei den Befragten nicht in allen Ländern den gleichen (positiven) Effekt auf die Cross-Cutting Exposure zu T2 hat. Die Varying Slopes fügen wir hinzu, indem wir die Variablen worried_from_covid_total_01
und cross_cutting_consumption_w1_01
in die Klammer (1 | dCountry_W2)
, welche die Varying Intercepts kennzeichnet, aufnehmen.
<- lmer(cross_cutting_consumption_w2_01 ~ cross_cutting_consumption_w1_01 + worried_from_covid_total_01 +
m2_cc 1 + cross_cutting_consumption_w1_01 + worried_from_covid_total_01 | dCountry_W2), d_zoizner)
(::report_table(m2_cc) report
Random effect variances not available. Returned R2 does not account for random effects.
Parameter | Coefficient | 95% CI | t(8429) | p | Effects | Group | Std. Coef. | Std. Coef. 95% CI | Fit
---------------------------------------------------------------------------------------------------------------------------------------------------
(Intercept) | 0.02 | [0.00, 0.03] | 2.66 | 0.008 | fixed | | 3.68e-03 | [-0.05, 0.05] |
cross cutting consumption w1 01 | 0.76 | [0.75, 0.78] | 85.26 | < .001 | fixed | | 0.74 | [ 0.73, 0.76] |
worried from covid total 01 | 0.07 | [0.05, 0.09] | 5.67 | < .001 | fixed | | 0.06 | [ 0.04, 0.08] |
| 0.02 | | | | random | dCountry_W2 | | |
| 0.03 | | | | random | dCountry_W2 | | |
| | | | | random | dCountry_W2 | | |
| 0.00 | | | | random | dCountry_W2 | | |
| 0.58 | | | | random | dCountry_W2 | | |
| 0.16 | | | | random | Residual | | |
| | | | | random | dCountry_W2 | | |
| | | | | | | | |
AIC | | | | | | | | | -6819.06
AICc | | | | | | | | | -6819.04
BIC | | | | | | | | | -6748.66
R2 (marginal) | | | | | | | | | 0.59 Sigma | | | | | | | | | 0.16
In der report_table()
werden leider die Varianzen bzw. Standardabweichungen der variierenden Slopes und Intercepts nicht gut gelabelt, daher greifen wir hier auf summary()
zurück.
summary(m2_cc)
Linear mixed model fit by REML ['lmerMod']
Formula: cross_cutting_consumption_w2_01 ~ cross_cutting_consumption_w1_01 +
worried_from_covid_total_01 + (1 + cross_cutting_consumption_w1_01 +
worried_from_covid_total_01 | dCountry_W2)
Data: d_zoizner
REML criterion at convergence: -6839.1
Scaled residuals:
Min 1Q Median 3Q Max
-5.4248 -0.4616 -0.1690 0.4677 5.9361
Random effects:
Groups Name Variance Std.Dev. Corr
dCountry_W2 (Intercept) 0.0000000 0.00000
cross_cutting_consumption_w1_01 0.0004027 0.02007 NaN
worried_from_covid_total_01 0.0011544 0.03398 NaN 0.58
Residual 0.0258233 0.16070
Number of obs: 8439, groups: dCountry_W2, 17
Fixed effects:
Estimate Std. Error t value
(Intercept) 0.016574 0.006230 2.661
cross_cutting_consumption_w1_01 0.762807 0.008947 85.258
worried_from_covid_total_01 0.069850 0.012328 5.666
Correlation of Fixed Effects:
(Intr) c___1_
crss___1_01 -0.149
wrrd_f___01 -0.672 0.125
optimizer (nloptwrap) convergence code: 0 (OK) boundary (singular) fit: see help('isSingular')
Das Modell unterstellt jetzt, dass es einen Gesamt-Intercept und Slopes über alle Befragten und Länder gibt sowie länderspezifische Abweichungen davon. Der länderspezifische Effekt ist dann die Summe aus Gesamt-Slope und länderspezifischen Abweichungen. Um diese zu schätzen, gibt es eine spezielle Funktion avg_slopes()
mit dem by
Parameter.
::avg_slopes(m2_cc, variables = "worried_from_covid_total_01", by = "dCountry_W2") |>
marginaleffectsas_tibble()
# A tibble: 17 × 13
term contrast dCountry_W2 estimate std.error statistic p.value s.value
<chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 worried_fr… mean(dY… Austria 0.0833 0.0123 6.76 1.37e-11 36.1
2 worried_fr… mean(dY… Belgium 0.0590 0.0123 4.79 1.68e- 6 19.2
3 worried_fr… mean(dY… Denmark 0.0453 0.0123 3.67 2.41e- 4 12.0
4 worried_fr… mean(dY… France 0.0318 0.0123 2.58 9.99e- 3 6.65
5 worried_fr… mean(dY… Germany 0.0404 0.0123 3.28 1.04e- 3 9.91
# ℹ 12 more rows
# ℹ 5 more variables: conf.low <dbl>, conf.high <dbl>, predicted_lo <dbl>, # predicted_hi <dbl>, predicted <dbl>
Wir sehen, dass sich die geschätzten Regressionskoeffizienten für die Besorgnis über Covid zwischen den Ländern unterscheiden. Auch für dieses Modell können wir die Modellvorhersagen berechnen und grafisch darstellen.
avg_predictions(m2_cc, variables = c("worried_from_covid_total_01", "dCountry_W2")) |>
as_tibble() |>
ggplot(aes(
x = worried_from_covid_total_01, y = estimate,
color = dCountry_W2, group = dCountry_W2
+
)) geom_line(show.legend = FALSE) +
labs(x = "Covid-related worries T1", y = "Predicted cross-cutting exposure")
Im Unterschied zum vorherigen Modell sehen wir nun länderspezifische Ausgangswerte und Anstiege der Regressionsgeraden.
6.4.2 Modellvergleich Fixed vs. Varying Slopes
Um unsere beiden Modelle zu vergleichen, können wir die anova()
-Funktion nutzen, um einen Likelihood-Ratio-Test durchzuführen.
anova(m1_cc, m2_cc)
Data: d_zoizner
Models:
m1_cc: cross_cutting_consumption_w2_01 ~ cross_cutting_consumption_w1_01 + worried_from_covid_total_01 + (1 | dCountry_W2)
m2_cc: cross_cutting_consumption_w2_01 ~ cross_cutting_consumption_w1_01 + worried_from_covid_total_01 + (1 + cross_cutting_consumption_w1_01 + worried_from_covid_total_01 | dCountry_W2)
npar AIC BIC logLik deviance Chisq Df Pr(>Chisq)
m1_cc 5 -6838.4 -6803.2 3424.2 -6848.4
m2_cc 10 -6845.5 -6775.1 3432.8 -6865.5 17.176 5 0.004178 **
--- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Der Test zeigt an, dass das Varying Slopes Modell signifikant besser ist als das Varying Intercept Modell (p<.001), d.h. es gibt signifikante Effektheterogenität bezüglich der Prädiktoren Cross-cutting Exposure zu T1 und Besorgnis über Covid.
6.5 Level-2 Prädiktoren
Bislang haben wir mit cross_cutting_consumption_w1_01
und worried_from_covid_total_01
lediglich Level-1-Prädiktoren für unsere Analyse verwendet. Es ist aber ebenso möglich, einen Level-2-Prädiktor in das Modell aufzunehmen, um die Unterschiede zwischen den Gruppen zu erklären. So könnte der Schweregrad von Covid19 (die Anzahl der Fälle im Land) die Cross-Cutting Exposure beeinflussen. Deshalb fügen wir die Variable confirmed_per_100k
in die Formel ein.
<- lmer(cross_cutting_consumption_w2_01 ~ cross_cutting_consumption_w1_01 + worried_from_covid_total_01 + confirmed_per_100k + (1 + cross_cutting_consumption_w1_01 + worried_from_covid_total_01 | dCountry_W2), d_zoizner)
m3_cc ::report_table(m3_cc) report
Parameter | Coefficient | 95% CI | t(8428) | p | Effects | Group | Std. Coef. | Std. Coef. 95% CI | Fit
----------------------------------------------------------------------------------------------------------------------------------------------------
(Intercept) | 0.01 | [-0.01, 0.04] | 1.21 | 0.227 | fixed | | 3.77e-03 | [-0.05, 0.05] |
cross cutting consumption w1 01 | 0.76 | [ 0.74, 0.78] | 78.17 | < .001 | fixed | | 0.74 | [ 0.73, 0.76] |
worried from covid total 01 | 0.07 | [ 0.05, 0.10] | 5.69 | < .001 | fixed | | 0.06 | [ 0.04, 0.08] |
confirmed per 100k | 3.38e-06 | [ 0.00, 0.00] | 0.09 | 0.932 | fixed | | 1.85e-03 | [-0.04, 0.04] |
| 0.02 | | | | random | dCountry_W2 | | |
| 0.03 | | | | random | dCountry_W2 | | |
| 0.04 | | | | random | dCountry_W2 | | |
| -0.77 | | | | random | dCountry_W2 | | |
| -0.34 | | | | random | dCountry_W2 | | |
| 0.87 | | | | random | dCountry_W2 | | |
| 0.16 | | | | random | Residual | | |
| | | | | | | | |
AIC | | | | | | | | | -6801.93
AICc | | | | | | | | | -6801.90
BIC | | | | | | | | | -6724.49
R2 (conditional) | | | | | | | | | 0.60
R2 (marginal) | | | | | | | | | 0.58 Sigma | | | | | | | | | 0.16
Wie wir sehen, hängt die Anzahl der Fälle im Land nicht signifikant mit der Cross-Cutting Exposure zusammen (p >.05).
Weitere detaillierte Beispiele mit R-Code und Daten finden sich in den Materialien zur Vorlesung Anwendungsorientierte Analyseverfahren, u.a. zu
- Varying Intercept und Slope Modellen
- Modellvorhersagen und -visualisierungen
6.6 Glossar
Funktion | Definition |
---|---|
lme4::lmer | Multilevel-Modelle schätzen |
performance::check_model | Modellannahmen prüfen |
performance::icc | Intraklassenkorrelationskoeffizient berechnen |
6.7 Hausaufgabe
- Wie beeinflusst die Angst vor Covid (
worried_from_covid_total_01
) und das Alter der Befragten (age
) auf Befragtenebene sowie die Anzahl der Fälle im Land (confirmed_per_100k
) auf Länderebene die Nachrichtennutzung auf Social Media (news_consumption_socialmedia_w2
)? - Schätzen Sie das ganze als REWB-Modell. Interpretieren Sie die Ergebnisse und vergleichen mit dem RE-Modell aus Aufgabe 1.