library(tidyverse)
library(easystats)
library(rstanarm)
data("penguins", package = "palmerpenguins")
penguins-interact
Aufgabe
Eine Forscherin untersucht, ob das Geschlecht eines Pinguins den Einfluss der Flossenlänge (Flipper, mm) auf das Körpergewicht (g) des Tieres moderiert.
Auf Basis der Daten: Liegt ein (substanzieller) Interaktionseffekt vor?
Hinweise:
- Nutzen Sie die folgende Analyse als Grundlage Ihrer Antworten.
- Beachten Sie die Hinweise des Datenwerks.
- Unter “substanziell” sei ein Effekt von mind. 100 g verstanden.
Setup:
Dafür ist folgende Analyse gegeben.
Setup
library(rstanarm)
library(easystats)
library(tidyverse)
library(ggpubr)
Modell und Hypothese
Die Forschungsfrage kann man wie folgt als Hypothese formalisieren:
\[\beta_{m} \ne 0\]
“Der Regressionskoeffizient der Moderation (\(m\), d.h. Interaktion) ist ungleich Null.”
Testet man nicht eine exakte, sondern einen Mindestwert (ROPE), so kann man die Hypothese so formulieren:
\[\beta_{m} > 100\]
Die Prioris übernehmen wir vom Stan-Golem.🤖
🤖 Beep, beep!
👩🏫 An die Arbeit, Stan-Golem!
Wir könnten den Datensatz auch als CSV-Datei importieren:
<- "https://vincentarelbundock.github.io/Rdatasets/csv/palmerpenguins/penguins.csv"
d_path <- data_read(d_path) # oder z.B. mit read_csv penguins
Ein Blick in die Daten zur Kontrolle, ob das Importieren richtig funktioniert hat:
glimpse(penguins)
Rows: 344
Columns: 8
$ species <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
$ island <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
$ bill_length_mm <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
$ bill_depth_mm <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
$ flipper_length_mm <int> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
$ body_mass_g <int> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
$ sex <fct> male, female, female, NA, female, male, female, male…
$ year <int> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…
Wir entfernen noch alle fehlenden Werte:
<-
penguins_nona |>
penguins filter(sex == "female" | sex == "male")
$sex |> unique() penguins_nona
[1] male female
Levels: female male
Zur besseren Interpretierbarkeit standardisieren wir die (metrische) UV:
<-
penguins_nona_z |>
penguins_nona standardise(select = "flipper_length_mm",
append = TRUE)
<- stan_glm(body_mass_g ~ sex + flipper_length_mm_z + sex:flipper_length_mm_z, # Regressionsgleichung
m_interaction data = penguins_nona_z, # Daten
seed = 42, # Reproduzierbarkeit
refresh = 0) # nicht so viel Output
<- parameters(m_interaction, ci_method = "hdi", ci = .9)
m_interaction_params m_interaction_params
Parameter | Median | CI | CI_low | CI_high | pd | Rhat | ESS | Prior_Distribution | Prior_Location | Prior_Scale |
---|---|---|---|---|---|---|---|---|---|---|
(Intercept) | 4031.156606 | 0.9 | 3985.09735 | 4078.37091 | 1.0000 | 1.0002909 | 3191.696 | normal | 4207.057 | 2013.040 |
sexmale | 348.800992 | 0.9 | 277.55234 | 410.74168 | 1.0000 | 1.0000000 | 3417.024 | normal | 0.000 | 4020.192 |
flipper_length_mm_z | 660.203105 | 0.9 | 610.01272 | 712.85777 | 1.0000 | 0.9993882 | 2487.696 | normal | 0.000 | 2013.040 |
sexmale:flipper_length_mm_z | -3.144666 | 0.9 | -70.02727 | 68.50731 | 0.5285 | 0.9994223 | 2651.322 | normal | 0.000 | 2695.055 |
Lösung
Punktschätzer
Der Punktschätzer ist in der Spalte Median
in der Tabelle parameters
zu finden. Sein Wert ist:
[1] -3.144666
Hier ist die Post-Verteilung des Effekts:
|> plot() m_interaction_params
Alternative Visualisierung:
hdi(m_interaction, ci = .9) |> plot()
Breite des Intervalls
Dazu liest man die Intervallgrenzen (90% CI
) in der richtigen Zeile ab (Tabelle parameters
).
Obere Grenze: 68.5073138.
Untere Grenze: -70.0272668.
Differenz = Obere_Grenze - Untere_Grenze:
[1] 138.5346
Einheit: mm
Effektwahrscheinlichkeit
Man erkennt schon im Diagramm zum Konfidenzintervall, dass 100% des Intervalls positiv ist. Daher ist die Effektwahrscheinlichkeit auch positiv.
Man kann diesen Wert aus der Tabelle oben (Ausgabe von parameters()
) einfach in der Spalte pd
ablesen. pd
steht für probability of direction, s. Details hier.
Oder so, ist auch einfach:
<- p_direction(m_interaction) # aus Paket easystats
pd_m_interaction_params pd_m_interaction_params
Parameter | pd | Effects | Component | |
---|---|---|---|---|
1 | (Intercept) | 1.0000 | fixed | conditional |
3 | sexmale | 1.0000 | fixed | conditional |
2 | flipper_length_mm_z | 1.0000 | fixed | conditional |
4 | sexmale:flipper_length_mm_z | 0.5285 | fixed | conditional |
Und plotten ist meist hilfreich: plot(pd_m_interaction_params)
.
plot(pd_m_interaction_params)
Substanzielle Effektwahrscheinlichkeit
Die Frage ist nichts anderes als nach ROPE zu fragen.
<- rope(m_interaction, range = c(-100,+100))
rope_m_interact rope_m_interact
Parameter | CI | ROPE_low | ROPE_high | ROPE_Percentage | Effects | Component | |
---|---|---|---|---|---|---|---|
1 | (Intercept) | 0.95 | -100 | 100 | 0 | fixed | conditional |
3 | sexmale | 0.95 | -100 | 100 | 0 | fixed | conditional |
2 | flipper_length_mm_z | 0.95 | -100 | 100 | 0 | fixed | conditional |
4 | sexmale:flipper_length_mm_z | 0.95 | -100 | 100 | 1 | fixed | conditional |
plot(rope_m_interact)
Das 95%-Post-Intervall ist komplett innerhalb des ROPE.
Wir können die ROPE-Hypothese daher bestätigen.