Data Mining mit R: Zusammenhänge erkennen, Zielgruppen finden

Beim Data Mining geht es darum, Erkenntnisse aus vorhandenen Daten zu gewinnen – im Gegensatz zum Machine Learning, das darauf abzielt, zuvor traininerte Modelle auf neue Daten anzuwenden.

TL; DR: Kurze Zusammenfassung

Entscheidungsbäume sind ein mächtiges Werkzeug für Data Mining-Aufgaben. Sind sind in R leicht zu erstellen und besonders gut präsentierbar, wenn sie in interaktiven Shiny Apps zugänglich gemacht werden. Beispielcode unten sowie zum Download auf Github.

Wurden beim Untergang der Titanic Frauen und Kinder zuerst gerettet?

Nehmen wir an: Jemand beauftragt uns, mit Data Mining-Methoden herauszufinden, ob beim Untergang der Titantic der ethische Grundsatz eingehalten wurde, Frauen und Kinder zuerst zu retten. Die Vorgabe lautet: Liefere ein Ergebnis, das für den Auftraggeber, einen statistischen Laien, leicht verständlich ist – ohne Koeffizienten, p-Werte, Signifikanzintervalle, Effektstärken – kurz ohne Methoden-Kauderwelsch.

Die Wahl fällt auf die Methode „Entscheidungsbaum“:

Titanic: Wurden Frauen und Kinder zuerst gerettet?
R, Funktion rpart, Darstellung mit rpart.plot

Um das Beispiel einfach zu halten, betrachten wir lediglich vier Variablen: Als Zielvariable, ob ein Passagier ertrunken ist oder gerettet wurde; dazu drei unabhängige Variablen (Prädiktoren): Alter, Geschlecht und Passagierklasse. Die ersten beiden hängen unmittelbar mit unserer Fragestellung zusammen, während wir die Passagierklasse zur Kontrolle verwenden, da anzunehmen ist, dass sie ebenfalls eine Rolle spielt.

Oben, im Knoten [1] ist unser gesamter Datensatz enthalten (es handelt sich nicht um alle Titanic-Passagiere, sondern um einen Trainingsdatensatz, der 891 Passagiere umfasst). Insgesamt ist eine Mehrheit von 549 Passagieren ertrunken, bei 342 Geretteten.

Entscheidungsbaum mit R: rpart und rpart.plot

Den Entscheidungsbaum zu erstellen, ist in R ein Einzeiler: Wir müssen der Funktion rpart lediglich die Daten und die Modellformel übergeben, also die abhängige und die unabhängigen Variablen. Dazu geben wir als Methode „class“ an: es geht um Klassifikation, d. h. die Zielvariable ist kategorial. Entscheidungsbäume können ebenso gut auf kontinuierliche (metrische) Zielvariablen angewendet werden – dann erhält man Mittelwerte statt Gruppenzuordnungen. (Es gibt einige weitere optionale Parameter, die wir zunächst vernachlässigen.) Das sieht so aus:

library(rpart)
tree <- rpart(Survived ~ ., data = titanic, method = "class")

Das heißt wir haben uns nicht selbst um die einzelnen Verzweigungsschritte gekümmert – das macht der Algorithmus automatisch. Wie entscheidet er über Verzweigungen? Es geht um Knoten-Reinheit: Ein reiner Knoten ist ein Knoten, der entweder nur Gerettete oder nur Ertrunkene enthält. Wir wollen diese beiden Gruppen anhand der uns zur Verfügung stehenden Merkmale (Alter, Geschlecht, Passagierklasse) möglichst deutlich unterscheiden. Bei jeder Verzweigung prüft der Algorithmus, welches Merkmal die Knotenreinheit am meisten erhöht. (Mathematisch basiert das auf dem Gini-Index – siehe Dokumentation.)

In unserem Beispiel wird zuerst nach dem Geschlecht verzweigt – durchaus im Sinne unserer Fragestellung: Tatsächlich wurde eine deutliche Mehrheit der Frauen gerettet (Verzweigung nach rechts, Knoten [5], grün), während eine deutliche Mehrheit der Männer ertrank (Verzweigung nach links, Knoten [2], blau). Bleiben wir bei den Männern, so sehen wir, dass anschließend nach dem Alter verzweigt wird, und zwar an der Schwelle 7 Jahre: die wenigen kleinen Jungs unter 7 wurden überwiegend gerettet (16 vs. 8 Ertrunkene), während bei den älteren Männern eine deutliche Mehrheit ertrank.

Bei den Frauen wird auf der zweiten Ebene jedoch nach der Passagierklasse verzweigt, erst dann nach dem Alter. Nur 9 Frauen in der 1. und 2. Klasse ertranken, 161 wurden gerettet. In der dritten Klasse hingegen standen die Chancen 50/50 (bzw. 72 zu 72). Beim Alter wird zunächst die Schwelle bei 39 Jahren gezogen, erst danach bei 6 Jahren, was unserer Fragestellung näher kommt.

Ergebnis: Wurden beim Untergang der Titanic Frauen und Kinder zuerst gerettet?

Am Entscheidungsbaum können wir erkennen, dass das ethische Prinzip nur teilweise eingehalten werden konnte. Zwar überlebte ein wesentlich höherer Anteil der Frauen, und bei den Männern überlebten mehr kleine Jungs als Ältere. Andererseits spielte bei den Frauen die Passagierklasse eine größere Rolle als das Alter

Entscheidungsbäume für Data-Mining-Aufgaben: Methodische Stärken

Ich habe eine Reihe von Projekten ausschließlich mit Entscheidungsbäumen bearbeitet, mit sehr zufriedenen Auftraggebern. Die Methode bietet einige Vorteile gegenüber klassischer Statistik, neben der bereits hoffentlich deutlich gewordenen leichten Interpretierbarkeit:

  • Entscheidungsbäume ermitteln selbständig die Variablen, die die Zielgruppen am deutlichsten trennen (bzw. bei metrischer Zielgröße die deutlichsten Mittelwertsunterschiede hervorbringen). Das ist besonders hilfreich, wenn es sehr viele Prädiktoren gibt. Das erspart dem Anwender die manuelle Suche nach der „Nadel im Heuhaufen“.
  • Entscheidungsbäume ermitteln bei metrischen Prädiktoren selbständig Schwellwerte. Hier im Beispiel werden Jungs unter 7 Jahren von älteren Jugendlichen und Männern getrennt. Mit klassischer Statistik wäre es unsere Aufgabe, sinnvolle Schwellen zu finden. Ich habe etliche Projekte erlebt, bei denen vorab Gruppeneinteilungen festgelegt werden. Beispiel: Kundenzufriedenheit mit Krankenkassen, Altersgruppen 21-30 Jahre, 31-40 Jahre, 41-50 Jahre, usw. Wenn mit 35 Jahren bestimmte Vorsorgeuntersuchungen beginnen, kann es sein, dass einem Versicherten plötzlich auffällt, dass die eigene Kasse weniger Leistungen übernimmt als die seines Kollegen, und er wird plötzlich unzufrieden. Mit einer vorab definierten Altersgruppe 31-40 Jahre würde uns dieses Phänomen entgehen. Mit Entscheidungsbäumen bekommen wir Anhaltspunkte für datenbasierte Gruppeneinteilungen.
    Anderes Beispiel: Technischer Produktionsprozess, Messzeiten für die Dauer vieler einzelner Produktionsschritte. Bei welcher Zeitschwelle an einer bestimmten Stelle steigt der Ausschuss (Teile, die den Qualitätsanforderungen nicht genügen)?
  • Entscheidungsbäume fassen Gruppen von kategorialen Prädiktoren zusammen. Hier im Beispiel werden die erste und zweite Passagierklasse zusammengefasst und der dritten Klasse gegenübergestellt. Stellen wir uns wiederum eine komplexere Anwendung vor: Kundenzufriedenheit eines Telekommunikations-Unternehmens, mit 40 verschiedenen Vertragsarten. Mit klassischer Statistik würden wir für jede Vertragsart die Zufriedenheit ermitteln, dann auf- oder absteigend sortieren und über vielen einzelnen Werten brüten. Der Entscheidungsbaum kann uns auf einen Blick sagen: Es gibt zwei Kundengruppen; bei 35 Vertragsarten sieht es gut aus (hohe Kundenzufriedenheit), und die folgenden fünf Vertragsarten mit schlechter Kundenzufriedenheit solltet Ihr Euch genauer ansehen.
    Passiert das weiter unten im Baum, wäre es noch aufwändiger, das manuell selbst herauszufinden. Etwa, wenn sich die problematischen Vertragsarten nach Geschlecht, Altersgruppen oder anderen Merkmalen unterscheiden.
  • Entscheidungsbäume können besser mit Fehlwerten umgehen als viele andere statistische Methoden. Im Beispiel oben werden Passagiere mit Fehlwerten beim Alter bei Verzweigungen nach Alter nicht berücksichtigt und fallen aus dem Modell heraus. In Knoten [7] und [8] gehen etliche Damen der dritten Klasse verloren, für die kein Alter vorliegt. Optional kann man bei Fehlwerten bei einem Prädiktor Ersatzvariablen für die Verzweigungen verwenden (engl. surrogates). Andere Möglichkeit: Fehlwerte als eigene Gruppe codieren.

Data Mining: Zielgruppen finden mit Entscheidungsbäumen

Anders als etwa bei Clusteranalysen liefern Entscheidungsbäume eine klare Zielgruppenbeschreibung gleich mit: Jede Verzweigung ist als Zielgruppenmerkmal beschreibbar.

Anwendungsbeispiel: Ein Kommunikationsdienstleister plant eine Werbekampagne und analysiert dafür Daten früherer Kampagnen. Ein Entscheidungsbaum kann Aussagen liefern wie: Frauen zwischen 24 und 35 Jahren mit diesem Vertragstyp und einem monatlichen Datenvolumen in diesem Bereich haben wesentlich häufiger auf eine vergleichbare frühere Marketingaktion angesprochen als andere Kunden. Bei dieser Zielgruppe ist das Budget am besten angelegt.

R und Shiny: Interaktive App – Szenarien vergleichen

Wer Ergebnisse von Datenanalyse präsentiert, sei es im eigenen Unternehmen gegenüber Mitarbeitern / Abteilungsleitern / Chefs, sei es im Kundengespräch, muss oft Fragen zu verschiedenen Szenarien beantworten: Was wäre, wenn? Auch dazu sind Entscheidungsbäume gut geeignet. Man kann an verschiedenen Stellschrauben drehen, um Entscheidungsbäume zu beeinflussen: z. B. durch Hinzunahme weiterer Prädiktoren oder durch Ausschluss bestimmter Prädiktoren; durch Einstellungen, die die Baumtiefe verändern (Mindest-Fallzahl je Knoten, Mindestschwelle „Verbesserung der Knotenreinheit“ für weitere Verzweigungen; hier: Komplexitätsparameter cp); man kann auch beeinflussen, welche Variablen für Verzweigungen präferiert werden, und so bestimmte Verzweigungen auf der ersten Ebene „erzwingen“ (technisch geht das mit einem „Kostenvektor“).

Data Mining mit R; Titanic: Frauen und Kinder zuerst? Interaktive Shiny App mit R 3.6.1; RStudio 1.2.1335; shiny 1.3.2; rpart 4.1.-15; rpart.plot 3.0.7
R-Code unter https://github.com/fjodor/ShinyApps: shinyTitanic.R

Solche Szenarien kann man vorbereiten, indem man vorab eine Reihe von Bäumen erstellt und als Grafiken bereit hält. Elegant ist es, sie in einem aus R heraus vollautomatisch erstellten Markdown-Dokument abzubilden – das kann eine HTML- oder Powerpoint-Präsentation sein oder ein Bericht in Word, HTML oder PDF.

Noch eleganter ist es, eine interaktive App zu bauen. Im Bild oben habe ich Ersatzvariablen freigegeben, um Verzweigungen vorzunehmen, wenn das Alter nicht bekannt ist. Den Unterschied sieht man in den Knoten 3 und 8.

Damit die App interaktiv funktioniert, muss sie live auf R zugreifen. Das kann lokal auf dem eigenen Rechner sein, oder auf einer Webseite, die dann eine serverbasierte R-Installation enthalten muss. Mein Provider bietet das leider nicht an … RStudio bietet Webspace für Shiny Apps, je nach Last kostenlos oder mit abgestuften Kosten. Der R-Code der App steht auf Github zum Download bereit (shinyTitanic.R) sowie unten, sodass jeder Leser, der R installiert hat, sie (zumindest lokal) anwenden kann.

So kann man live Szenarien durchspielen, ohne in einer Präsentation oder einem Dokument / einem Ordner blättern zu müssen oder sagen zu müssen: „Das könnte ich noch nachliefern“. Hier noch eine Variante, bei der zuerst nach Alter verzweigt wird.

Data Mining mit R; Titanic: Frauen und Kinder zuerst? Erste Verzweigung nach Alter
Interaktive Shiny App mit R 3.6.1; RStudio 1.2.1335; shiny 1.3.2; rpart 4.1.-15; rpart.plot 3.0.7. R-Code unter https://github.com/fjodor/ShinyApps: shinyTitanic.R

Entscheidungsbäume (rpart) visualisieren mit rpart.plot

Zur Darstellung des Entscheidungsbaum setze ich das rpart.plot-Paket ein. In den ansonsten sehr empfehlenswerten Lehrbüchern An Introduction to Statistical Learning: with Applications in R (Springer Texts in Statistics Book 103) (English Edition) und The Elements of Statistical Learning: Data Mining, Inference, and Prediction, Second Edition (Springer Series in Statistics) werden die Bäume wie simple Strichmännchen dargestellt, mit äußert spärlichen Infos zu den einzelnen Knoten. Mit rpart.plot und der prp-Funktion hat man sehr viele Einstellmöglichkeiten, siehe:

# install.packages("rpart.plot")     # einmalig installieren
library(rpart.plot)
?prp

Hier der R-Code der App:

library(shiny)
library(titanic)
library(tidyverse)
library(rpart)
library(rpart.plot)
titanic <- titanic_train %>% 
     # select(Survived, Pclass, Sex, Age) %>% 
     select(-PassengerId, -Name) %>% 
     rename(Alter = Age, Passagierklasse = Pclass, 
            Geschlecht = Sex) %>% 
     mutate(Survived = factor(Survived),
            Survived = fct_recode(Survived,
                       Ertrunken = "0", Gerettet = "1"),
            Geschlecht = fct_recode(Geschlecht, 
                         weiblich = "female", männlich = "male"),
            Passagierklasse = factor(Passagierklasse),
            Passagierklasse = fct_recode(Passagierklasse,
            1. Klasse = "1", 2. Klasse = "2", 3. Klasse = "3"),
            Alter = round(Alter))

ui <- fluidPage(
 titlePanel("Data Mining mit R: Titanic"),
 sidebarLayout(
     sidebarPanel(
         checkboxInput(inputId = "surrogate",
            label = "Fehlwerte: Ersatzvariable verwenden")
         radioButtons(inputId = "firstsplit",
            label = "Erste Verzweigung:",
            choices = c("Algorithmus entscheidet",
                      "Alter", "Passagierklasse"))
         ),
     mainPanel(
         plotOutput(outputId = "titanicPlot",
                    width = "100%", height = "750px")
     )
 )
)
 server <- function(input, output) {
 output$titanicPlot <- renderPlot({
     cost <- case_when(
         input$firstsplit == "Algorithmus entscheidet"
                  ~ c(rep(1, 3), rep(100, 6)),
         input$firstsplit == "Alter"
                  ~ c(1, 1, 0.01, rep(100, 6)),
         input$firstsplit == "Passagierklasse"
                  ~ c(0.01, 1, 1, rep(100, 6))     )

     tree <- rpart(Survived ~ ., data = titanic, method = "class",
             usesurrogate = ifelse(isTRUE(input$surrogate), 1, 0),
                   cost = cost, cp = 0.01, maxdepth = 4)
     prp(tree, 
            main = "Titanic: Wurden Frauen und Kinder
                    zuerst gerettet?",
           type = 4,
           extra = 1,  # extra: 1 = number of obs per node
           prefix = "Ertrunken / Gerettet\nMehrheit: ",
           xsep = " / ",
           faclen = 0,   # do not abbreviate factor levels
           nn = FALSE,   # display the node numbers
           ni = TRUE,    # display node indices
           yesno = 2,    # write yes / no at every split
           roundint = TRUE,
           # ycompress = FALSE,
           yes.text = "ja",
           no.text = "nein",
           facsep = ", ",
           varlen = 0,   # don't abbreviate variable names
           shadow.col = "gray",
           split.prefix = " ",
           split.suffix = " ",
           # col = cols, border.col = cols,
           # use for categorical outcomes, predefine colours
           box.palette = "BuGn",
           # box.palette = "auto",
           split.box.col = "lightgray",
           split.border.col = "darkgray",
           split.round = .5,
           cex = NULL)   # text size })
 }

shinyApp(ui = ui, server = server)

Entscheidungsbäume und Machine Learning

Ein einzelner Entscheidungsbaum liefert meist schlechte Vorhersagen in Machine Learning-Anwendungen. Dafür ist die Methode (meist – das ist datenabhängig) zu grob: alle Beobachtungen im selben Knoten erhalten dieselbe Vorhersage. Baumbasierte Methoden sind jedoch im Machine Learning sehr erfolgreich. Der „Trick“ besteht darin, viele Bäume zu kombinieren, um die Vorhersagen zu verfeinern. Das geschieht unter anderem beim Bagging, bei Random-Forest-Modellen und mit Boosting-Algorithmen.

Freue mich über Kommentare!