Datenanalyse mit R, Teil 1

In großen Datenmengen steckt häufig großes Potenzial. Doch wie kann man es nutzen? Die Sprache R bietet viele Möglichkeiten für statistische Berechnungen, die in Analyseszenarien nützlich sein können – Grund genug, sich R einmal genauer anzusehen.

In Pocket speichern vorlesen Druckansicht 6 Kommentare lesen
Lesezeit: 26 Min.
Von
  • Ralf Ehret
  • Benjamin Graf
Inhaltsverzeichnis

Mitten im goldenen Zeitalter des Data Mining entwickeln und verwenden Experten überall statistische Methoden: sei es für die zielgerichtete Werbung, die Analyse der Finanzmärkte oder die Entwicklung neuer Medikamente. Zusätzlich befeuern dies die immer größeren Datenmengen, in denen man große Potenziale vermutet. Grund genug, sich die populärste Entwicklungsumgebung für statistische Berechnungen einmal etwas näher anzusehen: R.

R ist eine Open-Source-Entwicklungsumgebung für statistische Analysen, vergleichbar mit anderen statistischen Softwarepaketen wie MATLAB, dem SAS Enterprise Miner oder SPSS Statistics. Sie basiert auf einer eigenen Skriptsprache, die für mathematische Berechnungen optimiert ist. R erlaubt es, Datensätze aus viele Datenquellen zu laden, diese zu transformieren und anschließend zu untersuchen. So gewonnene Einsichten sind wertvoll und lassen sich häufig zu Vorhersagemodelle weiterentwickeln. R bietet darüber hinaus eine Menge an domänenspezifischen Erweiterungen für besondere statistische Verfahren oder Visualisierungen.

In den letzten Jahren hat sich R zur populärsten Sprache für statistische Analysen entwickelt (siehe hierzu: 2011 Data Miner Survey von Rexer Analytics). Allen voran nutzen sie Big-Data-Firmen wie Google und Facebook, die sich auch aktiv an der Weiterentwicklung beteiligen. In der Geschäftswelt, wo das für wissenschaftliche Zwecke entwickelte R immer mehr Verbreitung findet, hat sich der Begriff Predictive Analytics (PA) entwickelt: Statt Daten der Vergangenheit zu betrachten und zu analysieren wie noch bei Business Intelligence, sind Prognosen über zukünftige Entwicklungen Ziel von PA. Die Erkenntnisse reichen von der Entdeckung von Zusammenhängen und Trends (zum Beispiel im Kundenverhalten) über quantitative Prognosen auf der Basis statistischer Modelle bis hin zur Automatisierung von Entscheidungsprozessen.

Für R wird, wie für alle Programmiersprachen, eine Laufzeitumgebung benötigt. Diese ist für Linux, Mac OS X und Windows verfügbar und steht auf der Projektsite bereit. Die Basisausführung mit einigen grundlegenden Statistikpaketen befindet sich samt detaillierter Installationsanleitung im Unterverzeichnis base. Folgende Schritt-für-Schritt-Anleitung beschränkt sich auf die Windows-Version, die Arbeitspunkte sollten allerdings analog für alle verfügbaren Binaries umzusetzen sein.

Die R-Konsole, eine grafische IDE wird später vorgestellt, lässt sich mit dem Aufruf von R.exe aus dem Installationsverzeichnis heraus starten. Bei erfolgreicher Eingabe sollten nun Informationen zur Versionsnummer und einige Hinweise zum Aufruf der Hilfe und Demonstrationsanwendungen auf dem Bildschirm erscheinen.

Durch das Eingeben von demo(graphics) und einer Bestätigung via RETURN-Taste lässt sich eine Demo der grafischen Ausgabemöglichkeiten starten (siehe Abb. 1). Ein Klick mit der Maus in das sich öffnende Fenster bewirkt, dass im Terminal der Code der erzeugten Plots erscheint. Zum Verlassen der R-Konsole ist der Befehl q() vorgesehen.

Zwei Beispiele aus demo(graphics) und demo(persp) (Abb. 1)

Das Workspace-Image ist das Speicherabbild des laufenden R-Prozesses. Beim Verlassen von R besteht die Möglichkeit, das Image in der Datei .Rdata zu speichern, um es beim nächsten Start automatisch wieder laden zu können.

Am besten beginnt man mit dem Anlegen eines Verzeichnisses für R-Projekte (zum Beispiel ~\R-Projekte\HeiseArtikel) im eigenen Home-Verzeichnis, von wo aus R auch gestartet werden sollte. Da der Installer unter Windows das R-Installationsverzeichnis nicht in die PATH-Variable einträgt, ist die Session mit dem vollen Pfad zu starten:

"C:\Program Files\R\R-2.15.0\bin\x64\R.exe" --no-save

Der verwendete Parameter --no-save verhindert beim Verlassen von R mit q() das Speichern des Images. Für das hier betrachtete Beispiel sind als Erstes 1000 normal verteilte Zufallszahlen mit dem Mittelwert 10 und der Standardabweichung 5 zu generieren. Sie sollen danach in einem Vektor namens random.numbers unterkommen.

> random.numbers <- rnorm(1000, mean=10, sd=5)

Bereits an dieser Zeile erkennt man einige Eigenheiten von R: Beispielsweise können die Variablennamen einen Punkt enthalten, was in der R-Community auch weit verbreitet ist. Eine Bedeutung hat er allerdings nicht. Als Zuordnungs-Operator lässt sich <- oder = verwenden, wobei man sich mit zweiterem eher als "Newbie" zu erkennen gibt. Informationen zum Programmierstil sind in einem Styleguide zu finden.

Den Vektor random.numbers hat R mit der letzten Anweisung also im Workspace angelegt. Mit ls() lassen sich die dort vorhandenen Objekte anschauen:

> ls()
[1] "random.numbers"

Der Befehl str(object) zeigt die Struktur eines Objekts:

> str(random.numbers)
num [1:1000] 8.2 -1.68 17.71 11.88 11.54 ...

Am Output ist zu erkennen, dass random.numbers ein numerischer Vektor der Länge 1000 ist. Danach folgen die ersten Zufallszahlen.

Um die Session wiederaufrufbar zu machen, wird ein Skript benötigt, das sich mit jedem Text-Editor erstellen lässt. Zum Ausprobieren wird zunächst eine Datei myFirstRScript.R im zuvor angelegten Verzeichnis erstellt. Das R-Skript selbst sieht dann beispielsweise folgendermaßen aus:

x <- rnorm(1000, mean=10, sd=5)
hist(x,
breaks = 50,
freq = FALSE,
main = "Gauss-Verteilung")
curve(dnorm(x, mean=10, sd=5), col="red", add=TRUE)

Von der R-Konsole aus lässt sich das Script mit

> source('myFirstRScript.R')

aufrufen.

Eine zentrale Datenstruktur in R ist der Vektor, also eine Auflistung gleichartiger Objekte, ähnlich den Vektoren in Java oder C++. Hier unterscheidet sich R von anderen statistischen Sprachen wie MATLAB, die Vektoren in ihrer mathematischen Bedeutung als Punkt in einem Vektorraum auffassen. Anders ist so vor allem die Interpretation der Operationen auf Vektoren: Der Befehl length(x) gibt die Anzahl der Elemente in x zurück – im obigen Beispiel also 1000. Ein Mathematiker würde hier die Länge eines Vektors in einem euklidischen Raum erwarten.

Operationen auf einem Vektor führt R grundsätzlich komponentenweise aus:

> a <- c(1,2,4,4,12,2,2,8,6,3)
> b <- c(3,5,2,4,2,24,3,2,2,2)
> a*b
[1] 3 10 8 16 24 48 6 16 12 6

Alle Elemente besitzen den gleichen Typ. Ein einzelnes oder mehrere Elemente werden über den [-Operator angesprochen (Details zum [-Operator erhält man mit dem Befehl help("[")). Hier ein paar Beispiele zum Ausprobieren.

Das zweite Element des Vektors:

> a[2]
[1] 2

Alle Elemente vom zweiten bis zum fünften:

> a[2:5]
[1] 1 2 4 4 12

Alle Elemente, die größer als 5 sind:

> a[a>5]
[1] 12 8 6

Die Operation a*b gibt nicht, wie man erwarten könnte, das Skalarprodukt der beiden Vektoren zurück, sondern multipliziert nur jeweils die einzelnen Komponenten. Soll ein Programm das Skalarprodukt berechnen, ist der Operator %*% zu verwenden.

Eine spezielle Form eines Vektors ist die sogenannte Sequenz. Sie beschreibt eine festgelegte Folge von Zahlen und wird mit der Funktion seq erstellt. Alle Zahlen zwischen –1 und 1 mit einer Schrittweite von 0,2 lassen sich beispielsweise durch die folgende Eingabe erzeugen:

> seq(-1,1,0.2)
[1] -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0

Sequenzen mit der Schrittweite 1 werden meist in einer etwas kompakteren Schreibweise abgekürzt:

> 1:5            #(gleichbedeutend mit seq(1,5,1))
[1] 1 2 3 4 5

Um statistische Analysen durchführen zu können, ist es nötig, Daten auch in tabellarischer Form darstellen zu können. Das wird in R mit einem sogenannten Data Frame erreicht, einer Auflistung von Tabellenspalten, die wiederum aus jeweils einem Vektor bestehen. Mit der Funktion data.frame() lässt sich ein solcher zusammensetzen:

> n <- c("Merkur","Venus","Erde","Mars")
> r <- c(2439, 6052, 6378, 3397)
> m <- c(0,0,1,2)
> planeten <- data.frame(name=n, aequator.radius=r, anzahl.monde=m)
> planeten
name aequator.radius anzahl.monde
1 Merkur 2439 0
2 Venus 6052 0
3 Erde 6378 1
4 Mars 3397 2

Wie man in diesem Beispiel erkennt, können die Elementtypen der einzelnen Vektoren (Spalten) unterschiedlich sein. Hier gehören sie den Typen character und numeric an.

Ein weiterer, spezieller Datentyp ist der Faktor: Dabei handelt es sich um Aufzählungen von Variablen, die keinen zahlenmäßigen Wert besitzen, wie Farbe, Beruf oder Geschlecht. Sie lassen sich also nicht der Größe nach ordnen (man kann nicht sagen, ob die Farbe Rot kleiner ist als Grün). Faktoren ordnungsgemäß zu deklarieren ist wichtig, da sie in den statistischen Berechnungen und bei grafischen Darstellungen anders zu behandeln sind. Es gibt auch geordnete Faktoren, bei denen eine natürliche Reihenfolge der möglichen Werte festgelegt ist. Der Unterschied zu numerischen Größen ist, dass sich auf diesen Faktoren keine mathematischen Operationen ausführen lassen. Ein Beispiel sind Schuhgrößen: Sie lassen sich in eine sinnvolle Ordnung bringen, Addieren oder Multiplizieren ergibt hingegen kein brauchbares Ergebnis.

Das folgende Beispiel enthält eine bessere Version der zuvor erstellten Planetentabelle, die auch alle Funktionen in R richtig interpretieren können.

> n <- factor(c("Merkur","Venus","Erde","Mars"))
> r <- c(2439, 6052, 6378, 3397)
> m <- c(0,0,1,2)
> s <- ordered(c("klein", "groß", "groß", "mittel"),
> levels=c("klein", "mittel", "groß"))
> planeten <- data.frame(name=n, aequator.radius=r, anzahl.monde=m,
> groessen.kategorie=s)
> planeten
name aequator.radius anzahl.monde groessen.kategorie
1 Merkur 2439 0 klein
2 Venus 6052 0 groß
3 Erde 6378 1 groß
4 Mars 3397 2 mittel

Die allgemeinste und komplexeste Datenstruktur ist die Liste. Sie ist eine geordnete Aufzählung von Datenobjekten. Der wichtige Unterschied zwischen einer Liste und einem Vektor ist, dass Listen Objekte unterschiedlichen Typs enthalten können. Außerdem lassen sich die einzelnen Objekte benennen und die Elemente über ihre Position in der Liste oder ihre Namen referenzieren. Syntaktisch ist zu beachten, dass die einzelnen Elemente mit einer doppelten eckigen Klammer ([[]]) angesprochen werden:

> pers.info <- list(name="Friedrich", ehepartner="Maria", anz.kinder=3,
+ alter.kinder=c(4,7,9))
> pers.info[["ehepartner"]]
[1] "Maria"
> pers.info[[2]]
[1] "Maria"
> pers.info[["alter.kinder"]][2]
[1] 7

Da die Entwicklung von R-Skripten mit einem Editor und die Ausführung auf der Konsole recht mühsam sind, gibt es einige Entwicklungstools. Diese reichen von erweiterten Editoren mit Code-Highlighting (zum Beispiel Textpad) über Emacs Add-on Packages (ESS: "Emacs speaks Statistics") bis hin zu richtigen GUIs wie JGR (Java Gui for R). Bei der Windows-Version wird Rgui.exe mit installiert. Unter Linux startet man eine Tk/Tcl-Version einfach mit R --gui=Tk. Eine Übersicht gängiger GUI findet sich auf einer Projektsite.

Eines der Werkzeuge, das einer modernen integrierten Entwicklungsplatform (IDE) am nächsten kommt, ist RStudio. Abbildung 2 zeigt den Anfangsbildschirm nach dem ersten Start: Auf der linken Seite befindet sich die R-Console, in der eine R-Session läuft. Auf der rechten Seite oben ist der Workspace zu finden. Beim ersten Start ist er leer. Später sieht man dort alle aktiven Objekte (die man sich in der R-CKonsole mit ls() anzeigen lassen kann). Im unteren Bereich rechts sind ein File-Browser, ein Ausgabefenster für alle Plots, die verfügbaren R-Pakete und das Hilfe-Fenster.

RStudio Startbildschirm (Abb. 2)

Es empfiehlt sich, nach dem ersten Start im Menü unter "Tools-Options..." das "Default working directory" anzupassen.

Options-Dialog von RStudio (Abb. 3)

Wird RStudio dann neu gestartet, sollte im File-Browser das zu Anfang angelegte Verzeichnis erscheinen. Oben rechts in der Symbolleiste, direkt unter dem Menü, befindet sich die Anzeige des aktuellen Projekts (none). Um ein erstes Projekt anzulegen, klickt man auf den Auswahlpfeil der Drop-down-Box und selektiert "New Project...". Im anschließenden Dialog wird "Create project from: Existing Directory" und das Verzeichnis ~\R-Projekte\HeiseArtikel ausgewählt. Im File-Browser sollte nun die Datei HeiseArtikel.Rproj sowie das zuvor erstellte Script myFirstRScript.R zu sehen sein. Durch einen Klick auf letzteres öffnet sich im linken oberen Bereich über der Konsole der Editor. Mit "Source" (oben rechts im Editor) lässt sich das Skript starten, und folgendes Bild erscheint:

RStudio nach Ausführung von myFirstRScript.R (Abb. 4)

Im Konsole-Fenster ist der source()-Befehl zu sehen, und im Grafikbereich erscheint ein Histogramm. Im "Workspace"-Fenster lässt sich erkennen, dass es jetzt ein Objekt (Vektor) x vom Typ numeric mit 1000 Werten gibt.

Das folgende Beispiel soll in die wichtigsten Befehle und Methoden von R einführen:

Eine Firma verkauft Haushaltsgroßgeräte. Mit dem Erhalt der Ware bekommen die Kunden eine Rechnung, die sie innerhalb von 21 Tagen zahlen müssen. Um ein Skonto von drei Prozent zu erhalten, muss die Zahlung innerhalb von sieben Tagen eingehen. Da die Firma Ausgaben hat, ist sie sehr daran interessiert, ihre Liquidität pro Kalenderwoche für mindestens einen Monat im Voraus zu wissen. Bisher wurden die Einnahmen pro Woche lediglich abgeschätzt.

Das minimale Zeitfenster für einen Zahlungseingang war ein Tag, das maximale 21 Tage nach Rechnungserhalt. Die Firma existiert seit dem 1. Januar 2012 und hat insgesamt 2000 Geräte an 100 Kunden verkauft.

Das Ziel der Analyse ist es, möglichst viel über das Zahlungsverhalten der Kunden zu lernen und für neue Rechnungen das wahrscheinlichste Datum für den Zahlungseingang zu bestimmen. Als Grundlage dienen (generierte und stark vereinfachte) Daten der abgeschlossenen Verkaufsaufträge der Kunden, für die die Zahlungsdauer, also die Anzahl Tage von der Rechnungsstellung bis zum Zahlungseingang, bekannt ist.

Das Vorgehen im folgenden Beispiel ist in fünf Schritte unterteilt, die auch für echte Analyseprojekte in der Praxis typisch sind:

  1. Vorbereitungen: Daten sind zu laden und in das richtige Datenformat zu bringen.
  2. Erste Begutachtung der Daten: Mit verschiedenen Visualisierungsmöglichkeiten werden die Daten begutachtet und es lassen sich eventuell erste Zusammenhänge finden.
  3. Modellbildung: Aufgrund der ersten Begutachtung der Daten und praktischen Menschenverstands lässt sich ein Modell bilden, das im Laufe der weiteren Schritte überprüft werden kann und gegebenenfalls anzupassen ist.
  4. Analyse des Modells: Mit interaktiven Visualisierungsmöglichkeiten und Clustering-Methoden lässt sich das Modell analysieren. Im vorliegenden Beispiel können die Kunden beispielsweise nach ihrem Zahlungsverhalten in Kategorien aufgeteilt werden.
  5. Prognose und Test: Das Modell erlaubt es abzuschätzen, wann eine offene Rechnung voraussichtlich vom betreffenden Kunden bezahlt wird.

In der Datei SalesOrders.csv befinden sich Informationen von 100 Kunden, die zwischen dem 1. Januar 2012 und dem 30. Juni 2012 eine Lieferung und eine Rechnung bekommen haben. Zusätzlich ist dort die Dauer in Tagen bis zum Zahlungseingang vermerkt. Die Datei legt man am besten in einem Ordner data im Projektordner HeiseArtikel ab.

Die erste Aufgabe besteht darin, die beschriebenen Daten einzulesen. RStudio stellt hierfür eine recht einfache Möglichkeit zur Verfügung: Im oberen Bereich des Workspace-Fensters befindet sich das Icon "Import Dataset". Klickt man darauf, lässt sich die Quelle für den Import bestimmen. Im vorliegenden Fall ist "From Text File..." und dort die Datei SalesOrder.csv auszuwählen. Im danach erscheinenden Pop-up-Fenster lässt sich die Struktur der Datei erkennen. Außerdem schlägt der Import-Assistent vor, daraus einen Data Frame mit vier Spalten zu machen. Nach einem erfolgreichen Import befindet sich das neue Objekt SalesOrders im Speicher und lässt sich in der Konsole benutzen. Im Workspace-Fenster erkennt man, dass es 2000 Observations (Zeilen) mit 4 Variable (Spalten) umfasst. In der Konsole lässt sich nachlesen, dass zwei Befehle ausgeführt wurden:

> SalesOrders <- read.csv("C:/Users/…/R-Projekte/ 
HeiseArtikel/data/SalesOrders.csv", sep=";")
> View(SalesOrders)
>

read.csv liest das File ein. Für nähere Informationen hierzu genügt ein Klick auf die Registerkarte "Help" im rechten unteren Teilfenster und die Eingabe von read.csv im Suchfeld. Der Befehl View() zeigt hingegen das Datenobjekt SalesOrders im Editor an. Dessen Struktur lässt sich mit dem Befehl str() näher betrachten:

> str(SalesOrders)
'data.frame': 2000 obs. of 4 variables:
$ BuyerRef : int 1088 1078 1075 1091 1004 1068 1011 1077
1005 1017 ...
$ DeliveryDate : Factor w/ 182 levels "2012-01-01","2012-01-02",..:
1 1 2 2 2 2 2 2 2 2 ...
$ TotalPrice : int 24693 22215 19340 20646 21981 27150 18148 23999 23608
23007 ...
$ PaymentDuration: int 15 20 7 6 7 7 6 11 24 26 ...

Es handelt sich also um ein data.frame mit den vier Variablen (Spalten) BuyerRef, DeliveryDate, TotalPrice und PaymentDuration. Eine einzelne Spalte (Variable) spricht man mit dem $-Operator an:

> SalesOrders$BuyerRef[1:5]
[1] 1088 1078 1075 1091 1004

Ein Blick auf die Struktur der Variablen DeliveryDate zeigt, dass es sich hier nicht wie erwartet um ein Datum, sondern einen Faktor (auch als "category" oder "enumerated type" bezeichnet) handelt:

> str(SalesOrders$DeliveryDate)
Factor w/ 182 levels "2012-01-01","2012-01-02",..: 1 1 2 2 2 2 2 ..

Der Import-Assistent hat das Datum folglich nicht als solches erkannt und dessen Werte als Strings interpretiert.

Um zu erfahren, wie der Import-Assistent die CSV-Datei importiert hat, ist zunächst die Historie der Eingabebefehle zu durchsuchen. Hierfür kann man in der Konsole den Befehl history() eingeben oder in RStudio auf die Registerkarte History im oberen rechten Fenster klicken. Dort findet sich der Befehl read.csv(), dessen Online-Hilfe sich unter Help in RStudio (oder mit dem Befehl help("read.csv") in der Console) aufrufen lässt. Wenn man sich die Liste der Parameter durchliest, findet man recht schnell den Parameter stringsAsFactors, der die Konvertierung steuert. Da dieser standardmäßig auf TRUE gesetzt ist, ist der Datenimport also erneut mit stringsAsFactor=FALSE durchzuführen.

Hierfür kann der Entwickler zunächst ein neues R-Skript im Projekt anlegen (Menu File-New-R Skript oder durch Klicken auf das +Icon, direkt unter dem Menü-Punkt File). Ein leeres Editor-Fenster mit dem Titel Untiteled1* wird geöffnet. Als Nächstes ist im History-Fenster die Zeile mit dem read.csv()-Befehl zu markieren und auf Icon To Source zu klicken. Der Befehl wird in das aktive Editor-Fenster übernommen, wo er sich anpassen lässt. Ein weiterer Parameter ist von Nöten:

# load data from csv file
SalesOrders <- read.csv("data/SalesOrders.csv",
sep=";",
stringsAsFactors=FALSE)

Kommentare sind in R mit der Raute # zu kennzeichnen. Nun kann man die Datei im aktuellen Projekt unter dem Namen preprocessData.R speichern und das Script ausführen (Kommando Source am oberen rechten Rand des Editors).

Tipp: Durch das Markieren der Checkbox "Source on Save" wird das gesamte File beim Sichern in der Konsole ausgeführt. Durch Eingabe des str()-Befehls sollte folgendes Ergebnis erscheinen:

> str(SalesOrders)
'data.frame': 2000 obs. of 4 variables:
$ BuyerRef : int 1088 1078 1075 1091 1004 1068 1011 1077 ...
$ DeliveryDate : chr "2012-01-01" "2012-01-01" "2012-01-02" ...
$ TotalPrice : int 24693 22215 19340 20646 21981 27150 ...
$ PaymentDuration: int 15 20 7 6 7 7 6 11 24 26 ...

Die Variable DeliveryDate ist jetzt ein Vektor mit Strings (characters), der sich in ein Datum konvertieren lässt. Hierfür gibt es unterschiedliche Befehle, fast alle beginnen mit as.ZielTyp. Zum Ausprobieren kann man einen Character-Vektor der Länge 1 anlegen und ihn dann mit as.Date() konvertieren:

> today <- "2012-07-02"
> str(today)
chr "2012-07-02"
> d1 <- as.Date(today, format="%Y-%m-%d")
> str(d1)
Date[1:1], format: "2012-07-02"

Für ein weiteres Experiment lassen sich die ersten zehn Einträge des Data Frame SalesOrders mit

> SO <- SalesOrders[1:10, ] 

kopieren. Man beachte das Komma im [-Operator. Da es sich bei einem Data Frame immer um ein zweidimensionales Objekt handelt, benötigt der [-Operator zwei Auswahlkriterien: eines für die Zeilen (hier 1:10) und eines für die Spalten (da keine Selektion stattfindet, sind alle Spalten zu kopieren).

Anschließend kann man die komplette Spalte DeliveryDate mit dem Befehls as.Date() konvertieren und das Ergebnis wieder mit str() ansehen.

> SalesOrders$DeliveryDate <- as.Date(SalesOrders$DeliveryDate, 
format="%Y-%m-%d")
> str(SalesOrders$DeliveryDate)
Date[1:1000], format: "2012-01-01" "2012-01-02" "2012-01-02"
"2012-01-02" ...

Der Befehl as.Date() erhält einen kompletten Character-Vektor und liefert einen neuen Vektor des Typs Date zurück. Dieser wird wieder der Spalte DeliveryDate des Data Frame SalesOrders zugeordnet. Daran erkennt man deutlich den Vektor-orientierten Ansatz von R. Fast alle Befehle, die einen Vektor, ein data.frame, eine Matrix oder ein Array als Input haben, wenden eine Funktion auf die einzelnen Elemente einer Spalte (oder einer Zeile) an. In anderen Programmiersprachen würde man eher versuchen, einen Loop über den Vektor zu implementieren (siehe Exkurs: Analysemethoden und "Fallen").

Die Sprache R erfreut sich zunehmend größerer Beliebtheit sowohl in akademischen Anwendungen als auch in Unternehmen. Sie bietet eine sehr mächtige Plattform zur Analyse und Visualisierung von Daten und ist frei verfügbar. R bietet einen Funktionsumfang an analytischen und statistischen Verfahren, der kaum einen Wunsch offen lässt. Achtet man auf einige Fallstricke, lässt sich das Potenzial, dass in den Datenmengen schlummert, effizient nutzen. Mehr erfährt man auch in einem zweiten Artikel.

Dr. Ralf Ehret
arbeitete von 1991 bis 1998 am europäischen Teilchenforschungszentrum CERN an Datenanalysen, bevor er zur SAP AG wechselte. Dort beschäftigte er sich unter anderem mit dem Thema Predicitve Analytics für die In-Memory-Technik HANA.

Benjamin Graf
entwickelt als Data Scientist bei der SAP AG statistische Algorithmen und Prognosemodelle auf der HANA-Plattform. Vor seiner Tätigkeit bei SAP beschäftigte er sich an der Universität von Edinburgh mit automatischer Übersetzung und maschinellem Lernen.

  • Beschreibende Statistik: beschreibt die Verteilung einer Variable, zum Beispiel die durchschnittliche Temperatur und deren Varianz in einer bestimmten Region.
  • Testen statistischer Hypothesen: Hier wird üblicherweise eine "Nullhypothese" formuliert, die an Hand der Daten widerlegt werden soll. Beispielsweise könnte eine Nullhypothese lauten, dass das Herzinfarktrisiko mit dem Cholesterinspiegel nicht ansteigt.
  • Vergleich unterschiedlicher Versuchsgruppen: untersucht, ob unterschiedliche Versuchsgruppen auch unterschiedliche statistische Eigenschaften haben. Beantwortet zum Beispiel die Frage, ob Männer und Frauen unterschiedliches Einkaufsverhalten aufweisen.
  • Faktorenanalyse: findet häufig in der Auswertung von Umfragen Anwendung. Findet aus der großen Menge von Attributen die wesentlichen unbekannten Einflussfaktoren. In der Psychologie werden beispielsweise aus Fragebögen grundlegende Charaktereigenschaften hergeleitet.
  • Clustering: ordnet Objekte in unterschiedliche Gruppen (Cluster), sodass alle Objekte innerhalb einer Gruppe ähnlich sind.
  • Assoziationsanalyse: versucht aus einer Menge von Ereignissen herauszufinden, welche Ereignisse häufig zusammen auftreten. Klassisches Anwendungsgebiet ist die sogenannte Warenkorbanalyse, die ermittelt, welche Produkte häufig gemeinsam gekauft werden.
  • Zeitreihenanalyse: untersucht die Entwicklung einer Variablen über die Zeit, um entweder zukünftige Entwicklungen vorherzusagen (zum Beispiel der Wertentwicklung bestimmter Finanzprodukte) oder aber um unvorhergesehene Änderungen aufspüren zu können (zum Beispiel für Störungsmeldungen).
  • Regression: ermittelt anhand einer Menge von Trainingsdaten den Zusammenhang zwischen bestimmten Objekteigenschaften und einer Zielgröße. Beispielsweise wird durch das Betrachten demographischer Daten und des bisherigen Kaufverhaltens eines Kunden auf dessen zukünftige Kaufbereitschaft geschlossen.

Das Konvertieren einer gesamten Spalte kann auch in einer Schleife erfolgen, wofür Data Frame SO nötig ist:

for(i in 1:length(SO$DeliveryDate))
{ SO$DeliveryDate[i] <-as.Date(SO$DeliveryDate[i], format="%Y-%m-%d") }

Tipp: Am besten legt man sich ein weiteres R-Skript Workspace.R an. Dort kann man die Befehle einfach eingeben. Mit dem [caps]Run[/cas]-Befehl des Editor-Fensters (oben rechts) lassen sich selektierte Zeilen ausführen. Zum Ausprobieren spart das viel Zeit.

Mit

> str(SO$DeliveryDate)
chr [1:10] "15340" "15341" "15341" "15341" "15341" "15341" ...

ist zu erkennen, dass dies nicht ganz dem erwarteten Ergebnis entspricht. Um das zu verstehen, muss man wissen, dass R im Prinzip eine objektorientierte Skriptsprache ist, die das sogenannte Duck-Typing unterstützt. Nicht die Klasse eines Objekts bestimmt den Typ, sondern allein die Existenz einer Methode (siehe beispielsweise Duck-Typing). Zwar führt das zu hoher Flexibilität, aber wie bei allen dynamischen Typsystemen zu einer erschwerten Fehlersuche, da der Typ sich nur zur Laufzeit überprüfen lässt. Es kommt hinzu, dass – im Gegensatz zu anderen Sprachen mit Duck-Typing wie Python, Ruby oder Smalltalk – in R intrinsische Typkonvertierungen durchgeführt werden, die Sprache sich also eher wie Fortran verhält.

Im Beispiel legt as.Date() zunächst ein neues Objekt der Klasse Date an, nimmt den Character-Vektor und versucht aus ihm, gemäß dem angegebenen Format, die Attribute der Date Class zu setzen. Anschließend wird einem Element des existierenden Character-Vektors (SO$DeliveryDate) dieser Wert durch den Assignment Operator <- zugewiesen. Da ein Vektor allerdings immer nur einen bestimmten Typ enthalten kann und der existierenden Vektor vom Typ character ist, wird die neue Instanz der Date Class durch coerce() in einen Character-String konvertiert und dem Vektor SO$DeliveryDate zugewiesen.

Die (vermeintliche) Lösung für das Problem mit der for-Schleife wäre folglich, einen neuen Vektor des Typs Date und der Länge 1 anzulegen und diesen anschließend zu
füllen:

> DD <- c(Sys.Date())
> for(i in 1:length(SO$DeliveryDate)) {
+ DD[i] = as.Date(SO$DeliveryDate[i], format="%Y-%m-%d")
+ }
> str(DD)
Date[1:10], format: "2012-01-01" "2012-01-02" "2012-01-02" ...

Die eigentliche Lösung ist die Vermeidung der for-Schleife unter Ausnutzung von Vektoroperationen, zum Beispiel

> SO$DeliveryDate <- as.Date(SO$DeliveryDate, format=“="%Y-%m-%d")

Mehr "Fallen" bei der Nutzung von R findet man in Patrick Burns' Tutorial. (jul)