Auf Grund der immer transparenter werdenden Preise sind viele Märkte, beispielsweise in der Energie oder der Telekommunikation, hart umkämpft. Kunden können quasi in Echtzeit Verträge kündigen und zu anderen Anbietern wechseln. Da die Wiedergewinnung bereits gewechselter Kunden häufig mit erheblichem finanziellem Aufwand verbunden ist und selten gelingt, ist es für Unternehmen von großer Bedeutung, wechselwillige Kunden bereits vor einem möglichen Wechsel zu identifizieren und zu kontaktieren. Die Größe des Kundenstamms erlaubt jedoch oft keine individuelle und zielgerichtete Kampagne. Maßnahmen nach dem Gießkannenprinzip verpuffen oft oder zeigen gar einen negativen Effekt.

Doch die vermeidlich einfache Fragestellung „Welche meiner Kunden haben eine hohe Wahrscheinlichkeit zu kündigen?“ ist nicht so trivial wie sie zunächst aussieht. So klingen die Fragen „Mit welcher Wahrscheinlichkeit kündigt der Kunde im nächsten Jahr?“ und „Wann kündigt mein Kunde?“ zunächst ziemlich identisch – die mathematische Modellierung und insbesondere die Auswahl der Daten und Verfahren ist jedoch eine gänzlich andere.

Auch die Definition eines „Kündigers“ kann variieren: Während bei manchen Unternehmen ein Kunde ein Kündiger ist sobald eine schriftliche Kündigung vorliegt, definieren andere Unternehmen ihre Kündiger als Kunden, die seit einem bestimmten Zeitraum keine Leistungen mehr bezogen haben. Im Vorfeld der Analyse muss daher genau durchdacht werden, welche Fragestellung beantwortet werden soll, wie die Rahmenbedingungen des Prozesses definiert sind und welche Maßnahmen aus dem Ergebnis abgeleitet werden sollen, um den größtmöglichen Mehrwert aus der Analyse ziehen zu können.

Bei der Modellierung von Churn Problemen müssen verschiedene Fallstricke im Auge behalten werden. Neben einer genauen Definition der Fragestellung ist die Kenntnis über die Zensiertheit der Daten elementar. Daher soll an dieser Stelle kurz auf diese Thematik eingegangen werden.

Laden von benötigten Paketen

Für die folgenden Grafiken werden einige Pakete benötigt. Diese werden zunächst installiert.

Code
#install.packages("pacman")
pacman::p_load(ggplot2, data.table, dplyr, tidyquant, DT, IRdisplay, kableExtra, latex2exp)

Die Quellcodes für alle Plots können durch Klick auf Code angezeigt werden.

Zensierte Daten

Linkszensierung

Im Umfeld der Churn-Analyse hat man es häufig mit sogenannten zensierten Daten zu tun. Sind die Daten erst ab einem bestimmten Zeitpunkt verfügbar, an dem einige der Kunden aber bereits Leistungen bezogen haben, so spricht man von linkszensierten Daten. Diesen Fall findet man beispielsweise häufig im Bereich der Printmedien: Während einige Kunden schon seit Jahrzehnten Zeitungen abonniert haben, starten die Datenaufzeichnungen erst vor wenigen Jahren. Es ist somit nicht mehr genau bestimmbar, wann das Einstiegsdatum des Kunden war.

Ein Beispiel für die Linkszensierung ist in der folgenden Abbildung gezeigt. Die Grafik sowie alle weiteren Grafiken werden mit R und dem Package ggplot2 erstellt.

Code
data_leftcensored <- data.table(
    Kunde = c("A", "B", "C", "D"), 
    von = c(-4, -5, -5, -4), 
    bis = -3
)
data_leftcensored_new <- data.table(
    Kunde = c("A", "B", "C", "D", "E"), 
    von = c(-3, -3, -3, -3, -2), 
    bis = c(-1, 0, -1, -2, 0)
)
options(repr.plot.height=5, repr.plot.width = 10)
ggplot() + 
    geom_point(data = data_leftcensored %>% 
               melt(id.vars = "Kunde") %>% 
               filter(!(variable == "bis" & value >= 0)), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_leftcensored, 
                 aes(x = von,
                     xend = bis, 
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 2) +
    geom_vline(xintercept = c(-3,0)) +
    geom_point(data = data_leftcensored_new %>% 
               melt(id.vars = "Kunde") %>% 
               filter(variable == "bis"), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_leftcensored_new,
                 aes(x = von,
                     xend = bis, 
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 1) +
    xlab("Zeitpunkt") +
    ggtitle("Linkszensierung") +
    coord_cartesian(xlim = c(-5, 1)) +
    theme_classic() +
    annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
    annotate("text", x = -3.1, y = 4.5, label = "Start der Daten", angle = 90) +
    theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))

png

Im gezeigten Beispiel ist beispielsweise nicht bekannt, dass Kunde seit Zeitpunkt Kunde ist. Lediglich der Status “aktiv” des Kunden zum Zeitpunkt ist bekannt, da er zum Zeitpunkt der Datenaufzeichnung bereits Bestandskunde war.

Rechtszensierung

Sind die Daten auf der rechten Seite zensiert, so spricht man von rechtszensierten Daten. Mit diesem Fall ist man im Bereich der Churn Analyse stets konfrontiert. Bei aktuell aktiven Kunden (Bestandskunden) kennt man den Zeitpunkt der Kündigung nicht. Genau diese Kunden sind das Ziel der Analyse - es sollen Aussagen über das Kündigungsverhalten über die Bestandskunden getätigt werden.

Im folgenden Beispiel sind für Kunde , und die Kündigungszeitpunkte noch nicht bekannt. Ihr Lebenszyklus ist also rechtszensiert.

Code
data_rightcensored <- data.table(
    Kunde = c("A", "B", "C", "D", "E", "F"), 
    von = c(-4, -3, -1, -5, -5, -4), 
    bis = c(0, -1, 0, 0, -2, -3)
)
data_rightcensored_new <- data.table(
    Kunde = c("A", "C", "D", "F"), 
    von = c(0, 0, 0, -3), 
    bis = c(1, 3, 2, -1)
)
options(repr.plot.height=5, repr.plot.width = 10)
ggplot() + 
    geom_point(data = data_rightcensored %>% 
               melt(id.vars = "Kunde") %>% 
               filter(!(variable == "bis" & value >= 0)) %>%
               filter(!(Kunde == "F" & variable == "bis")), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_rightcensored, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 1) +
    geom_vline(xintercept = 0) +
    geom_point(data = data_rightcensored_new %>% 
               melt(id.vars = "Kunde") %>% 
               filter(variable == "bis"), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_rightcensored_new, 
                 aes(x = von, 
                     xend = bis, 
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 2) +
    xlab("Zeitpunkt") +
    ggtitle("Rechtszensierung") +
    coord_cartesian(xlim = c(-5, 3)) +
    theme_classic() +
    annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
    theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))

png

Im Umfeld der Churn Analyse soll genau für all heute aktiven Kunden, also für die Kunden , und im obigen Beispiel, eine Aussage getroffen werden. All diese Kunden sind per Definition rechtszensiert, die Rechtszensierung ist demnach im Bereich der Churn Analyse die Regel.

Rechtszensierte Daten können aber auch zu einem Zeitpunkt in der Vergangenheit auftreten. Beispielsweise könnte der Vertrag von Kunde zum Zeitpunkt wegen Fehlverhalten des Kunden seitens des Unternehmens aufgehoben worden sein. Dass eine Kündigung seitens des Kunden erst zum Zeitpunkt erfolgt wäre, ist dann nicht mehr beobachtbar. Es ist wichtig, solche Kündigungen seitens des Unternehmens gesondert zu beachten, da sie keine Rückschlüsse auf das Kündigungsverhalten des Kunden zulassen.

Code
data_rightcensored2 <- data.table(
    Kunde = c("F"), 
    von = c(-4), 
    bis = c(-3)
)
data_rightcensored2_new <- data.table(
    Kunde = c("F"), 
    von = c(-3), 
    bis = c(-1)
)
options(repr.plot.height=1.5, repr.plot.width = 10)
ggplot() + 
    geom_point(data = data_rightcensored2 %>% 
               melt(id.vars = "Kunde") %>% 
               filter(!(variable == "bis" & value >= 0)) %>%
               filter(!(Kunde == "F" & variable == "bis")), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_rightcensored2, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 1) +
    geom_vline(xintercept = 0) +
    geom_point(data = data_rightcensored2_new %>% 
               melt(id.vars = "Kunde") %>% 
               filter(variable == "bis"), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_rightcensored2_new, 
                 aes(x = von, 
                     xend = bis, 
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 2) +
    xlab("Zeitpunkt") +
    ggtitle("Rechtszensierung") +
    coord_cartesian(xlim = c(-5, 3)) +
    theme_classic() +
    annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
    theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))

png

Modellierung von Fragestellungen im Bereich Customer Churn

Nun zur Ausgangsfrage: Wie modelliert man welche Fragestellung im Bereich der Churn-Analyse und mit welchen Modellen können sie gelöst werden? Im Vorfeld der Analyse muss eindeutig geklärt werden, welches Problem gelöst werden soll. Während die Frage Wann kündigt mein Kunde? nach einem Zeitpunkt fragt, ist die Antwort auf die Frage Hat der Kunde in 6 Monaten gekündigt? binär. Die genaue Definition der Fragestellung ist Voraussetzung für eine korrekte Modellierung sowie die korrekte Auswahl der Verfahren. Zudem ist die Auswahl der Daten, die in den Trainingsdatensatz eingehen, unterschiedlich. Eine Übersicht über mögliche Fragestellungen gibt die folgende Tabelle. Im Folgenden werden die verschiedenen Input-Datentypen sowie die verschiedenen Modellierungsansätze beschrieben.

Fragestellung Datenselektion Datenmodellierung Art des Verfahrens Verfahren
Wann wird der aktive Kunde kündigen? Typ I Typ A Survival Nichtparametrische Modelle (Kaplan-Meier)
Semiparametrische Modelle (Cox-PH)
Parametrische Modelle (lineare Regression)
Machine Learning Modelle (Neuronale Netze)
Mit welcher Wahrscheinlichkeit
wird der Kunde im Zeitraum kündigen?
Typ II Typ B Regression Logistische Regression
Gradient Boosting
Neuronale Netze
Wird der aktive Kunde innerhalb
des Zeitraums kündigen?
Typ II Typ B Klassifikation Gradient Boosting
Neuronale Netze
Mit welcher Wahrscheinlichkeit wird der
aktive Kunde im Zeitraum nach
Vertragsbeginn gekündigt haben?
Typ III Typ B Regression Logistische Regression
Gradient Boosting
Neuronale Netze
Mit welcher Wahrscheinlichkeit wird der
aktive Kunde am Ende der
Vertragslaufzeit gekündigt haben?
Typ IV Typ B Regression Logistische Regression
Gradient Boosting
Neuronale Netze
Mit welcher Wahrscheinlichkeit wird der
Neukunde am Ende der
Vertragslaufzeit gekündigt haben?
Typ V Typ B Regression Logistische Regression
Gradient Boosting
Neuronale Netze
Wird der aktive Kunde im Zeitraum
nach Vertragsbeginn kündigen?
Typ III Typ B Klassifikation Gradient Boosting
Neuronale Netze
..
Wird der aktive Kunde am Ende
der Vertragslaufzeit kündigen?
Typ IV Typ B Klassifikation Gradient Boosting
Neuronale Netze
Wird der Neukunde am Ende
der Vertragslaufzeit kündigen?
Typ V Typ B Klassifikation Gradient Boosting
Neuronale Netze

Die Art der Datenselektion beschreibt die Art, wie Trainingsdaten generiert werden. Grundlegender Unterschied ist die Frage, ob die Zeitpunkte der Betrachtung für alle Kunden gleich oder verschieden sind sowie die Frage, ob der Horizont der Betrachtung für alle Kunden gleich oder verschieden sind. Außerdem muss darin unterschieden werden, ob überhaupt eine Rücksetzung auf vergangene Zeitpunkte durchgeführt werden muss (Typen II-V) oder nicht (Typ I).

Die Datenmodellierung beschreibt die Art, wie die ausgewählten Daten modelliert werden. Bei der Datenmodellierung können demnach grundlegend zwei Typen unterschieden werden. Typ A betrachtet stets einen unbekannten Zeitraum in der Zukunft. Es ist nicht definiert, auf welchen Zeitraum die Fragestellung abzielt. Hierbei unterscheidet sich dieser Datentyp von Typ B, der bei Fragestellungen angewendet wird, die auf einen vordefinierten Zeitraum abzielt.

Im Folgenden werden alle Typen detailliert beschrieben.

Verschiedene Datenquellen für die Modellierung

Typ I

Fragestellungen mit Datenselektion des Typs I werden über Survival-Modelle gelöst. Hierzu wird der gesamte - rechtszensierte und ggf. auch linkszensierte - Datenbestand im Modell berücksichtigt. Die Abbildung der Daten in den Modellen wird über die besondere Datenmodellierung - beschrieben im Abschnitt Datenmodellierung Typ B - gelöst.

Code
data <- data.table(
    Kunde = c("A", "B", "C", "D", "E"), 
    von = c(-10, -8.3, -7, -7.4, -4.5), 
    bis = c(-8.5, -5.1, -2.5, -5.2, 0)
)
options(repr.plot.height=5, repr.plot.width = 10)
ggplot() + 
    geom_point(data = data %>% 
               melt(id.vars = "Kunde"), 
               aes(x = value, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 1) +
    geom_vline(xintercept = 0) +
    xlab("Zeitpunkt") +
    ggtitle("Input-Daten Typ I") +
    coord_cartesian(xlim = c(-10, 0)) +
    theme_classic() +
    annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
    theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))

png

Typ II

Fragestellungen, die mit Datenselektion des Typs II gelöst werden müssen, fragen danach, ob oder mit welcher Wahrscheinlichkeit ein Kunde innerhalb eines bestimmten Zeitraumes kündigen wird. Um eine geeignete Datenbasis zu generieren, setzt man sich in diesem Fall fiktiv auf verschiedene Zeitpunkte zurück, die jeweils mehr als Zeiteinheiten in der Verganenheit liegen. So kann man für die zu dem jeweiligen Zeitpunkt aktiven Kunden bewerten, ob sie zum Zeitpunkt noch immer aktiv waren.

In der folgenden Grafik ist der Datengenerierungsprozess dargestellt:

Code
x <- 1
t <- seq(-9, -x, by = x+0.5)
segment_typeII <- data.table(
    timestamp = TeX(paste0("$$t_", seq_along(t), "$$")),
    xmin = t,
    xmax = t+x,
    ymin = 0.5,
    ymax = 5.5
)
plotFunction <- function(data, segment, title){
    p <- ggplot() + 
        geom_point(data = data %>% 
                   melt(id.vars = "Kunde"), 
                   aes(x = value, y = Kunde, col = Kunde),
                   pch = 3, size = 3) + 
        geom_segment(data = data, 
                     aes(x = von, 
                         xend = bis,
                         y = Kunde, 
                         yend = Kunde, 
                         col = Kunde), lty = 1) +
        geom_vline(xintercept = 0) +
        xlab("Zeitpunkt") +
        ggtitle(title) +
        coord_cartesian(xlim = c(-10, 0)) +
        theme_classic() +
        annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
        theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))+
        geom_rect(data = segment, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), alpha = 0.1) + 
        geom_segment(data = segment, aes(x = xmin, xend = xmin, y = ymin, yend = ymax))+
        geom_curve(data = segment, aes(x = xmin, xend = xmax, y = ymax-0.3, yend = ymax-0.3), 
                   arrow = arrow(length = unit(0.03, "npc")), curvature = -0.2)
    return(p)
}
options(repr.plot.height=5, repr.plot.width = 10)
plotFunction(data, segment_typeII, "Input-Daten Typ II") +
    annotate("text", x = segment_typeII$$xmin+1/2*x, y = segment_typeII$$ymax-0.3, label = TeX("$$x$$"))+
    annotate("text", x = segment_typeII$$xmin-0.1, y = 0.75, label = segment_typeII$$timestamp, angle = 90)

png

Im gezeigten Beispiel ist zum Zeitpunkt Kunde aktiv, nach Beendigung des Zeitraumes das Vertragsverhältnis beendet hat. Zum Zeitpunkt sind die Kunden , und aktiv, nach Beendigung des Zeitraumes bleibt Kunde , während und gekündigt hat.

Insgesamt sind also alle aktiven Kunden zu den Zeitpunkten mit , und zu wählen. Ein Kunde kann demnach auch mehrfach - mit jeweils verschiedenen Start- und Endzeitpunkten - in den Daten auftauchen. Ebenso ist es möglich, dass Kunden sowohl in den Trainings- als auch in den Testdaten vertreten sind. Der Prognosezeitraum sowie die Zeitpunkte der Betrachtung sind für alle Kunden identisch. Wie genau die Modellierung erfolgt wird im Abschnitt Datenmodellierung Typ A gezeigt.

Typ III

Für Fragestellungen mit Datenselektion Typ III müssen die Kunden vor mindestens Zeiteinheiten eingetreten sein. Nur so lässt sich bewerten, ob der Kunde nach Zeiteinheiten gekündigt hat oder nicht. Der Unterschied zu Typ II besteht darin, dass der Startzeitpunkt der Betrachtung, nämlich das Eintrittsdatum, nicht konstant ist, sondern sich für jeden Kunden unterscheidet. Hieraus folgt, dass jeder Kunde nur genau ein mal in den Trainingsdaten oder in den Testdaten auftritt.

In der folgenden Grafik wird der Datengenerierungsprozess gezeigt:

Code
x <- 3
segment_typeIII <- data.table(
    xmin = data$$von,
    xmax = data$$von + x,
    ymin = as.integer(as.factor(data$$Kunde))-0.3,
    ymax = as.integer(as.factor(data$$Kunde))+0.3
)
options(repr.plot.height=5, repr.plot.width = 10)
plotFunction(data, segment_typeIII, "Input-Daten Typ III")

png

Für die Betrachtung des Prognosezeitraumes gilt für Kunde und , dass sie als Kündiger innerhalb dieses Zeitraumes behandelt werden. Die anderen Kunden , und haben Zeiteinheiten nach ihrem individuellen Eintrittsdatum das Vertragsverhältnis nicht beendet.

Es sind also alle Kunden zu wählen, die seit mindestens Zeiteinheiten Kunde sind. Während nun der Zeitpunkt der Betrachtung kundenindividuell,nämlich das Eintrittsdatum, ist, bleibt der Prognosezeitraum konstant.

Typ IV

Für Fragestellungen mit Datenselektion des Typs IV muss eine Vertragslaufzeit vorliegen. Diese kann pro Kunde individuell sein. Gefragt ist nun nach einer Aussage bzgl. der Kündigung zum Vertragsende aus Sicht eines festen Zeitpunktes. Auch hier werden wie bei Typ II historische feste Zeitpunkte betrachtet. Es können alle Kunden berücksichtigt werden, die zu den Zeitpunkten aktiv waren. Auch hier kann analog zu Typ II jeder Kunde mehrfach in den Trainings- bzw. Testdaten auftreten.

Der Prozess der Datengenerierung ist in folgendem Beispiel gezeigt:

Code
data_typeIV_short <- data.table(
    Kunde = c("A", "B", "C", "D", "E"), 
    von = c(-10, -8.3, -7, -7.4, -4.5), 
    bis = c(-8.5, -5.1, -2.5, -5.2, 0),
    Laufzeit = c(1, 2, 1, 1, 3)
)
data_typeIV <- data_typeIV_short[,.(timestamps = c(seq(von, bis+Laufzeit, by = Laufzeit), bis)),by = "Kunde"]
data_typeIV_remaining <- data_typeIV_short[bis < 0,
    .(von = bis, bis = tail(seq(von, bis+Laufzeit, by = Laufzeit), 1)),
    by = "Kunde"]
t <- seq(-9, -2, by = 2)
segment_typeIV <- lapply(t, function(ti){
    data_typeIV_short %>%
    filter(von <= ti & bis >= ti) %>%
    group_by(Kunde) %>%
    summarize(
        xmin = ti,        
        xmax = c(seq(von, bis, by = Laufzeit), bis)[c(seq(von, bis, by = Laufzeit), bis)>ti][1],
        ymin = which(Kunde == LETTERS[1:5])-0.3,
        ymax = which(Kunde == LETTERS[1:5])+0.3
   )
}) %>% rbindlist()
options(repr.plot.height=5, repr.plot.width = 10)
ggplot() + 
    geom_point(data = data_typeIV, 
               aes(x = timestamps, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_typeIV_short, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 1) +
    geom_segment(data = data_typeIV_remaining, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 2) +
    geom_vline(xintercept = 0) +
    xlab("Zeitpunkt") +
    ggtitle("Input-Daten Typ IV") +
    coord_cartesian(xlim = c(-10, 0)) +
    theme_classic() +
    annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
    theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))+
    geom_rect(data = segment_typeIV, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), alpha = 0.1) + 
    geom_segment(data = segment_typeIV, aes(x = xmin, xend = xmin, y = ymin, yend = ymax))+
    geom_curve(data = segment_typeIV, aes(x = xmin, xend = xmax, y = ymax-0.3, yend = ymax-0.3), 
               arrow = arrow(length = unit(0.03, "npc")), curvature = -0.2)+
    geom_vline(xintercept = t) +
    annotate("text", x = t-0.1, y = 0.7, label = TeX(paste0("$$t_", seq_along(t), "$$")), 
                                                                       angle = 90)

png

Zu Zeitpunkt ist lediglich Kunde aktiv. Dieser kündigt zum nächst möglichen Zeitpunkt. Zum Zeitpunkt sind die Kunden und aktiv. Kunde kündigt hierbei nach Ende seinder Vertragslaufzeit während Kunde das Vertragsverhältnis verlängert. In dieser Form der Datengenerierung sind die Zeitpunkte der Betrachtung für alle Kunden identisch, während die Prognosezeitpunkte kundenindividuell die Restvertragslaufzeit angibt.

Typ V

Für Fragestellungen mit Datenselektion vom Typ V werden Kunden benötigt, die bereits den ersten Vertragszeitraum vollständig durchlebt haben. Dieser erste Vertragszeitraum wird ausgewertet. Demnach kann auch hier jeder Kunde nur genau einmal in den Trainings- bzw. Testdaten auftreten.

Die folgende Grafik stellt erneut ein Beispiel dar:

Code
data_typeV_short <- data.table(
    Kunde = c("A", "B", "C", "D", "E"), 
    von = c(-10, -8.3, -7, -7.4, -4.5), 
    bis = c(-8.5, -5.1, -2.5, -5.2, 0),
    Laufzeit = c(1, 2, 3, 1, 3)
)
data_typeV <- data_typeV_short[,.(timestamps = c(seq(von, bis+Laufzeit, by = Laufzeit), bis)),by = "Kunde"]
data_typeV_remaining <- data_typeV_short[bis < 0,
    .(von = bis, bis = tail(seq(von, bis+Laufzeit, by = Laufzeit), 1)),
    by = "Kunde"]
segment_typeV <- data_typeV_short %>%
    group_by(Kunde) %>%
    summarize(
        xmin = von, 
        xmax = von + Laufzeit,
        ymin = which(Kunde == LETTERS[1:5])-0.3,
        ymax = which(Kunde == LETTERS[1:5])+0.3
    )
options(repr.plot.height=5, repr.plot.width = 10)
ggplot() + 
    geom_point(data = data_typeV, 
               aes(x = timestamps, y = Kunde, col = Kunde),
               pch = 3, size = 3) + 
    geom_segment(data = data_typeV_short, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 1) +
    geom_segment(data = data_typeV_remaining, 
                 aes(x = von, 
                     xend = bis,
                     y = Kunde, 
                     yend = Kunde, 
                     col = Kunde), lty = 2) +
    geom_vline(xintercept = 0) +
    xlab("Zeitpunkt") +
    ggtitle("Input-Daten Typ V") +
    coord_cartesian(xlim = c(-10, 0)) +
    theme_classic() +
    annotate("text", x = 0.1, y = 1.1, label = "heute", angle = 90) +
    theme(plot.title = element_text(hjust = 0.5, vjust = 0.5))+
    geom_rect(data = segment_typeV, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax), alpha = 0.1) + 
    geom_segment(data = segment_typeV, aes(x = xmin, xend = xmin, y = ymin, yend = ymax))+
    geom_curve(data = segment_typeV, aes(x = xmin, xend = xmax, y = ymax-0.3, yend = ymax-0.3), 
               arrow = arrow(length = unit(0.03, "npc")), curvature = -0.2)

png

Im gezeigten Beispiel überleben alle Kunden ihre erste Vertragslaufzeit. Um ein aussagekräftiges Modell bauen zu können, müssen jedoch Kündiger in der Datenbasis vorliegen. Die Unbalanciertheit der Daten ist ein häufiges Problem im Bereich der Churn-Prediction. Wie man damit umgeht, zeigen wir in einem der nächsten Blogbeiträge.

Im Fall der Selektion nach Typ V sind sowohl Zeitpunkt der Betrachtung als auch Prognosehorizont kundenindividuell.

Zusammenfassung Datenselektion

Die Datenselektion nach Typ II bis Typ V kann man in folgender Tabelle anschaulich zusammenfassen:

Typ Zeitpunkt der Betrachtung für alle Kunden Horizont der Betrachtung für alle Kunden
Typ II gleich gleich
Typ III unterschiedlich gleich
Typ IV gleich unterschiedlich
Typ V unterschiedlich unterschiedlich

Verschiedene Arten der Datenmodellierung

Während wir im vorherigen Abschnitt beleuchtet haben, welche Daten in die Trainingsdaten eingehen, bleibt nun die Frage, wie die Daten modelliert werden. Bei allen Fragestellungen außer Fall 1 ist die Art der Modellierung hierbei dieselbe, nämlich die im Abschnitt Datemodellierung Typ B beschrieben. Lediglich Fragstellungen, die über Survival Modelle gelöst werden sollen, müssen abweichend modelliert werden. Diese Art der Modellierung wird im Abschnitt Datenmodellierung Typ A beschrieben.

Typ B

Alle Fragestellungen, die über Klassifikations- oder Regressionsmodelle gelöst werden sollen, werden äquivalent modelliert. Insgesamt ist für jede Zeile, also für jeden Kunden in der Trainingsmenge (Typ III und Typ V) bzw. für jeden Fall der aus einem historischen Kunden produziert wird (Typ II und Typ IV) eine Responsevariable zu generieren, die entweder (im Kündigerfall) oder (im Fall ohne Kündigung) zu erstellen.

Der finale Datensatz sieht demnach beispielsweise für Datenselektion des Typs III bzw. Typ V wie folgt aus:

Code
data.table(
    Kunde = c("A", "B", "C", "D", "E"),
    Alter = c(50, 30, 44, 31, 60),
    Wohnort = c("Würzburg", "Berlin", "Frankfurt", "Würzburg", "Frankfurt"),
    Kündigung = c(1, 1, 1, 0, 0)
)
Kunde Alter Wohnort Kündigung
A 50 Würzburg 1
B 30 Berlin 1
C 44 Frankfurt 1
D 31 Würzburg 0
E 60 Frankfurt 0

Für Typ II bzw. Typ VI könnten die Input-Daten so aussehen:

Code
data.table(
    Kunde = c("A", "A", "B", "B", "C", "D", "D", "E"),
    Alter = c(50, 52, 30, 32, 44, 33, 35, 60),
    Wohnort = c("Würzburg", "Würzburg", "Berlin", "Berlin", "Frankfurt", "Würzburg", "Würzburg", "Frankfurt"),
    Kündigung = c(0, 1, 0, 0, 0, 0, 1, 0)
)
Kunde Alter Wohnort Kündigung
A 50 Würzburg 0
A 52 Würzburg 1
B 30 Berlin 0
B 32 Berlin 0
C 44 Frankfurt 0
D 33 Würzburg 0
D 35 Würzburg 1
E 30 Frankfurt 0

Hinweis: Dass sich das Alter hierbei verändert ist den verschiedenen Zeitpunkten der Datenerfassung geschuldet.

Typ A

Im Falle der Suvival Analyse sind bereits die Trainingsdaten rechtszensiert. Man unterscheidet zwischen statischer Modelleriung und dynamischer Modellierung. Die statische Modelleriung ist relevant, wenn keine Einflussgrößen zeitlich veränderbar sind. Beispielsweise könnte lediglich das Geschlecht ins Modell einbezogen werden. In diesem Fall wird für jeden Kunden eine Zeile im Datensatz angelegt:

Code
data.table(
    Kunde = c("A", "B", "C", "D", "E"),
    Startzeitpunkt = c(0, 0, 0, 0, 0),
    Endzeitpunkt = c(15, 19, 40, 10, 41),
    Kündigung = c(0, 0, 0, 1, 1),
    Geschlecht = c("m", "f", "d", "m", "m")
)
Kunde Startzeitpunkt Endzeitpunkt Kündigung Geschlecht
A 0 15 0 “m”
B 0 19 0 “f”
C 0 40 0 “d”
D 0 10 1 “m”
E 0 41 1 “m”

Im Falle Kündigung ist der Endzeitpunkt jeweils das heutige Datum gemessen in Zeiteinheiten nach Vertragsbeginn. Es handelt sich um die Daten, die rechtszensiert sind. Aus diesem Grund ist der Startzeitpunkt für jeden Kunden . Im Falle Kündigung ist der Endzeitpunkt der Zeitpunkt der Kündigung, gemessen in Zeiteinheiten nach Vertragsbeginn.

Sollen zeitdynamische Variablen einbezogen werden, so wird der Zeitraum von Startzeitpunkt bis Endzeitpunkt aufgeteilt. Im vorliegenden Beispiel soll beipielsweise die Anzahl der Verträge einbezogen werden, die vereinfacht bei jedem Kunden zu Beginn bei ist. Bekommt Kunde zum Zeitpunkt einen weiteren Vertrag, so würde die Zeile für Kunde aufgeteilt in folgender Form:

Code
data.table(
    Kunde = c("A", "B", "C", "D", "E", "E"),
    Startzeitpunkt = c(0, 0, 0, 0, 0, 20),
    Endzeitpunkt = c(15, 19, 40, 10, 20, 41),
    Kündigung = c(0, 0, 0, 1, 0, 1),
    Geschlecht = c("m", "f", "d", "m", "m", "m")
)
Kunde Startzeitpunkt Endzeitpunkt Kündigung Geschlecht
A 0 15 0 “m”
B 0 19 0 “f”
C 0 40 0 “d”
D 0 10 1 “m”
E 0 20 0 “m”
E 20 41 1 “m”

Zu beachten ist hierbei, dass Kunde zum Zeitpunkt noch nicht gekündigt hat und daher die Responsevariable Kündigung zu diesem Zeitpunkt den Wert hat.

Ausblick

In diesem Blogbeitrag wurden die Methoden präsentiert, wie man Daten im Bereich der Churn Analyse abhängig von der gewählten Fragestellung auswählt und modelliert. Die Modellierung kann in R praktisch umgesetzt werden. Dabei sind, abhängig vom jeweiligen Typ der Datenselektion und Modellierung, verschiedene Pakete verfügbar. Neben der Umsetzung der Modellierung ist die Evaluation von Churn Modellen ein zentraler Baustein hin zum fertigen Churn Modell. Wie genau die Umsetzung ausehen kann, welche Schritte man beachten muss und wie ein Churn Modell validiert wird zeigen wir in einem Praxisbeispiel in einem weiteren Blogbeitrag.


Möchten Sie mehr darüber erfahren, wie wir unter anderem mit R für unsere Kunden Lösungen im Bereich Churn Prevention oder andere Lösungen entwickeln? Wir freuen uns auf Ihre Anfrage!