Datenanalyse mit R, Teil 2
Seite 2: Analyse
Um eine solche Zeitreihe für jeden einzelnen Kunden zu erzeugen, sind Methoden zur Datenmanipulation (aggregieren, zusammenführen, ableiten von neuen aus alten Attributen) nötig. R besitzt hierfür eine Reihe von Möglichkeiten, wobei spezielle Pakete das Verwenden anderer Sprachen, zum Beispiel SQL (Package sqldf), erlauben.
Ein erster Schritt ist, alle Zahlungsdauern eines Kunden in ein TimeSeries-Objekt zu packen und in einem neuen Data Frame zu speichern, beispielsweise mit aggregate(). Die Funktion arbeitet den Data Frame zeilenweise ab, aggregiert alle Einträge nach einer Spalte, die durch den Parameter by angegeben ist, und führt danach die in FUN angegebene Aggregationsfunktion ts (create Time Services) durch. Anschließend setzt die eingegebene Sequenz den Namen der Spalten des Objekts Pd.ts.
Pd.ts <- aggregate(x=SalesOrders$PaymentDuration,
by=list(Customer=SalesOrders$BuyerRef), FUN=ts)
names(Pd.ts) <- c("Customer", "TimeSeries")
Das resultierende Objekt lässt sich mit der bekannten str()-Funktion untersuchen:
> str(Pd.ts[1:3,])
'data.frame': 3 obs. of 2 variables:
$ Customer: int 1001 1002 1003
$ TimeSeries:List of 5
..$ 0: Time-Series from 1 to 7: 14 15 16 16 15 19 17
..$ 1: Time-Series from 1 to 16: 23 15 15 19 11 18 19 23 19 12 ...
..$ 2: Time-Series from 1 to 20: 26 29 24 25 24 21 28 20 19 20 ...
>
Alle Werte des Attributs PaymentDuration sind jetzt in einem Time-Series-Objekt abgelegt. Auf dem neuen Data Frame Pd.ts lässt sich mit sapply() die Funktion mean() zur Berechnung des Mittelwerts der PaymentDurations für einen Kunden anwenden:
# Mean value of time series
Pd.mean <- sapply(Pd.ts[, "TimeSeries"], FUN=mean)
Als Nächstes sind der Vektor Pd.mean und das Data Frame Pd.ts mit cbind() zu einem neuen Data Frame Pd zusammenzufügen.
Pd <- cbind(Pd.ts, Mean=Pd.mean)
Beide Befehle lassen sich kombinieren, indem man beispielsweise eine Standardabweichung hinzufügt. Das anfänglich erstellte Histogramm des Attributs PaymentDuration hatte zwei Peaks, einen schmalen und einen breiten. Dies legt nahe, dass es zwei Verteilungen mit unterschiedlichen Breiten (Standardabweichungen) gibt.
Pd <- cbind(Pd, StdDev=sapply(Pd.ts[, "TimeSeries"], FUN=sd))
Bisher wurden die Aggregation (aggregate()), das Anwenden einer Funktion auf eine Spalte (sapply() ), sowie das Erweitern von data.frames durch das Hinzufügen von Vektoren mit cbind() vorgestellt. Was jetzt noch fehlt ist das Zusammenfügen (Mergen) von zwei Datenobjekten. Dafür sind für die hier beschriebenen Zwecke eine Aggregation der Kunden durchzuführen und diesen die Anzahl der Verkaufsaufträge zuzuordnen (könnte analog zu den Beispielen durch sapply(..., FUN = length)
geschehen):
# example for more attributes and merge
Pd.nr <- aggregate(x=SalesOrders$PaymentDuration,
by=list(Customer=SalesOrders$BuyerRef), FUN=length)
names(Pd.nr) <- c("Customer", "NrDel")
Pd <- merge(Pd, Pd.nr)
Bei dem Befehl merge() ist darauf zu achten, dass die zusammzuführenden Spalten der Objekte gleiche Namen besitzen. Ist das nicht der Fall oder ist es nicht eindeutig, lassen sie sich mit den Parametern by.x und by.y setzen.
Ein Umsortieren der Spalten des Objekts Pd lässt die Time-Series-Objekte zum Schluss erscheinen:
> Pd <- Pd[, c(1,3,4,5,2)]
> str(Pd[1:3,])
'data.frame': 3 obs. of 5 variables:
$ Customer : int 1001 1002 1003
$ Mean : num 16 17.8 24.1
$ StdDev : num 1.63 4.42 3.56
$ NrDel : int 7 16 20
$ TimeSeries:List of 3
..$ 0: Time-Series from 1 to 7: 14 15 16 16 15 19 17
..$ 1: Time-Series from 1 to 16: 23 15 15 19 11 18 19 23 19 12 ...
..$ 2: Time-Series from 1 to 20: 26 29 24 25 24 21 28 20 19 20 ...
>
Die Modellannahmen besagen also, dass es die "Skonto"-Zahler, die innerhalb von 7 Tagen zahlen (da sie das Skonto nutzen möchten) und deshalb eine schmale Verteilung besitzen, und die "ich warte bis zum Zahlungsziel"-Zahler gibt, die ihre Rechnungen erst am Ende der Zahlungsfrist von 21 Tagen bezahlen.
Analyse des Modells
Die zugrunde gelegten Annahmen lassen sich durch eine Clusteranalyse überprüfen. Der Standard-Algorithmus für Clustering ist wohl der k-means-Algorithmus, der auf Ideen von Hugo Steinhaus von 1957 [1] basiert. Neuere Algorithmen sind meist in kurzer Zeit in R als Paket verfügbar – so auch der MCLUST- Algorithmus von Fraley and Raftery [2] [3]. Um ihn zu nutzen, wird das Paket mclust benötigt, das sich, wie bereits erwähnt, mit dem Button "Install Packages" auf der Registerkarte Packages im rechten unteren Hilfe-Bereich von RStudio installieren lässt. Die Ausführung der Analyse ist recht einfach: Man muss nur die zu clusternden Daten angeben, und der Befehl Mclust( data ) führt den Algorithmus aus. Zu beachten ist, dass nicht das zu clusternde Attribut BuyerRef Verwendung findet. Hierfür soll sich schließlich die Zuordnung bestimmen lassen.
# find customer clusters
cl.m <- Mclust(Pd[,2:4])
Das erzeugte Objekt cl.m besitzt viele einzelne Komponenten, die das verwendete Modell, die Cluster- Zentren, die Wahrscheinlichkeit der Zugehörigkeit der Datensätze zu jedem Cluster, und vieles mehr beschreibt. Wichtige Informationen stecken beispielsweise in den einzelnen Cluster-Zentren:
> cl.m$parameters$mean
[,1] [,2] [,3]
Mean 18.140297 6.0060369 25.054981
StdDev 4.138271 0.9696506 3.232709
NrDel 14.705898 33.3333333 28.571594
Der Algorithmus findet nicht zwei, sondern drei Kunden-Cluster, was sich wieder visuell darstellen lässt. Hierzu ruft man die plot()-Funktion für ein Objekt der Klasse Mclust auf:
plot(cl.m, Pd[,2:4], what=c("classification"))
Das Resultat ist in Abbildung 3 gezeigt. Auf der rechten Seite sind die bekannten Scatterplots der drei Attribute Mean, StdDev und NrDel zu sehen, in denen jeweils die einem Cluster zugeordneten Datenpunkte unterschiedlich eingefärbt wurden: Cluster 1 ist blau, Cluster 2 rot und Cluster 3 grün. Man erkennt weiterhin, dass die Cluster am besten in den Variablen Mean und StdDev getrennt werden können. Für sie ist rechts daneben der Scatterplot beider Attribute samt der Cluster-Zentren und der zugehörigen Fehlerellipsen dargestellt.
Neben den beiden erwarteten Gruppen der "Skonto"-Zahler (rot) und der "ich warte bis zum Zahlungsziel"-Kunden (blau) gibt es wohl eine dritte Gruppe (grün), die "ich warte auf die Mahnung"-Kunden. Allein dieses Wissen kann für eine Firma viel Wert sein.