1 Einführung
Dieser Post stellt den Code zum Kapitel 3 aus ARM vor, und zwar im Tidyverse-Stil.
2 Pakete laden
library(tidyverse)
library(arm)
library(foreign)
library(modelr)
library(ggfortify)
3 Daten laden
Die Daten können hier heruntergeladen werden als Zip-Datei. Danach muss man lokal entzippen und den Pfad am eigenen Rechner nennen. Tipp: Die Datendatei in den gleichen Ordner legen wie die Rmd-Datei; das erspart Rätseln über den korrekten Pfad.
kidsiq_path <- "/Users/sebastiansaueruser/datasets/ARM_Data/child.iq/kidiq.dta"
Die Daten sind im Format der Statistik-Software Stata gespeichert (.dta
). Mit dem Paket foreign
kann man solche Daten importieren.
kidsiq <- read.dta(kidsiq_path)
kidsiq %>%
slice_head(n=5)
## kid_score mom_hs mom_iq mom_work mom_age
## 1 65 1 121.11753 4 27
## 2 98 1 89.36188 4 25
## 3 85 1 115.44316 4 27
## 4 83 1 99.44964 3 25
## 5 115 1 92.74571 4 27
4 Ein Prädiktor
4.1 lm1: Binärer Prädiktor
lm1 <- lm (kid_score ~ mom_hs, data = kidsiq)
display(lm1)
## lm(formula = kid_score ~ mom_hs, data = kidsiq)
## coef.est coef.se
## (Intercept) 77.55 2.06
## mom_hs 11.77 2.32
## ---
## n = 434, k = 2
## residual sd = 19.85, R-Squared = 0.06
4.1.1 Diagramm
kidsiq %>%
ggplot(aes(x = mom_hs, y = kid_score)) +
geom_jitter(width = 0.2) +
geom_smooth(method = "lm", se = FALSE) +
scale_x_continuous(breaks = c(0, 1))
4.1.2 Unterschied im Mittelwert
kidsiq_summary <-
kidsiq %>%
group_by(mom_hs) %>%
summarise(kid_score = mean(kid_score, na.rm = TRUE))
kidsiq_summary
## # A tibble: 2 x 2
## mom_hs kid_score
## <dbl> <dbl>
## 1 0 77.5
## 2 1 89.3
Differenz der Mittelwerte:
kidsiq_summary %>%
summarise(kid_score[1] - kid_score[2])
## # A tibble: 1 x 1
## `kid_score[1] - kid_score[2]`
## <dbl>
## 1 -11.8
Das entspricht der Steigung von lm1
:
coef(lm1)
## (Intercept) mom_hs
## 77.54839 11.77126
4.2 lm2: Ein kontinuierlicher Prädiktor
lm2 <- lm(kid_score ~ mom_iq, data = kidsiq)
display(lm2)
## lm(formula = kid_score ~ mom_iq, data = kidsiq)
## coef.est coef.se
## (Intercept) 25.80 5.92
## mom_iq 0.61 0.06
## ---
## n = 434, k = 2
## residual sd = 18.27, R-Squared = 0.20
ggplot(kidsiq) +
aes(x = mom_iq, y = kid_score) +
geom_point() +
geom_abline(intercept = 25.8, slope = 0.61, color = "blue")
Oder so:
ggplot(kidsiq) +
aes(x = mom_iq, y = kid_score) +
geom_point() +
geom_smooth(method = "lm", se = FALSE)
5 Mehrere Prädiktoren
5.1 lm3: Ohne Interaktionseffekt
lm3 <- lm(kid_score ~ mom_hs + mom_iq, data = kidsiq)
display(lm3)
## lm(formula = kid_score ~ mom_hs + mom_iq, data = kidsiq)
## coef.est coef.se
## (Intercept) 25.73 5.88
## mom_hs 5.95 2.21
## mom_iq 0.56 0.06
## ---
## n = 434, k = 3
## residual sd = 18.14, R-Squared = 0.21
kidsiq %>%
mutate(mom_hs = factor(mom_hs)) %>%
ggplot() +
aes(x = mom_iq, y = kid_score, group = mom_hs) +
geom_point() +
geom_abline(slope = 0.56, intercept = 25.73, color = "grey20") +
geom_abline(slope = 0.56, intercept = 25.73+5.95, color = "red")
5.2 lm4: Mit Interaktionseffekt
lm4 <- lm(kid_score ~ mom_hs + mom_iq + mom_hs:mom_iq, data = kidsiq)
display(lm4)
## lm(formula = kid_score ~ mom_hs + mom_iq + mom_hs:mom_iq, data = kidsiq)
## coef.est coef.se
## (Intercept) -11.48 13.76
## mom_hs 51.27 15.34
## mom_iq 0.97 0.15
## mom_hs:mom_iq -0.48 0.16
## ---
## n = 434, k = 4
## residual sd = 17.97, R-Squared = 0.23
kidsiq %>%
mutate(mom_hs = factor(mom_hs)) %>%
ggplot() +
aes(x = mom_iq, y = kid_score, group = mom_hs) +
geom_point() +
geom_abline(slope = 0.97, intercept = -11.48, color = "grey20") +
geom_abline(slope = 0.97-0.48, intercept = -11.48+51.27, color = "red")
Oder so:
kidsiq %>%
mutate(mom_hs = factor(mom_hs)) %>%
ggplot() +
aes(x = mom_iq, y = kid_score, group = mom_hs) +
geom_point() +
geom_smooth(aes(color = mom_hs),
method = "lm", se = FALSE)
Mit Verlängerung der X-Achse zum Achsenabschnitt:
kidsiq %>%
mutate(mom_hs = factor(mom_hs)) %>%
ggplot() +
aes(x = mom_iq, y = kid_score, group = mom_hs) +
geom_point() +
geom_abline(slope = 0.97, intercept = -11.48, color = "grey20") +
geom_abline(slope = 0.97-0.48, intercept = -11.48+51.27, color = "red") +
lims(x = c(0, 150), y = c(-20, 150))
6 Eingeschränkter Wertebereich
kidsiq %>%
summarise(max_mom_iq = max(mom_iq),
min_mom_iq = min(mom_iq))
## max_mom_iq min_mom_iq
## 1 138.8931 71.03741
6.1 lm5: Regressionsmodell
lm5 <-
kidsiq %>%
filter(mom_iq >= 85 & mom_iq <= 115) %>%
lm(kid_score ~ mom_iq, data = .)
display(lm5)
## lm(formula = kid_score ~ mom_iq, data = .)
## coef.est coef.se
## (Intercept) 43.37 13.22
## mom_iq 0.46 0.13
## ---
## n = 277, k = 2
## residual sd = 18.14, R-Squared = 0.04
Vergleich mit uneingeschränktem Wertebereich:
display(lm2)
## lm(formula = kid_score ~ mom_iq, data = kidsiq)
## coef.est coef.se
## (Intercept) 25.80 5.92
## mom_iq 0.61 0.06
## ---
## n = 434, k = 2
## residual sd = 18.27, R-Squared = 0.20
kidsiq %>%
filter(mom_iq >= 85 & mom_iq <= 115) %>%
ggplot() +
aes(x = mom_iq, y = kid_score) +
geom_point() +
geom_abline(intercept = 25.8, slope = 0.61, color = "blue") +
lims(x = c(70, 140))
7 Visualisierung von Ungewissheit im Model
Der Standardfehler se
ist ein Maß für unsere Ungewissheit in der Regressionsgeraden:
ggplot(kidsiq) +
aes(x = mom_iq, y = kid_score) +
geom_point() +
geom_smooth(method = "lm", se = TRUE)
7.1 Variation eines Prädiktors und anderen konstant gehalten
7.1.1 Variation von mom_iq
Und mom_hs
halten wir auf dem Mittelwert konstant:
kidsiq %>%
summarise(mean(mom_hs))
## mean(mom_hs)
## 1 0.7857143
Ohne Visualisierung der Ungewissheit des Modells, nur mit einem Prädiktor auf dem Mittelwert fixiert:
kidsiq %>%
data_grid(mom_iq = seq_range(mom_iq, n = 20)) %>%
mutate(mom_hs = 0.79) %>%
add_predictions(lm3) %>%
ggplot(aes(x = mom_iq)) +
geom_point(data = kidsiq, aes(y = kid_score)) +
geom_line(aes(y = pred), color = "red")
Oder so, jetzt auch mit Visualisierung des Standardfehlers, also mit Visualisierung der Ungewissheit des Modells:
kidsiq %>%
mutate(mom_hs = .79) %>%
ggplot(aes(x = mom_iq, y = kid_score)) +
geom_point() +
geom_smooth(method = "lm") +
labs(title = "Zusammenhang (Kovariation) von mom_iq und kid_score\nwenn die übrigen Prädiktoren konstant gehalten sind (auf dem Mittelwert)")
7.1.2 Kovariation mit mom_iq
kidsiq %>%
summarise(mean(mom_iq))
## mean(mom_iq)
## 1 100
kidsiq %>%
mutate(mom_iq = 100) %>%
ggplot(aes(x = mom_hs, y = kid_score)) +
geom_point() +
geom_smooth(method = "lm") +
labs(title = "Zusammenhang (Kovariation) von mom_hs und kid_score\nwenn die übrigen Prädiktoren konstant gehalten sind (auf dem Mittelwert)") +
scale_x_continuous(breaks = c(0, 1)) +
geom_label(data = kidsiq_summary,
aes(label = round(kid_score, 2)))
8 Annahmen der Regressionsanalyse
8.1 Additivität
\[\hat{y} = \beta_0 + \beta_1x_1 + \beta_2x_2 + \ldots\]
Bei Verletzung z.B.
8.1.1 Log-Transformation
\[y=abc \quad \leftrightarrow \quad \text{log} y = \text{log} a + \text{log} b + \text{log}\]
df <-
tibble(
x1 = 1:10,
x2 = 1:10,
x3 = 1:10,
y = x1*x2*x3)
df %>%
mutate(y_log = x1 + x2 + x3)
## # A tibble: 10 x 5
## x1 x2 x3 y y_log
## <int> <int> <int> <int> <int>
## 1 1 1 1 1 3
## 2 2 2 2 8 6
## 3 3 3 3 27 9
## 4 4 4 4 64 12
## 5 5 5 5 125 15
## 6 6 6 6 216 18
## 7 7 7 7 343 21
## 8 8 8 8 512 24
## 9 9 9 9 729 27
## 10 10 10 10 1000 30
8.1.2 Interaktionen hinzufügen
8.2 Linearität
Hier ist die Linearität verletzt:
df <-
tibble(
x = 1:10,
y1 = x^2,
y2 = 2^x)
df %>%
ggplot(aes(x = x, y = y1)) +
geom_line()
df %>%
ggplot(aes(x = x, y = y2)) +
geom_line()
Durch eine passende Transformation kann die Linearität wieder hergestellt werden:
df %>%
ggplot(aes(x = x, y = sqrt(y1))) +
geom_line()
df %>%
ggplot(aes(x = x, y = log(y2))) +
geom_line()
8.3 Visualisierung der Residen, um Verletzungen der Annahmen zu entdecken
8.4 Additivität
autoplot(lm3, which = 1)
Wenn es keine Verletzungen gibt, sollten sich die Residen ohne Muster um die \(y=0\) herum verteilen. Hier sind die Residuen für mittlere Werte etwas erhöht und and den Randbereichen etwas zu gering. Insgesamt ist die Verletzung nicht gravierend.
8.5 Linearität
SD der Residuen
kidsiq %>%
add_residuals(lm2) %>%
summarise(sd(resid))
## sd(resid)
## 1 18.24502
kidsiq %>%
add_residuals(lm2) %>%
ggplot(aes(x = mom_iq, y = resid)) +
geom_ref_line(h = c(0)) +
geom_hline(yintercept = c( -18, +18),
color = "grey60",
linetype = "dashed") +
geom_point() +
labs(title = "Residuen vs. Prädiktor",
caption = "Gestrichtelte Linien zeigen ±1SD")
Hier zeigt sich nur Rauschen: Die Residuen sind ohne erkennbares Muster um \(y=0\) herum verteilt. Es ist keine Verletzung der Linearitätsannahme erkennbar.
9 Vorhersage
Nicht ausgeführt.
10 Referenz
S. auch den Post zu ARM, Kap. 4