8  Regressionsmodelle

Zum Einstieg betrachten wir zunächst einen (fiktiven) Datensatz mit lediglich fünf Fällen. Mit dem data.frame Befehl können wir einen Datensatz erstellen. Unserer hat zunächst lediglich zwei Variablen: var1 und var2

dat1 <- data.frame(id   = 1:8,
                   var1 = c(2,1,2,5,7, 8, 9,5),
                   var2 = c(2,2,1,9,7, 4,25,3),
                   educ = c(3,1,2,2,1, 3, 2,-1),
                   gend = c(2,1,1,2,1,2,1,2),
                   x    = c(2,1,2,4,1,NA,NA,NA) )
dat1
  id var1 var2 educ gend  x
1  1    2    2    3    2  2
2  2    1    2    1    1  1
3  3    2    1    2    1  2
4  4    5    9    2    2  4
5  5    7    7    1    1  1
6  6    8    4    3    2 NA
7  7    9   25    2    1 NA
8  8    5    3   -1    2 NA

8.1 Regressionsmodelle mit lm()

Regressionsmodelle in R lassen sich mit lm() erstellen. Hier geben wir das Merkmal an, dass auf der y-Achse liegt (die abhängige Variable) und nach einer ~ das Merkmal für die x-Achse (unabhängige Variable). Die Interpretation des Ergebnisses wird uns die kommenden Wochen beschäftigen.

lm(var2~ var1, data = dat1)

Call:
lm(formula = var2 ~ var1, data = dat1)

Coefficients:
(Intercept)         var1  
     -2.340        1.839  

Der Wert unter var1 gibt an, um wieviel sich die Gerade pro “Schritt nach rechts” nach oben/unten verändert. Die Gerade steigt also pro Einheit von var1 um 1.8389662. Die Ergebnisse können wir unter m1 ablegen:

m1 <- lm(var2~ var1, data = dat1)  

Mit summary() bekommen wir dann eine Regressionstabelle:

summary(m1)

Call:
lm(formula = var2 ~ var1, data = dat1)

Residuals:
   Min     1Q Median     3Q    Max 
-8.372 -3.613  0.162  2.234 10.789 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)  -2.3400     4.3454  -0.538   0.6096  
var1          1.8390     0.7727   2.380   0.0548 .
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 6.127 on 6 degrees of freedom
Multiple R-squared:  0.4856,    Adjusted R-squared:  0.3999 
F-statistic: 5.664 on 1 and 6 DF,  p-value: 0.05477

m1 enthält alle Informationen zum Modell, besonders hilfreich ist $coefficients:

m1$coefficients
(Intercept)        var1 
  -2.339960    1.838966 
summary(m1)$coefficients
             Estimate Std. Error    t value   Pr(>|t|)
(Intercept) -2.339960  4.3453801 -0.5384938 0.60961706
var1         1.838966  0.7727028  2.3799139 0.05477457

Wir können uns die einzelnen Werte mit View(m1) ansehen:

Bspw. finden sich unter fitted.values die vorhergesagten Werte für jeden Fall.

8.2 Regressionsgerade und Daten visualisieren

Mit geom_smooth(method = "lm") können wir Regressionsgeraden auch in {ggplot2} darstellen:

Unser Modell mit var1 und var2 können wir so darstellen:

library(ggplot2)
ggplot(dat1, aes(x = var1, y = var2)) + 
  geom_point(size = 2) + 
  geom_smooth(method = "lm")  

Hier scheinen wir einen Ausreißer zu haben. In unserem übersichtlichen Datensatz ist der schnell gefunden. In größeren Datensätzen hilft uns geom_text():

ggplot(dat1, aes(x = var1, y = var2)) + 
  geom_point(size = 2) + 
  geom_smooth(method = "lm")  +
  geom_text(data = . %>% filter(var2 > 20), aes(y = var2+3, label = id), color = "sienna1")

Wir können nämlich einzelne geom_ auch nur für ein Subset angeben - dazu vergeben wir data = neu (übernehmen also nicht die Auswahl aus dem Haupt-Befehl ggplot()) und setzen darin einen filter(). Außerdem verschieben wir mit var2+3 das Label etwas über den Punkt.

8.2.1 Übung

8.3 Modelle nur für manche Fälle berechnen

Wenn wir jetzt das Modell nochmal berechnen wollen, haben wir zwei Möglichkeiten:

8.3.1 Neuen data.frame erstellen

Wir können in R mehrere data.frame-Objekte im Speicher halten. Also können wir leicht einen neuen data.frame erstellen, der nur die Beobachtungen mit var2 < 20 enthält und diesen dann für unseren lm()-Befehl verwenden:

dat1_u20 <- dat1 %>% filter(var2<20)
m2a <- lm(var2~ var1, data = dat1_u20)
summary(m2a)

Call:
lm(formula = var2 ~ var1, data = dat1_u20)

Residuals:
      1       2       3       4       5       6       7 
-0.4737  0.1941 -1.4737  4.5230  1.1875 -2.4803 -1.4770 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)   1.1382     1.9217   0.592    0.579
var1          0.6678     0.3877   1.722    0.146

Residual standard error: 2.555 on 5 degrees of freedom
Multiple R-squared:  0.3724,    Adjusted R-squared:  0.2469 
F-statistic: 2.967 on 1 and 5 DF,  p-value: 0.1456

8.3.2 Direkt in lm() filtern

Wir können filter()-Befehl auch direkt in das data=-Argument von lm() bauen:

m2b <- lm(var2~ var1, data = dat1 %>% filter(var2<20))
summary(m2b)

Call:
lm(formula = var2 ~ var1, data = dat1 %>% filter(var2 < 20))

Residuals:
      1       2       3       4       5       6       7 
-0.4737  0.1941 -1.4737  4.5230  1.1875 -2.4803 -1.4770 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)   1.1382     1.9217   0.592    0.579
var1          0.6678     0.3877   1.722    0.146

Residual standard error: 2.555 on 5 degrees of freedom
Multiple R-squared:  0.3724,    Adjusted R-squared:  0.2469 
F-statistic: 2.967 on 1 and 5 DF,  p-value: 0.1456

8.4 Regressionstabellen

Wenn wir diese verschiedenen Modelle jetzt vergleichen möchten, bietet sich eine Tabelle an.

Es gibt zahlreiche Alternativen zur Erstellung von Regressionstabellen, mein persönlicher Favorit ist modelsummary() aus dem gleichnamigen Paket {modelsummary}. Es kommt mit (nahezu) allen Modellarten zurecht und bietet darüber hinaus eine breite Palette an (u.a. auch Word-Output - dazu später mehr) und auch Koeffizientenplots (auch dazu kommen wir noch). Außerdem ist die Dokumentation hervorragend.

install.packages("modelsummary")
library(modelsummary)
Warning: Paket 'modelsummary' wurde unter R Version 4.2.2 erstellt
modelsummary(list(m1,m2a,m2b))
 (1)   (2)   (3)
(Intercept) -2.340 1.138 1.138
(4.345) (1.922) (1.922)
var1 1.839 0.668 0.668
(0.773) (0.388) (0.388)
Num.Obs. 8 7 7
R2 0.486 0.372 0.372
R2 Adj. 0.400 0.247 0.247
AIC 55.4 36.6 36.6
BIC 55.6 36.5 36.5
Log.Lik. -24.702 -15.321 -15.321
F 5.664 2.967 2.967
RMSE 5.31 2.16 2.16

Wir werden uns noch ein bisschen ausführlicher mit den Anpassungsmöglichkeiten für {modelsummary} befassen, hier nur schon mal zwei zentrale Optionen:

  • mit stars = T können wir uns die Signifikanz mit den gebräuchlichen Sternchen-Codes anzeigen lassen (*: p < .05 usw.)
  • mit gof_omit = "IC|RM|Log" können wir die Goodness of Fit Statistiken ausblenden die IC, RM oder Log im Namen haben (also AIC, BIC, RMSE und die LogLikelihood)
  • mit "Name" = in list() können wir Namen angeben:
modelsummary(list("m1"=m1,"m2a"=m2a,"m2b"=m2b),stars = T,gof_omit = "IC|RM|Log")
m1  m2a  m2b
(Intercept) -2.340 1.138 1.138
(4.345) (1.922) (1.922)
var1 1.839+ 0.668 0.668
(0.773) (0.388) (0.388)
Num.Obs. 8 7 7
R2 0.486 0.372 0.372
R2 Adj. 0.400 0.247 0.247
F 5.664 2.967 2.967
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001

8.4.1 Übung

8.5 Kategoriale unabhängige Variablen

Natürlich können wir auch kategoriale unabhängige Variablen in unser Modell mit aufnehmen. Dazu müssen wir aber entsprechende Variable als factor definieren - und R so mitteilen, dass die Zahlenwerte nicht numerisch zu interpretieren sind. Wenn wir educ aus unserem kleinen Beispiel betrachten - dann steht 1 für einen grundlegenden Bildungsabschluss, 2 für einen mittleren und 3 für einen hohen Bildungsabschluss.

dat1
  id var1 var2 educ gend  x
1  1    2    2    3    2  2
2  2    1    2    1    1  1
3  3    2    1    2    1  2
4  4    5    9    2    2  4
5  5    7    7    1    1  1
6  6    8    4    3    2 NA
7  7    9   25    2    1 NA
8  8    5    3   -1    2 NA
m3 <- lm(var2~factor(educ), dat1)
summary(m3)

Call:
lm(formula = var2 ~ factor(educ), data = dat1)

Residuals:
         1          2          3          4          5          6          7 
-1.000e+00 -2.500e+00 -1.067e+01 -2.667e+00  2.500e+00  1.000e+00  1.333e+01 
         8 
-2.387e-15 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)
(Intercept)    3.000e+00  8.848e+00   0.339    0.752
factor(educ)1  1.500e+00  1.084e+01   0.138    0.897
factor(educ)2  8.667e+00  1.022e+01   0.848    0.444
factor(educ)3 -1.632e-15  1.084e+01   0.000    1.000

Residual standard error: 8.848 on 4 degrees of freedom
Multiple R-squared:  0.2848,    Adjusted R-squared:  -0.2516 
F-statistic: 0.531 on 3 and 4 DF,  p-value: 0.685

Noch schöner ist das aber natürlich, wenn wir educ vorher labeln:

dat1$ed_fct <- factor(dat1$educ, levels = 1:3,
                        labels = c("basic","medium","high"))
dat1
  id var1 var2 educ gend  x ed_fct
1  1    2    2    3    2  2   high
2  2    1    2    1    1  1  basic
3  3    2    1    2    1  2 medium
4  4    5    9    2    2  4 medium
5  5    7    7    1    1  1  basic
6  6    8    4    3    2 NA   high
7  7    9   25    2    1 NA medium
8  8    5    3   -1    2 NA   <NA>

Dann verwenden den factor im Regressionsbefehl:

m3 <- lm(var2 ~ ed_fct, dat1)
summary(m3)

Call:
lm(formula = var2 ~ ed_fct, data = dat1)

Residuals:
      1       2       3       4       5       6       7 
 -1.000  -2.500 -10.667  -2.667   2.500   1.000  13.333 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)
(Intercept)     4.500      6.257   0.719    0.512
ed_fctmedium    7.167      8.077   0.887    0.425
ed_fcthigh     -1.500      8.848  -0.170    0.874

Residual standard error: 8.848 on 4 degrees of freedom
  (1 Beobachtung als fehlend gelöscht)
Multiple R-squared:  0.2594,    Adjusted R-squared:  -0.1109 
F-statistic: 0.7005 on 2 and 4 DF,  p-value: 0.5485
  • Im Vergleich zu educ = basic ist der vorhergesagte Wert für var2 bei educ = medium um 7.17 höher.

  • Im Vergleich zu educ = basic ist der vorhergesagte Wert für var2 bei educ = high um -1.5 höher.

Wir können die Referenzkategorie auch ändern:

dat1$ed_fct <- relevel(dat1$ed_fct,ref = "medium")
m3b <- lm(var2 ~ ed_fct, dat1)
summary(m3b)

Call:
lm(formula = var2 ~ ed_fct, data = dat1)

Residuals:
      1       2       3       4       5       6       7 
 -1.000  -2.500 -10.667  -2.667   2.500   1.000  13.333 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)   11.667      5.109   2.284   0.0844 .
ed_fctbasic   -7.167      8.077  -0.887   0.4251  
ed_fcthigh    -8.667      8.077  -1.073   0.3437  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 8.848 on 4 degrees of freedom
  (1 Beobachtung als fehlend gelöscht)
Multiple R-squared:  0.2594,    Adjusted R-squared:  -0.1109 
F-statistic: 0.7005 on 2 and 4 DF,  p-value: 0.5485
  • Im Vergleich zu educ = medium ist der vorhergesagte Wert für var2 bei educ = basic um 7.17 niedriger.

  • Im Vergleich zu educ = medium ist der vorhergesagte Wert für var2 bei educ = high um 8.67 niedriger.

8.5.1 Übung

8.6 Mehre unabhängige Variablen

Um mehrere unabhängige Variablen in unser Regressionsmodellen aufzunehmen, geben wir sie mit + an:

m4 <- lm(var2 ~ ed_fct  + var1, dat1)
summary(m4)

Call:
lm(formula = var2 ~ ed_fct + var1, data = dat1)

Residuals:
     1      2      3      4      5      6      7 
 4.258  2.758 -4.824 -2.082 -2.758 -4.258  6.907 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)   2.3187     5.8227   0.398    0.717
ed_fctbasic  -4.8297     6.0381  -0.800    0.482
ed_fcthigh   -8.0824     5.9411  -1.360    0.267
var1          1.7527     0.8347   2.100    0.127

Residual standard error: 6.501 on 3 degrees of freedom
  (1 Beobachtung als fehlend gelöscht)
Multiple R-squared:  0.7002,    Adjusted R-squared:  0.4003 
F-statistic: 2.335 on 3 and 3 DF,  p-value: 0.2521

8.7 Koeffizientenplots

Neben Regressionstabellen stellt {modelsummary} auch die Funktion modelplot() zur Verfügung, mit denen einfach ein Koeffizientenplot aus einem oder mehreren Modellen erstellt werden kann:

modelplot(m4)

Für einen Modellvergleich geben wir einfach die Modelle in einer named list an, außerdem können wir mit den üblichen {ggplot2}-Befehlen die Grafik weiter anpassen:

modelplot(list("Modell 1"=m1,
               "Modell 4"=m4))

Mit coef_map können wir Labels für die Koeffizienten vergeben ((Intercept) bekommt keinen Namen und wird daher weggelassen:

modelplot(list("Modell 1"=m1,
               "Modell 4"=m4),
          coef_map = c("var1" = "Name für var1",
                       "ed_fcthigh"  = "Höhere Bildung",
                       "ed_fctbasic" = "Grundlegende Bildung"
                          ))

Außerdem können wir mit den üblichen {ggplot2}-Befehlen die Grafik weiter anpassen:

modelplot(list("Modell 1"=m1,
               "Modell 4"=m4),
          coef_map = c("var1" = "Name für var1",
                       "ed_fcthigh"  = "Höhere Bildung",
                       "ed_fctbasic" = "Grundlegende\nBildung")) + # \n fügt einen Zeilenumbruch ein
  geom_vline(aes(xintercept = 0), linetype = "dashed", color = "grey40") +  # 0-Linie einfügen
  scale_color_manual(values = c("orange","navy")) +
  theme_minimal(base_size = 15,base_family = "mono") 

Mit {broom} können wir auch einen data.frame aus den Regressionsergebnissen erstellen und den ggplot ganz selbst erstellen - siehe Anhang.

8.7.1 Übung

8.8 Übungen

8.8.1 Übung 1: Regression

Verwenden Sie folgenden Subdatensatz der ETB2018:

etb18 <- haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta")
etb_reg1 <- etb18 %>% filter(F518_SUF < 99990,intnr< 200000)
  • Erstellen Sie ein Objekt mod1 mit einem linearen Regressionsmodell (lm) mit F518_SUF (Monatsbrutto in EUR) als abhängiger und az (Arbeitszeit in Stunden) als unabhängiger Variable! (siehe hier)
  • Betrachten Sie Ergebnisse mod1 - was können Sie zum Zusammenhang zwischen F518_SUF und az erkennen?
  • Visualisieren Sie Ihr Regressionsmodell mit {ggplot2}.
  • Sehen Sie Ausreißer im Scatterplot? Markieren Sie diese mit Hilfe der Variable intnr und geom_text().

8.8.2 Übung 2

  • Erstellen Sie ein lm()-Modell mod2, welches nur auf den Beobachtungen mit einem Monatseinkommen unter 20.000 EUR beruht.
  • Erstellen Sie eine Regressionstabelle, welche diese neue Modell mod2 neben das Modell mod1 aus Übung 1 stellt.

8.8.3 Übung 3: kat. UVs

  • Erstellen Sie ein Regressionsmodell mit de Einkommen der Befragen (F518_SUF) als abhängiger und dem Ausbildungsabschluss der Befragten m1202 als unabhängiger Variable:
var . -1 1 2 3 4
m1202 Höchster Ausbildungsabschluss keine Angabe Ohne Berufsabschluss duale o. schulische Berufsausbildung/einf.,mittl. Beamte Aufstiegsfortbildung (Meister, Techniker, kfm. AFB u.ä.) Fachhochschule, Universität/ geh., höhere Beamte
  • Achten Sie darauf, dass m1202 als factor definiert ist. Vergeben Sie für die Levels 1-4 die Labels ohne, dual/schulisch, Aufstieg, FH/Uni und legen sie den factor als Variable m1202_fct in Ihrem data.frame ab - siehe Code-Hilfe unten:
Code
etb_reg1$m1202_fct <-  factor(etb_reg1$m1202,levels = 1:4, labels = c("ohne","dual","Aufstieg","FH/Uni"))
  • Erstellen Sie das Regressionsmodell mit dieser neuen factor-Variable für m1202 als unabhängiger Variablen.
  • Ändern Sie die Referenzkategorie auf die Ausprägung Aufstiegsfortbildung (m1202 = 3) und schätzen Sie das Modell erneut.

8.8.4 Übung 4: mehrere UVs & Koeffizientenplot

  • Passen Sie das lm()-Modell mod1 (mit allen Fällen aus etb_reg1) so an, dass neben der Arbeitszeit zusätzlich die Ausbildungsniveau (m1202) als unabhängige Variable mit aufgenommen werden.
  • Erstellen Sie auch eine grafische Gegenüberstellung der beiden Modelle mit und ohne das Ausbildungsniveau.

8.9 Anhang

dat1 <- dat1 %>% select(-matches("compl"))

8.9.1 Vorhergesagte Werte

Die vorhergesagten Werte von lm() finden sich unter $fitted.values:

m1$fitted.values
        1         2         3         4         5         6         7         8 
 1.337972 -0.500994  1.337972  6.854871 10.532803 12.371769 14.210736  6.854871 

Diese vorhergesagten Werte entsprechen einfach der Summe aus dem Wert unter Intercept und dem Wert unter var1 multipliziert mit dem jeweiligen Wert für var1.

m1

Call:
lm(formula = var2 ~ var1, data = dat1)

Coefficients:
(Intercept)         var1  
     -2.340        1.839  

Für die erste Zeile aus dat1 ergibt sich also m1 folgender vorhergesagter Wert: 2.1351+0.5811*1=2.7162

Die Werte unter fitted.values folgen der Reihenfolge im Datensatz, sodass wir sie einfach als neue Spalte in dat1 ablegen können:

dat1$lm_vorhersagen <- m1$fitted.values
dat1
  id var1 var2 educ gend  x ed_fct lm_vorhersagen
1  1    2    2    3    2  2   high       1.337972
2  2    1    2    1    1  1  basic      -0.500994
3  3    2    1    2    1  2 medium       1.337972
4  4    5    9    2    2  4 medium       6.854871
5  5    7    7    1    1  1  basic      10.532803
6  6    8    4    3    2 NA   high      12.371769
7  7    9   25    2    1 NA medium      14.210736
8  8    5    3   -1    2 NA   <NA>       6.854871

Die Grafik zeigt wie Vorhersagen auf Basis von m1 aussehen: Sie entsprechen den Werten auf der blauen Geraden (der sog. Regressionsgeraden) an den jeweiligen Stellen für var1.

Code
ggplot(dat1, aes(x = var1, y = var2)) +
  geom_point(size = 3) +      
  geom_smooth(method = "lm", color = "darkblue" , se = FALSE,size =.65) +
  geom_point(aes(x = var1, y = lm_vorhersagen), color = "dodgerblue3", size = 3) +
  expand_limits(x = c(0,8),y=c(0,8)) 

8.9.2 Residuen

Die hellblauen Punkte (also die Vorhersagen von m1) liegen in der Nähe der tatsächlichen Punkte. Trotzdem sind auch die hellblauen Punkte nicht deckungsgleich mit den tatsächlichen Werten. Diese Abweichungen zwischen den vorhergesagten und tatsächlichen Werten werden als Residuen bezeichnet:

\[Residuum = beobachteter\, Wert \; - \; vorhergesagter\,Wert\]

\[\varepsilon_{\text{i}} = \text{y}_{i} - \hat{y}_{i}\]

Wir können diese per Hand berechnen als Differenz zwischen dem tatsächlichen und dem vorhergesagten Wert oder einfach unter m1$residuals aufrufen:

m1$residuals
         1          2          3          4          5          6          7 
 0.6620278  2.5009940 -0.3379722  2.1451292 -3.5328032 -8.3717694 10.7892644 
         8 
-3.8548708 

Auch die Residuen für lm können wir in dat1 ablegen:

dat1$lm_residuen <- m1$residuals
dat1
  id var1 var2 educ gend  x ed_fct lm_vorhersagen lm_residuen
1  1    2    2    3    2  2   high       1.337972   0.6620278
2  2    1    2    1    1  1  basic      -0.500994   2.5009940
3  3    2    1    2    1  2 medium       1.337972  -0.3379722
4  4    5    9    2    2  4 medium       6.854871   2.1451292
5  5    7    7    1    1  1  basic      10.532803  -3.5328032
6  6    8    4    3    2 NA   high      12.371769  -8.3717694
7  7    9   25    2    1 NA medium      14.210736  10.7892644
8  8    5    3   -1    2 NA   <NA>       6.854871  -3.8548708

Hier sind die Residuen für lm hellblau eingezeichnet:

Code
ggplot(dat1, aes(x = var1, y = var2)) + 
  geom_smooth(method = "lm", color = "darkblue" , se = FALSE,size =.65) +
  geom_segment(aes(x = var1, xend = var1, y = var2, yend = lm_vorhersagen), color = "dodgerblue3", size = .65, linetype = 1) +
  geom_point(size = 3) +
  geom_point(aes(x = var1, y = lm_vorhersagen), color = "dodgerblue3", size = 3) +
  expand_limits(x = c(0,8),y=c(0,8)) 

8.9.3 Annahmen checken

model dashboard

install.packages("performance")
library(performance)

model_test <- check_model(m4)
plot(model_test)

8.9.4 Test auf Normalverteilung der Residuen

Grafische Überprüfung: Q-Q-Plot

library(ggfortify)
autoplot(m1,which = 2)

Überprüfen lässt sich die NV-Annahme mit dem Shapiro-Wilk-Test & shapiro.test(). Dieser testet die \(H_0\): “Die Residuen sind normalverteilt” gegen die \(H_A\): “Die Residuen weichen signifikant von der Normalverteilung ab”

shapiro.test(m1$residuals) 

    Shapiro-Wilk normality test

data:  m1$residuals
W = 0.95346, p-value = 0.746

8.9.5 Test auf Homoskedastizität

Homoskedastizität ist gegeben, wenn die vorhergesagten Werte über den kompletten Wertebereich (ungefähr) gleich weit von den tatsächlichen Werten (m1\$fitted.values) entfernt sind. Auch hier gibt es eine graphische Überprüfungsmethode sowie einen Test. Zur graphischen Überprüfung werden die vorhergesagten Werten und die Residuen als Scatterplot dargestellt. Auch hier hilft uns autoplot():

autoplot(m1, which = 1)

Der dazugehörige Test ist der Breusch-Pagan-Test. Dieser testet die \(H_0\) “Homoskedastizität” gegen die \(H_A\) “Heteroskedastizität”, der p-Wert gibt also an mit welcher Irrtumswahrscheinlichkeit wir die Homoskedastizitäts-Annahme verwerfen müssen. In R können wir dafür bptest aus dem Paket lmtest verwenden:

install.packages("lmtest")
library(lmtest)
Warning: Paket 'zoo' wurde unter R Version 4.2.2 erstellt
bptest(m3)

    studentized Breusch-Pagan test

data:  m3
BP = 3.6069, df = 2, p-value = 0.1647

8.9.6 Test auf Multikollinearität

install.packages("car")
# library(car)
etb18x <- haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta",n_max = 300)  %>% filter(F518_SUF < 99998, zpalter < 100)
mox <- lm(F518_SUF ~ zpalter + az,data=etb18x)
car::vif(mox)
 zpalter       az 
1.000688 1.000688 

Interpretation:

  • Ein verbreiteter Schwellenwert des VIF beträgt 10,00. Werte des VIF über 10 deuten auf ein schwerwiegendes Multikollinearitätsproblem, oftmals werden Gegenmaßnahmen schon ab einem strikteren Grenzwert von ca. 5,00 empfohlen. Im konkreten Beispiel ist für alle UVs also nach beiden Grenzwerten alles in Ordnung.
  • Beim Vorliegen von Mulitkollinearität gibt es mehrere Möglichkeiten, das zu beheben: Wir können eine oder mehrere unabh. Variablen aus dem Modell ausschließen. Das ist letztlich eine inhaltliche Frage und kann nicht mit einem Standardrezept gelöst werden. Alternativ können wir die kollinearen unabh. Variablen zu Indexvariablen zusammenfassen. Wir würden also einen gemeinsamen Index, bspw. der Mittelwert über die jeweiligen unabh. Variablen, erstellen.

8.9.7 Regressionsmodelle vergleichen

Mit dem Paket {performance} können wir auch einen umfassenden Modellvergleich bekommen:

install.packages("performance")
library(performance)
compare_performance(m1,m4,metrics = c("R2","R2_adj"))
Warning: When comparing models, please note that probably not all models were fit
  from same data.
# Comparison of Model Performance Indices

Name | Model |    R2 | R2 (adj.)
--------------------------------
m1   |    lm | 0.486 |     0.400
m4   |    lm | 0.700 |     0.400

8.9.8 Individuellere Koeffizientenplots mit {broom}

modelplot() bietet eine schnelle Art, Koeffizientenplots zu erstellen, allerdings verwende ich häufig {broom}. Mit broom::tidy(..., conf.int = TRUE) bekommen wir einen data.frame mit den Ergebnissen des Regressionsmodells, die wir bspw. in einem {ggplot2} weiterverarbeiten können - wenn uns die Standardlösung von modelplot() nicht weiterhilft/gefällt:

library(broom) ## schon geladen als Teil des tidyverse
Warning: Paket 'broom' wurde unter R Version 4.2.2 erstellt
tidy(m3, conf.int = TRUE)
# A tibble: 3 × 7
  term         estimate std.error statistic p.value conf.low conf.high
  <chr>           <dbl>     <dbl>     <dbl>   <dbl>    <dbl>     <dbl>
1 (Intercept)      4.5       6.26     0.719   0.512    -12.9      21.9
2 ed_fctmedium     7.17      8.08     0.887   0.425    -15.3      29.6
3 ed_fcthigh      -1.5       8.85    -0.170   0.874    -26.1      23.1
tidy(m3, conf.int = TRUE) %>% 
  mutate(term = str_replace(term, "ed_fct", "Education: ")) %>% 
  ggplot(aes(y = term, x = estimate)) +
  geom_vline(aes(xintercept = 0), linetype = "dashed", color = "navy") +
  geom_errorbarh(aes(xmin = conf.low, xmax  = conf.high), height = .1) + 
  geom_point(color = "orange", shape = 17,size = 3) +
  theme_minimal(base_size = 16)