Machine Learning-Algorithmen verstehen: Interaktionseffekte

Lineares Regressionsmodell mit zwei Prädiktoren mit Interaktionseffekt

Machine Learning-Algorithmen zu verstehen ist eine Herausforderung. Mit dem folgenden Text möchte ich einen Beitrag dazu leisten, indem ich ein Spezialthema betrachte: Wie gehen verschiedene Machine Learning-Algorithmen mit Interaktionseffekten um?

Folgende Machine-Learning-Algorithmen werden betrachtet:

  • Lineare Regression
  • GAM = Generalized Additive Model
  • KNN = K nächste Nachbarn = k nearest neighbors
  • Ein einzelner Entscheidungsbaum (rpart)
  • Ein Random-Forest-Modell, das viele einzelne Entscheidungsbäume kombiniert

Die Daten: Boston

Wir verwenden die Boston-Daten, die in der Standard-R-Installation im MASS-Paket enthalten sind.

library(MASS)
data(Boston)
str(Boston)

Die unabhängige Variable, die wir modellieren (je nach Fragestellung: erklären oder vorhersagen) wollen, ist der Median Wohnungspreis selbstgenutzter Eigentumswohnungen in 506 Stadtteilen von Boston (Variablenname: medv). Das heißt eine Analyseeinheit („Fall“, „Beobachtung“, Zeile im Datensatz) entspricht einem Stadtteil.

Der Einfachheit halber verwenden wir nur zwei Prädiktoren = unabhängige Variablen: den Bevölkerungsanteil mit niedrigem Status in Prozent (lstat) sowie die Flusslage am Charles River (chas) mit den Ausprägungen nein (keine Flusslage) und ja (Stadtteil liegt am Fluss).

Was sind Interaktionseffekte?

Kurz gesagt: Der Einfluss einer unabhängigen Variable auf eine abhängige Variable fällt bei einer Interaktion unterschiedlich stark aus je nach Zustand einer anderen unabhängigen Variable. Grafisch kann man es sich leichter vorstellen: Wir betrachten ein Streudiagramm mit einer kontinuierlichen unabhängigen Variable auf der x-Achse und der abhängigen Variable auf der y-Achse. Als zweiter Prädiktor steht kategoriale Variable mit zwei Ausprägungen zur Verfügung. Für jede dieser Ausprägungen zeichnen wir die Regressionsgerade ein. Ohne Interaktion sieht das so aus:

Lineares Regressionsmodell mit zwei Prädiktoren ohne Interaktionseffekt
Lineares Regressionsmodell mit zwei Prädiktoren ohne Interaktionseffekt

Hier der Code dazu:

library(dplyr)
library(broom)
library(ggplot2)
library(caret)

theme_set(theme_grey(base_size = 14)) # Schriftgröße erhöhen

# Lineare Regression mit den beiden unabhängigen Variablen

Boston$chas <- recode(Boston$chas, "0" = "nein", "1" = "ja")
mod_lm <- lm(medv ~ lstat + chas, data = Boston)
summary(mod_lm)

ggplot(augment(mod_lm), aes(x = lstat, y = medv, color = chas)) +
geom_point(alpha = 0.8) +
geom_line(aes(y = .fitted), size = 1) +
labs(x = "Bevölkerungsanteil mit niedrigem Status in Prozent",
y = "Median Wohnungspreis in 1.000 USD", 
title = "Modell: lm(medv ~ lstat + chas, data = Boston)") +
scale_color_discrete(name = "Lage am Charles River?") +
theme(legend.position = "bottom")
ggsave("lm_ohne-Interaktion.png")

„Technisch“ werden die beiden Prädiktoren hier mit „+“ verknüpft. Das Modell ist additiv, die Variablen verlaufen genau parallel. Das ist keine empirische Aussage, sondern eine Modellannahme, d. h. das Modell wird rechnerisch so bestimmt, dass die Geraden parallel verlaufen müssen. Anders formuliert: Es gibt nur einen Steigungsparameter für lstat, der für die beiden Fälle Flusslage ja und nein als identisch angenommen wird. Die Flusslage wirkt sich nur im Niveau aus, nicht in der Steigung. Ist das realistisch? Um das zu prüfen, erlauben wir dem Modell, eine Interaktion zu berücksichtigen: Also eine Wechselwirkung zwischen Flusslage und Bevölkerungsanteil mit niedrigem Status. Das sieht so aus:

Lineares Regressionsmodell mit zwei Prädiktoren mit Interaktionseffekt
Lineares Regressionsmodell mit zwei Prädiktoren mit Interaktionseffekt
# Lineare Regression mit Interaktionseffekt
ggplot(Boston, aes(x = lstat, y = medv, color = chas)) +
geom_point(alpha = 0.8) +
geom_smooth(method = "lm", se = FALSE) +
labs(x = "Bevölkerungsanteil mit niedrigem Status in Prozent",
y = "Median Wohnungspreis in 1.000 USD",
title = "Modell: lm(medv ~ lstat * chas, data = Boston)") +
scale_color_discrete(name = "Lage am Charles River?") +
theme(legend.position = "bottom")
ggsave("lm_mit-Interaktion.png")

Tatsächlich verlaufen die Geraden nun nicht mehr parallel, sie schneiden sich. Inhaltlich interpretiert: In Stadtteilen mit Flusslage fällt der Wohnungspreis mit steigenden Bevölkerungsanteil mit niedrigem Status schneller als in Stadtteilen ohne Flusslage. Grafisch: Die rote Gerade fällt steiler als die türkise Gerade.

Technische Umsetzung: Siehe Modellformel in der Bildüberschrift – die Prädiktoren werden mit „*“ verknüpft. R fügt dann automatisch die sog. Haupteffekte (die beiden Prädiktoren einzeln) und den Interaktionseffekt (die Wechselwirkung = das Produkt der beiden Prädiktoren) ein. Man könnte auch länger schreiben:

lm(medv ~lstat + chas + lstat:chas)

Will man es ganz manuell machen, kann man eine neue Variable berechnen, die das Produkt der beiden Prädiktoren enthält, und diese ins Modell aufnehmen.

Interaktionen in der linearen Regression

Somit haben wir bereits Interaktionseffekte im linearen Regressionsmodell umgesetzt. Das heißt: Die lineare Regression kann Interaktionen modellieren, aber nicht automatisch. Das geschieht erst, wenn wir explizit Interaktionsterme ins Modell aufnehmen. Ausführlicher wird das Vorgehen hier beschrieben: Regressionsmodelle visualisieren in R: Mit Interaktionseffekten, 3D (ggplot2, plotly).

GAM = Generalized Additive Model

Im folgenden betrachten wir ein GAM (Generalized Additive Model; Erstellung in R mit dem caret-Paket und der Methode „gamSpline“). Es erweitert das lineare Regressionsmodell, indem es nichtlineare Kurvenverläufe ermöglicht. Dazu werden Glättungsfunktionen aus den Daten geschätzt. Eine ausführliche Beschreibung findet sich in An Introduction to Statistical Learning: with Applications in R (Springer Texts in Statistics), noch ausführlicher in dem mathe-lastigeren The Elements of Statistical Learning: Data Mining, Inference, and Prediction, Second Edition (Springer Series in Statistics).

GAM: Keine automatischen Interaktionseffekte
GAM: Keine automatischen Interaktionseffekte

Es wird schnell erkennbar, dass die Kurven parallel verlaufen. Trotz der größeren Flexibilität gegenüber dem linearen Modell sind auch hier nicht automatisch Interaktionseffekte enthalten. Sie können aber, ähnlich wie bei der linearen Regression, explizit angegeben werden. Das „A“ in GAM, „Additive“, weist uns darauf hin, dass die Kurvenverläufe parallel bleiben. Hier der Code:

# GAM = Generalized Additive Model

ctrl <- trainControl(method = "repeatedcv", number = 10, repeats = 10, verboseIter = FALSE)

Boston$chas <- recode(Boston$chas, "0" = "nein", "1" = "ja")
Boston$chas <- factor(Boston$chas)
set.seed(2018)
mod_gam <- train(medv ~ lstat + chas, method = "gamSpline", data = Boston, trControl = ctrl)
Boston$pred.gam <- predict(mod_gam)

ggplot(Boston, aes(x = lstat, color = chas)) +
geom_jitter(aes(y = medv), alpha = 0.8) +
geom_line(aes(y = pred.gam), size = 1.5) +
labs(title = "Modell: gamSpline für (medv ~ lstat + chas)",
x = "Bevölkerungsanteil mit niedrigem Status in Prozent",
y = "Median Wohnungspreis in 1.000 USD", 
caption = "Additives Modell: Kein Interaktionseffekt!") +
scale_color_discrete(name = "Lage am Charles River?") +
theme(legend.position = "bottom")
ggsave("GAM.png")
Boston$pred.gam <- NULL

KNN = K nächste Nachbarn = K nearest neighbors

KNN ist ein Modell mit einer schlichten Grundidee: Zur Modellierung eines Datenpunktes wird der Mittelwert der k nächsten Nachbarn verwendet, wobei der Wert von k vorgegeben oder mittels Kreuzvalidierung (cross validation) optimiert werden kann. (Bei einer kategorialen abhängigen Variable wird statt des Mittelwerts eine Mehrheitsentscheidung für die häufigste Kategorie verwendet.) Vorteil dieses Modells: Es ist nichtparametrisch, d. h. es muss keine Formel zur Kurvenanpassung schätzen.

KNN: Automatische Interaktionseffekte
KNN: Automatische Interaktionseffekte

Die Kurvenverläufe sind nun auffällig anders als bei der linearen Regression. Die türkise Kurve basiert auf mehr Datenpunkten und zeigt entsprechend mehr „Zacken“. Es liegt keine Modellformel zugrunde, die auf den gesamten Wertebereich anwendbar wäre. Das caret-Paket hat mittels 10facher Kreuzvalidierung mit 10 Wiederholungen als optimalen Tuning-Parameter k=9 ermittelt, d. h. jede Modellvorhersage beruht auf den Mittelwerten der neun nächsten Nachbarn.

Die Kurven verlaufen nicht parallel! Das bedeutet: Das schlichte knn-Modell stellt automatisch den Interaktionseffekt dar, ohne dass man das explizit im Modell-Aufruf vorgeben muss. Wichtig: Daten standardisieren, um Effekte unterschiedlicher Skalen auszuschließen – sonst haben Variablen mit größerem Skalenbereich bei der Bestimmung der Abstände (wer sind die nächsten Nachbarn?) einen unerwünscht größeren Einfluss. Das Standardisieren erfolgt hier bequem innerhalb der train-Funktion aus dem caret-Paket mittels pre-Processing (preProc).

Der R-Code:

# KNN = K Nearest Neighbors

set.seed(2018)
mod_knn <- train(medv ~ lstat + chas, data = Boston, trControl = ctrl,
preProc = c("center", "scale"), method = "knn")

Boston$pred.knn <- predict(mod_knn)

ggplot(Boston, aes(x = lstat, color = chas)) +
geom_jitter(aes(y = medv), alpha = 0.8) +
geom_line(aes(y = pred.knn), size = 1.5) +
labs(title = "Modell: knn für (medv ~ lstat + chas)",
x = "Bevölkerungsanteil mit niedrigem Status in Prozent",
y = "Median Wohnungspreis in 1.000 USD") +
scale_color_discrete(name = "Lage am Charles River?") +
theme(legend.position = "bottom")
ggsave("KNN.png")
Boston$pred.knn <- NULL

Ein einzelner Entscheidungsbaum (rpart)

Nun betrachten wir einen einzelnen Entscheidungsbaum, wobei wir auf den rpart-Algorithmus zurückgreifen (recursive partitioning). Entscheidungsbäume haben den Charme, sehr einfach interpretierbar zu sein – die Ergebnisse kann man auch statistischen Laien leicht vermitteln. Hier geht es uns allerdings nur um den Interaktionseffekt:

Einzelner Entscheidungsbaum: Interaktionseffekte
Einzelner Entscheidungsbaum: Interaktionseffekte

Auch hier fällt der zackige Verlauf auf, und auch hier sind die Kurven nicht parallel, d. h. wir erhalten erneut automatische Interaktionseffekte.

Mit caret wurde der Tuning-Parameter cp optimiert, der einen Kompromiss zwischen Anzahl der Verzweigungen und möglichem Overfitting (Über-Anpassung, d. h. schlechte Generalisierbarkeit auf neue Daten) regelt.

Weiterer Vorteil der Entscheidungsbäume: Sie erfordern keine vorherige Standardisierung (pre-Processing).

# Entscheidungsbaum: rpart

myGrid <- data.frame(cp = seq(from = 0.0001, to = 0.5, length.out = 20))
set.seed(2018)
rpart <- train(medv ~ lstat + chas, data = Boston,
trControl = ctrl,
method = "rpart",
tuneGrid = myGrid)

Boston$pred <- predict(rpart)

ggplot(Boston, aes(x = lstat, color = chas)) +
geom_jitter(aes(y = medv), alpha = 0.8) +
geom_line(aes(y = pred), size = 1.5) +
labs(title = "Modell: rpart für (medv ~ lstat + chas), cp mit custom grid getunt",
x = "Bevölkerungsanteil mit niedrigem Status in Prozent",
y = "Median Wohnungspreis in 1.000 USD") +
scale_color_discrete(name = "Lage am Charles River?") +
theme(legend.position = "bottom")
ggsave("rpart.png")
Boston$pred <- NULL

Random Forest

Zu guter Letzt noch ein Random Forest-Modell. Random Forests verbinden viele (z. B. 1000 oder 2000) einzelne Entscheidungsbäume, um die Vorhersage-Genauigkeit zu erhöhen. Dazu wird für jeden Baum mittels Bootstrapping eine Zufallsstichprobe aus den Daten gezogen (mit Zurücklegen, sodass die ursprüngliche Fallzahl erhalten bleibt). Die finale Vorhersage für jeden Datenpunkt resultiert aus dem Mittelwert der Vorhersagen aller Bäume.

Random Forest: Automatische Interaktionseffekte
Random Forest: Automatische Interaktionseffekte

Die Kurvenverläufe enthalten mehr „Zacken“ als beim einzelnen Entscheidungsbaum. Auch hier verlaufen die Kurven nicht parallel – das bedeutet: Auch das Random-Forest-Modell liefert automatisch Interaktionseffekte. Es ist als nichtparametrischer Ansatz (es wird keine universelle Modellformel aufgestellt und keine parametrisierte Kurvenanpassung vorgenommen) ebenso flexibel wie KNN und ein einzelner Entscheidungsbaum. Es ist weniger interpretierbar als ein einzelner Entscheidungsbaum oder die lineare Regression, liefert aber in aller Regel genauere Vorhersagen.

Der Tuning-Paramter mtry, die Anzahl der Prädiktoren, aus denen bei jeder Verzweigung ausgewählt wird, wurde hier auf den Wert 2 festgesetzt. Ein feineres Tuning wäre möglich, ähnlich wie oben beim rpart-Modell.

# Random Forest

ctrl <- trainControl(method = "cv", number = 10)
set.seed(2018)
rf <- train(medv ~ lstat + chas, data = Boston,
method = "rf",
tuneGrid = data.frame(mtry = 2),
trControl = ctrl)

Boston$pred <- predict(rf)

ggplot(Boston, aes(x = lstat, color = chas)) +
geom_jitter(aes(y = medv), alpha = 0.8) +
geom_line(aes(y = pred), size = 1) +
labs(title = "Modell: Random Forest für (medv ~ lstat + chas), mtry = 2",
x = "Bevölkerungsanteil mit niedrigem Status in Prozent",
y = "Median Wohnungspreis in 1.000 USD") +
scale_color_discrete(name = "Lage am Charles River?") +
theme(legend.position = "bottom")
ggsave("rf.png")
Boston$pred <- NULL

Fazit: Machine Learning-Algorithmen und Interaktionseffekte

Der Umgang mit Interaktionseffekten ist ein Kriterium, anhand dessen man verschiedene Machine Learning-Algorithmen vergleichen kann. Die grafischen Darstellungen helfen zu verstehen, wie die Algorithmen vorgehen. Die parametrischen Verfahren wie lineare Regression (liefert Regressionsgeraden) und GAM (liefert nichtlineare Kurvenverläufe) können Interaktionen nur dann modellieren, wenn man dies im Modellaufruf explizit vorgibt. Die nichtparametrischen Verfahren (KNN, Entscheidungsbaum, Random Forest) modellieren dank ihrer Flexibilität automatisch Interaktionseffekte, da es keine Steigungsparameter gibt, die über den gesamten Wertebereich fixiert werden.

Anbei drei Literatur-Empfehlungen. Die linken beiden sind eng verwandt – Hastie und Tibshiranie haben einige der Methoden selbst (weiter-)entwickelt (z. B. Bootstrapping, GAM). Elements ist älter und anspruchsvoller; Introduction kam später, um den Leserkreis auf nicht ganz so mathematisch versierte Kreise zu erweitern. Rechts: Max Kuhn ist der Kopf hinter dem caret-Paket; das Buch ist dank zahlreicher Code-Beispiele sehr praxisorientiert.

Man erkennt hier gut die Uneinheitlichkeint in der Begriffsverwendung. Machine Learning lese ich am häufigsten; Statistical Learning und Predictive Modeling verstehe ich weitgehend synonym, wobei ersteres auf den Bereich der Statistik verweist, auf dem viele Methoden aufbauen. Andere Methoden stammen eher aus dem Bereich Computer Science / Artificial Intelligence; in unserer spannenden Zeit wird der Werkzeugkasten aus ganz unterschiedlichen Fachbereichen gefüllt …

 

Freue mich über Kommentare!