4 Datenauswahl und Datentransformation in:

Andreas Behr, Ulrich Pötter

Einführung in die Statistik mit R, page 54 - 68

2. Edition 2010, ISBN print: 978-3-8006-3599-3, ISBN online: 978-3-8006-4878-8, https://doi.org/10.15358/9783800648788_54

Series: Vahlens Kurzlehrbücher

Bibliographic information
D D Daten sind selten schon in einer Form, in der man sie für die weitere Analyse benötigt. Man muss Daten nach bestimmten Kriterien auswählen, sie transformieren und Variable rekodieren. Und oft müssen verschiedene Datensätze zusammengeführt werden. Solche Arbeiten erfordern den größten Arbeitsaufwand in jeder Datenanalyse. Effiziente Methoden und entsprechende Dokumentationsmöglichkeiten sind daher eine wesentliche Voraussetzung jeder Datenanalyse. 4.1 Datenauswahl und Zusammenführung 4.1.1 Auswahl von Fällen und Variablen 4.1.2 Verbinden von Datensätzen 4.1.3 Daten sortieren 4.1.4 Daten zusammenführen 4.2 Transformationen und Rekodierungen 4.2.1 Transformationen 4.2.2 Rekodierung 4.2.3 Rekodierung von Faktoren 4.3 Übungsaufgaben . Datenauswahl und Zusammenführung . . Auswahl von Fällen und Variablen Variablenauswahl Wir laden den Datensatz aus dem Anfang des letzten Kapitels erneut in den Arbeitsspeicher: > daten < read.table("test.dat") > daten name t x y 1 Hans 1 2 5 Datenauswahl und Datentransformation 2 Hans 2 3 4 3 Susi 1 4 3 4 Susi 2 5 2 Aus demDataframe daten soll ein neuerDataframemit demNamen daten.zwei erstellt werden, der nur die beiden Variablen name und x enthält: > daten.zwei < data.frame(daten$name,daten$x) Einfacher ist es oft, vorher die Variablen des Dataframes (in unserem Beispiel daten) mit dem attach() Befehl dem Suchpfad von R hinzuzufügen: > attach(daten) > daten.zwei < data.frame(name,x);daten.zwei name x 1 Hans 2 2 Hans 3 3 Susi 4 4 Susi 5 Allerdings ändert der attach() Befehl die Reihenfolge, in der nach Symbolen in einer R Sitzung gesucht wird: Der Dataframe daten wird an zweiter Stelle (nach der globalen Umgebung) in den Suchpfad eingefügt. Ein Verweis auf die Variable mit dem Namen name verweist daher auf die entsprechenden Werte, die in dem Dataframe daten abgelegt sind, nicht auf die Variable gleichen Namens im Dataframe daten.zwei. Ein attach(daten.zwei) fügt die Variablennamen dieses Datensatzes an zweiter Stelle des Suchpfads ein. Die Variablen des Dataframes daten rücken an die dritte Stelle. In diesem Fall erzeugt R eine Warnung > attach(daten.zwei) The following object(s) are masked from daten: name x Der nächste Verweis auf die Variable mit dem Namen name bezieht sich also auf die Version im Dataframe daten.zwei, die Version gleichen Namens im Dataframe daten ist nur durch expliziten Verweis (z.B. durch daten$name) ansprechbar, diese Variable ist „masked“. Eine weitere Möglichkeit der Variablenauswahl besteht in der Verwendung von Indizes. Man kann folgende Varianten verwenden: > daten.zwei < daten[,c(1,3)] > daten.zwei < daten[,c("name","x")] > daten.zwei < daten[c("name","x")] > daten.zwei < daten[c(1,3)] Die ersten beiden Formen behandeln den Dataframe daten als Matrix, die letzten beiden als Liste. Wir nehmen hier an, dass die Daten daten in einer neuen Sitzung geladen wurden, so dass die Variablen mit den Namen name und x nicht mehr in der globalen Umgebung definiert sind. . Datenauswahl und Zusammenführung Auswahl bestimmter Beobachtungen Als Beispiel wollenwir einenDataframe erzeugen, der nur die Beobachtungen der beiden Variablen name und x enthält, falls diese die Bedingung x>=4 erfüllen. Diese Selektion können wir durch die Angabe der entsprechenden Zeilen und Spalten erreichen: > daten.highx < daten.zwei[x>=4,];daten.highx name x 3 Susi 4 4 Susi 5 Mit der Bedingung x>=4 wird festgelegt, welche Zeilen eingelesen werden sollen. Da dem „,“ kein Spaltenindex folgt, werden alle Spalten eingelesen. subset Sowohl die Auswahl vonVariablen als auch die Auswahl von Fällen kann über die Indizierung des Dataframes vorgenommen werden. Der Befehl subset() ermöglicht eine Vereinfachung beider Aufgaben. subset() hat folgende Argumente: subset(,subset=,select=) Dieser Befehl gibt alle und Zeilen von zurück, die der genügen. Die Bedingung sollte ein logischer Ausdruck sein, der sich auf Variable des Datenfiles bezieht. Lässt man die Bedingung frei (im zweiten Beispiel unten durch das leere zweite Argument ,, angegeben), so werden alle Datensätze übernommen. Lässt man die Variablenliste weg, so werden alle Variablen übernommen. Die Besonderheit des subset() Befehls ist, dass die Variablennamen des Dataframes benutzt werden können, ohne dass der Dataframe dem Suchpfad hinzugefügt wurde. Hier einige Beispiele mit unserem Datenfile: - nur bestimmte Beobachtungen: > subset(daten,x>=4) name t x y 3 Susi 1 4 3 4 Susi 2 5 2 - nur bestimmte Variable: Dieser Befehl subset() des Basispakets unterscheidet sich vom Befehl subset() des memisc Pakets in Abschnitt . . , das im letzten Kapitel besprochen wurde. Insbesondere ist das Ergebnis des subset() Befehls im memisc-Paket ein data.set und kein Dataframe. Trotzdem entsteht nach dem laden des Pakets memisc kein Konflikt zwischen den Funktionen. Denn das neue Verhalten von subset() hängt allein von der Klasse des Objektes ab, das als Argument übergeben wird. Für „Importer“-Objekte des memisc Pakets werden Objekte der Klasse data.set erzeugt. Übergibt man dagegen einen Dataframe, dann verhält sich subset() wie in diesem Abschnitt beschrieben. Dies ist ein Aspekt objektorientierten Programmierens in R. Datenauswahl und Datentransformation > subset(daten,,c(name,x))#oder: subset(daten,select=c(name,x)) name x 1 Hans 2 2 Hans 3 3 Susi 4 4 Susi 5 - nur bestimmte Beobachtungen bestimmter Variablen: > subset(daten,x>=4,c(name,x)) name x 3 Susi 4 4 Susi 5 . . Verbinden von Datensätzen rbind und cbind Datensätze, Matrizen und Vektoren kann man auf verschiedene Arten zusammenführen. Am einfachsten ist dies mit den Befehlen rbind() und cbind() möglich. Mit cbind(a,b) werden die Objekte a und b spaltenweise (c wie „column“) kombiniert, mit rbind werden sie zeilenweise (r wie „row“) kombiniert. Betrachten wir zwei Beispiele: > x < c(2,3,1) > y < c(2,1,1) - vertikales Zusammenfügen: > cbind(x,y) x y [1,] 2 2 [2,] 3 1 [3,] 1 1 - horizontales Zusammenfügen: > rbind(x,y) [,1] [,2] [,3] x 2 3 1 y 2 1 1 Eine Besonderheit von R ist das „Recyclen“ von zu kurzen Vektoren. Ist ein Vektor zu kurz, wird wieder mit dem ersten Element begonnen: > x < c(2,3,1,4) > y < c(1,2) > rbind(x,y) [,1] [,2] [,3] [,4] x 2 3 1 4 y 1 2 1 2 . Datenauswahl und Zusammenführung Eine weitere Besonderheit tritt auf, wenn sowohl x als auch y Dataframes sind. Dann haben die Spalten (Variable) Namen und das Ergebnis von rbind() sortiert das zweite Argument spaltenweise so, dass Spalten gleichen Namens untereinander stehen. do.call Die Befehle lapply(), tapply() und andere liefern Listen als Ergebnis zurück. Wenn die Ergebnisse (die Listenelemente) alle wieder Vektoren gleicher Länge sind, möchte man oft wieder eine Matrix oder ein Dataframe erzeugen. Der Befehl rbind() (bzw. cbind()) kann aber nur selten direkt angewandt werden, denn meist ist weder die Zahl der Listenelemente des Ergebnisses noch sind deren Namen von vornherein bekannt. Außerdem wäre es auch sehr umständlich, jeweils lange Listen angeben zu müssen. Dabei hilft der (auch in anderen Zusammenhängen hilfreiche) Befehl do.call(), der als Argumente einen Befehl und eine Liste vorsieht. Als Ergebnis wird zunächst die Liste als Folge von Argumenten des Befehls interpretiert und anschließend der so konstruierte Befehl ausgeführt. Nehmen wir die Daten des Dataframes daten: > name < c(rep("Hans",2),rep("Susi",2)) > t < rep(c(1,2),2) > x < c(2,3,4,5) > y < c(5,4,3,2) > daten < data.frame(name,t,x,y) > erste < tapply(1:nrow(daten),daten$name, + function(i) c(daten$x[i][1],daten$y[i][1])) > erste $Hans [1] 2 5 $Susi [1] 4 3 erste enthält also jeweils die erste Datenzeile für Susie und Hans. Es ist eine Liste mit zwei Einträgen. Aber wie macht man daraus wieder eine Matrix oder ein Dataframe? Hier hilft do.call() > dat < do.call(rbind,erste) > is.matrix(dat) [1] TRUE > dat [,1] [,2] Hans 2 5 Susi 4 3 Während diese Eigenschaft sehr hilfreich bei der Arbeit mit Daten in Form von Dataframes ist, kann das unterschiedliche Verhalten bei Matrizen (ohne Spaltennamen) und Dataframes leicht zu unliebsamen Überraschungen führen. Datenauswahl und Datentransformation do.call(rbind,erste) konstruiert den Befehl rbind(erste[[1]],erste[[2]]) und rbind() fügt dann die beiden Zeilen aneinander. Das funktioniert für eine beliebige Anzahl von Listenelementen und man braucht weder ihre Zahl noch ihre Namen zu kennen. Natürlich kann man do.call() auch mit allen anderen R Befehlen benutzen, die eine beliebige Anzahl von Argumenten mit ähnlicher Bedeutung verwenden können. Da z.B. Dataframes auch Listen (von Variablen) sind, kann man etwa mit > do.call("+",daten[,2:3]) die zweite und dritte Spalte von Daten addieren. Ähnliches (mit interessanteren Funktionen) kann nützlich sein, wenn man mit sehr vielen Variablen arbeitet, so dass deren Aufzählung mühsam wird. . . Daten sortieren Vektoren können mit dem Befehl sort() sortiert werden. In Klammern wird das zu sortierende Objekt angegeben. Als Voreinstellung wird aufsteigend sortiert. > x < c(5,3,0.5,4) > sort(x) [1] 0.5 3 4 5 Eine absteigende Sortierungwird durchAngabe derOption decreasing=TRUE erreicht: > sort(x,decreasing=TRUE) [1] 5 4 3 0.5 Soll eine Datenmatrix nach einer oder mehreren Spalten sortiert werden, dann muss die zunächst etwas umständlich wirkende, aber mächtige Funktion order() verwandt werden. Das Argument von order() ist ein Vektor (oder mehrere Vektoren, deren Namen durch , zu trennen sind). Wird nur ein Vektor (eine Spalte eines Dataframes) angegeben, dann liefert die Funktion einen Vektor von Indizes zurück, so dass das erste Element des Vektors angibt, an welcher Stelle sich das kleinste Element von x befindet, das zweite Element den Index des zweit-kleinsten Elements von x angibt usw. Betrachten wir als Beispiel wieder den Vektor x < c(5,3,0.5,4). Das kleinste Element von x ist das dritte Element von x (also x[3]), das zweit-kleinste Element ist das zweite Element von x (also x[2]) usw. Die Indizes lauten also , usw. > order(x) [1] 3 2 4 1 Wennwir nun die Elemente von x nach demVektor order(x) anordnen, erhalten wir den aufsteigend sortierten Vektor: Das obige Ergebnis lässt sich eleganter und expressiver durch rowSums(daten[,2:3]) erreichen. Aber diese Funktionalität wird nur für wenige Funktionen bereitgestellt. . Datenauswahl und Zusammenführung > x[order(x)] [1] 0.5 3.0 4.0 5.0 Mit anderen Worten: order(x) ist die Permutation der Indizes von x, die x[order(x)] zu einem aufsteigend geordneten Vektor macht. Die absteigende Sortierung wird durch die Angabe von order( x) erreicht: > mox < order( x) > x[mox] [1] 5.0 4.0 3.0 0.5 Der Befehl rank() ist die Umkehrung des order() Befehls: Zu jedem Element des Vektors x wird dessen Ordnungsposition angegeben: > rank(x) [1] 4 2 1 3 Das erste Element von x ist das größte (hat den Rang ), das dritte Element hat den Rang , ist also das kleinste. Die Permutation rank() ist damit die „Umkehrung“ der Permutation der Indizes, die durch order() erzeugt wird: > o < order(x) > r < rank(x) > o[r] [1] 1 2 3 4 > r[o] [1] 1 2 3 4 Mit demBefehl order() können auchMatrizen oder Dataframes sortiert werden. Betrachten wir als Beispiel unseren Dataframe daten und sortieren ihn nach den Werten der Variablen y: > o < order(daten$y) > daten[o,] name t x y 4 Susi 2 5 2 3 Susi 1 4 3 2 Hans 2 3 4 1 Hans 1 2 5 Wird der Befehl order()mit mehr als einemArgument benutzt, dann werden weiter rechts stehende Argumente benutzt, um uneindeutige Anordnungen zu verfeinern. Gibt es mehrere Elemente gleicher Größe im ersten Argument, dann wird versucht, deren Reihenfolge durch das zweite Argument zu bestimmen. Gibt es immer noch Übereinstimmungen, wird das dritte Argument benutzt etc. Hat man etwa Geburtsdatumsangaben in den Variablen GJahr, GMonat und GTag abgelegt, dann erhält man z.B. Datumsangaben wie in diesem Beispiel bearbeitet man natürlich besser mit entsprechenden Mitteln. Das Paket chron stellt viele Funktionen einschließlich entsprechender Ordnungs- und Sortierungsmöglichkeiten für Datumsangaben bereit. Datenauswahl und Datentransformation > GJahr < c(1950,1980,1950,1980,1968,1950,1968,1950,1980,1968) > GMonat < c(1,5,1,3,11,11,12,11,1,9) > GTag < c(6,12,5,25,3,17,23,11,12,14) > order(GJahr) [1] 1 3 6 8 5 7 10 2 4 9 > order(GJahr,GMonat) [1] 1 3 6 8 10 5 7 9 4 2 > order(GJahr,GMonat,GTag) [1] 3 1 8 6 10 5 7 9 4 2 Ob die ursprüngliche Reihenfolge der Daten beibehalten wird, wenn es übereinstimmende Werte nach Betrachtung aller Argumente gibt, hängt vom intern verwandten Sortieralgorithmus ab. Der Algorithmus kann nur durch den expliziten Aufruf der spezielleren Funktion sort.list() kontrolliert werden. Bei der Sortierung nach Variablen, in denen übereinstimmende Werte vorkommen können, sollte man daher nicht ohne weiteres davon ausgehen, dass die ursprüngliche Reihenfolge der Daten bei Übereinstimmungen erhalten bleibt. Möchte man diese Reihenfolge sicherstellen (und arbeitet mit einem Dataframe), kann man als letzte Sortiervariable den Zeilennamen des Dataframes angeben. Da aber der Zeilenname eines Dataframes sich nach diversen Operationen verändern kann, sollten vor dem order() Befehl den Zeilennamen wieder ihre Ordnungsnummer zugewiesen werden: row.names(daten) <- NULL. Die Sortierungs- und Ordnungsfunktionen ordnen fehlende Werte als letzte an. Man kann sie mit der Option na.last=F auch an die erste Stelle der Ordnungsrelation setzen. . . Daten zusammenführen Dateien können auch mit Hilfe von Identifikations- oder Schlüsselvariablen zusammengefügt werden. Dabei werden Datensätze mit den gleichen Werten der Identifikationsvariablen verbunden. Als Beispiel betrachten wir die Verknüpfung von Kunden- und Umsatzdaten, die sich jeweils einem Kunden zuordnen lassen, aber zunächst in zwei getrennten Dateien gespeichert sind. Die Schlüsselvariable, über die eine adäquate Zusammenführung der Dateien möglich ist, lautet in der Kundendatei knummer und in der Umsatzdatei k. Über diese beiden Variablen werden die Kunden- und Umsatzdaten für die entsprechenden Kunden zusammengeführt: > #1. Kundendatei > knummer < c(1,2,3) > kname < c("Meier","Meier","Schmidt") > kort < c("Frankfurt","Bad Homburg","Frankfurt") > kunden < data.frame(knummer,kname,kort) > #2. Umsatzdatei . Transformationen und Rekodierungen > k < c(1,1,2,3,2,1) > u < c(1000,1500,2000,3000,2700,1100) > umsatz < data.frame(k,u) > #3. Rechnungsdatei > rechnung < merge(kunden,umsatz,by.x="knummer", + by.y="k") > rechnung knummer kname kort u 1 1 Meier Frankfurt 1000 2 1 Meier Frankfurt 1500 3 1 Meier Frankfurt 1100 4 2 Meier Bad Homburg 2000 5 2 Meier Bad Homburg 2700 6 3 Schmidt Frankfurt 3000 Im Befehl merge() gibt by.x den Namen der Identifikationsvariable im ersten Dataframe an, by.y den Namen im zweiten Dataframe. Wenn es in einem der Datensätze Angaben mit einer Identifikationsvariable gibt, die nicht im anderen Datensatz vorkommt, dann wird sie aus dem gemeinsamen Dataframe ausgeschlossen. Das kann man mit der Option all=T (oder all.x=T nur für den ersten Dataframe bzw. all.y=T nur für den zweiten Dataframe) geändert werden. Dann werden für die fehlenden Angaben im jeweils anderen Dataframe NAs eingefügt. Anzumerken ist noch, dass merge() in der Voreinstellung die Zeilen des neuen Dataframes nach den Spalten von by bzw. von by.x und by.y sortiert. Will man das vermeiden, dann kann man die Option sort=FALSE in merge() verwenden. . Transformationen und Rekodierungen Daten liegen selten schon in der Form vor, in der man sie auswerten möchte. Man hätte gern Variable in anderen Maßeinheiten (Euro statt Dollar), den Logarithmus des Einkommens statt des Einkommens, oder dieWerte einer diskreten Variablen in anderer Anordnung. Natürlich kann man einfach die Funktionen aus Kapitel verwenden. Das ist aber häufig wenig durchsichtig und zudem fehleranfällig. Die vorsichtige Behandlung von Datenänderungen und deren Dokumentation ist aber für jede Arbeit mit Daten die Grundvoraussetzung. Ein oft übergangenes Element der Arbeit mit R betrifftDataframes und deren Variablen sowie deren Transformation und Rekodierung. Transformationen mit den Mitteln des Kapitels erzeugen nur neue Vektoren imHauptspeicher. Sie ändern nie direkt die Struktur oder den Inhalt eines Dataframes. Und im Gegensatz zu Statistik-Paketen wie SPSS wird die zugrunde liegende Datei niemals verändert. Datenauswahl und Datentransformation Man wird daher zumindest bei kleinen Datensätzen entsprechend vorgehen und nach dem Einlesen von Daten aus Dateien Transformationen und Rekodierungen mit den Mitteln des Kapitels durchführen, diese ausreichend kommentieren und die Datei mit dem R-Skript abspeichern. Dann sind alle Änderungen an den Daten in der Skriptdatei dokumentiert (und hoffentlich ausreichend kommentiert). Änderungen in den Ausgangsdaten müssen dann nicht getrennt dokumentiert werden. Und Änderungen in der Programmdatei lassen sich auch leicht nachvollziehen. Allerdings kann dies Vorgehen dann nicht mehr befriedigen, wenn Datensätze sehr groß sind oder Datenänderungen sehr viel Rechenzeit erfordern. Außerdem kann man so nur mit zusätzlichem Aufwand die relativ bequemen Möglichkeiten von Dataframes benutzen. . . Transformationen Wir möchten zu den Umsätzen in unserem Dataframe rechnung die Umsatzsteuer und die Nettopreise berechnen. Nun ist die Variable u (Umsatz) sowohl in der globalen Umgebung als auch im Dataframe rechnung definiert, denn wir haben zunächst die Variable u definiert. Diese Variable befindet sich also in der globalen Umgebung. Daraus wurde dann der Dataframe rechnung konstruiert, in dem sich eine Version der Variablen u befindet. Beide Versionen unterscheiden sich aber, weil die Reihenfolge der zweiten nach der Kundennummer geordnet ist. Nur wenn man sich sicher sein kann, dass die Variable u in der globalen Umgebung identisch zu der entsprechenden Variablen im Dataframe ist (und die Variable in der globalen Umgebung nicht mehr geändert worden ist), dann reichen natürlich die Befehle > Netto < u/1.19 > USt < u Netto zur Berechnung vonNettobetrag undUmsatzsteuer. Nur entspricht das Ergebnis nicht dem entsprechenden Ergebnis, wenn die Variable rechnung$u benutzt wird. Die Reihenfolge der Einträge unterscheidet sich. Man kann also die berechneten Größen nicht einfach mit cbind() an den Dataframe anhängen. Sicherer ist es offenbar, nur mit den Werten in rechnung zu arbeiten. Die Variablen können dann auch gleich an den Dataframe angehängt werden: > rechnung$Netto < rechnung$u/1.19 > rechnung$USt < rechnung$u rechnung$Netto > rechnung knummer kname kort u Netto USt 1 1 Meier Frankfurt 1000 840.3361 159.6639 2 1 Meier Frankfurt 1500 1260.5042 239.4958 3 1 Meier Frankfurt 1100 924.3697 175.6303 4 2 Meier Bad Homburg 2000 1680.6723 319.3277 R weiß offenbar nichts von kaufmännischem Runden. 2 10 35 83 _W iS o B eh r P öt te r 2A - B g 2 . Transformationen und Rekodierungen 5 2 Meier Bad Homburg 2700 2268.9076 431.0924 6 3 Schmidt Frankfurt 3000 2521.0084 478.9916 Dabei ist der Verweis auf Variable in der Form rechnung$variable umständlich. Aber ein attach(rechnung) würde hier nicht zum Ziel führen. Denn dann würde die Variable u aus dem Dataframe an die zweite Stelle des Suchpfades gesetzt. An erster Stelle stünde immer noch das u aus der globalen Umgebung. Man hätte möglicherweise also mit der falschen Variablen gerechnet. Der Befehl transform() erleichtert die Arbeit, wenn Variable aus Dataframes transformiert werden sollen. Damit kann man auch schreiben: > rechnung < transform(rechnung,Netto2=u/1.19) > rechnung < transform(rechnung,USt2=u Netto2) Die Namen der Variablen können im transform() Befehl direkt angegeben werden, weil der Bezug durch den vorangestellten Namen eines Dataframes eindeutig ist. Das macht die Transformation unabhängig von vorherigen Definitionen und Operationen im R-Skript, die den jeweiligen Dataframe nicht betreffen. Der transform() Befehl erleichtert daher die Nachvollziehbarkeit und damit die Dokumentation der Datenaufbereitung. Aus dieser Konstruktion des transform() Befehls folgt aber auch, dass die rekursive Definition von Transformationen nicht möglich ist: USt2 kann nicht im gleichen Befehl definiert werden, in dem Netto2 definiert wurde. Denn Netto2 existiert erst nach der Zuweisung des Ergebnisses der ersten Transformation auf den Dataframe rechnung. Manchmal möchte man neue Variable aus den Werten einer Gruppe von Fällen berechnen. Man möchte etwa den Gesamtumsatz eines Kunden an die Rechnungsdatei anfügen. Natürlich kann man auf die Befehle tapply() oder by aus Kapitel zurückgreifen. Aber dann ist es schwierig, die Ergebnisse wieder an den Dataframe anzufügen, denn der Vektor etwa mit dem Namen „Gesamt“ würde nur einen Wert für jede Person enthalten, nicht aber für jeden Kauf. Der Befehl transformBy() aus dem Paket doBy erlaubt analog zu dem Befehl transform() die direkte Berechnung innerhalb des Dataframes und das Anfügen an den ursprünglichen Dataframe: > library(doBy) > rechnung < transformBy(~knummer,rechnung,Gesamt=sum(u)) Das erste Argument von transformBy() ist eine „Formel“, die aus einer Tilde ~ und anschließend dem Namen einer Index- oder Gruppierungsvariablen besteht. Definieren mehrere Variablen gemeinsam die Gruppen, dann stehen sie durch + getrennt rechts von ~. Anschließend folgt der Name eines Dataframes und als letztes eine Folge von Transformationsregeln der Form NeuerVariablenName=Funktion(). Die Transformationsfunktion wird dann getrennt auf die Zeilen des Dataframes angewandt, die durch den gleichen Wert der Indexvariable gekennzeichnet sind. Hinweis: Jeder Dataframe enthält Zeilennamen, die eindeutig sein müssen. Sie werden i.d.R. automatisch erzeugt. Befehle wie merge(), rbind(), 3 10 35 83 _W iS o B eh r P öt te r 2A - B g 3 Datenauswahl und Datentransformation transform() oder transformBy() ändern u.U. die Zeilennamen durch anhängen neuer Zahlen, wenn die Eindeutigkeit nicht gewährleistet ist. Man kann sich die Zeilennamen mit > row.names(rechnung) [1] "1.1" "1.2" "1.3" "2.4" "2.5" "3" ausgeben lassen. Nach einigen Transformationen können diese Namen relativ lang werden. Da sie Character-Strings sind, verbrauchen sie u.U. erheblichen Speicherplatz und man sollte sie dann wieder in ihre ursprüngliche Form (Integer von bis nrow()) bringen: > row.names(rechnung) < NULL . . Rekodierung In den Sozialwissenschaften besteht der Wertebereich einer Variablen oft nur aus wenigen Werten. Zu denken ist etwa an den Schulabschluss einer Person, ihre berufliche Stellung, ihren Familienstand, ihren Beruf etc. Sind die Daten als numerische Werte abgelegt, dann kann man natürlich die Transformationsmethoden des letzten Abschnitts verwenden. So ist z.B. „Geschlecht“ im Mikrozensusdatensatz mit 1 (männlich) und 2 (weiblich) kodiert. Da es oft einfacher ist, eine 0,1-kodierte Variable zu verwenden, kann man schreiben: > library(foreign) > dat < read.spss("mz02_cf.sav",to.data=T,use.value.labels=F) > geschl < dat$ef32 1 Man kann auch die transform() (oder transformBy()) Funktionen benutzen und damit die Ergebnisse direkt an den Dataframe anhängen. Das Vorgehen stößt an seine Grenzen, wenn es keine einfache Funktion gibt, die den gegebenen Wertebereich in den gewünschten transformiert. Man kann zwar den Indextrick aus der Übung des Kapitels übernehmen, wenn die ursprüngliche Kodierung nur Werte zwischen und n enthält. Alternativ kann man eine lange (und verschachtelte, damit schlecht lesbare) Folge von ifelse() Befehlen verwenden. Das ist aber nicht nur unleserlich (und damit fehleranfällig), man erzeugt zudem das Problem möglicherweise fehlerhafter Verweise auf verschiedene Versionen von Variablen gleichen Namens. In der Standardversion von R gibt es keine einfachen Funktionen, diese Probleme zu lösen. Da aber die effizienteste Art der Verwaltung und Speicherung von Variablen mit nur wenigen möglichen Werten in ihrer Speicherung als „Faktoren“ implementiert ist, gibt es verschiedene Methoden und Zusatzpakete, die die üblichen „recode“ Funktionen realisieren. Diese Methoden sind allerdings sehr effizient. Sie sind auch sicher, wenn man sie im Rahmen eines einzelnen Skripts mit Anweisungen ausführt und davon ausgehen kann, dass zu Beginn der Ausführung des Skripts keine weiteren Variablen definiert sind. Dazu kann man zu Beginn des Skripts alle anderen Variablen und Objekte durch rm(list=ls()) löschen. Übrigens ist dies auch ein weiterer guter Grund, niemals den „Workspace“ einer R Sitzung zu speichern. Denn dann würden die in der letzten R-Sitzung definierten Objekte wieder geladen und könnten zu unerwartetem Verhalten in der neuen R-Sitzung führen. . Transformationen und Rekodierungen . . Rekodierung von Faktoren Faktoren sind in R ein eigener Datentyp, der die effiziente Speicherung von Variablen mit wenigen Ausprägungen ermöglicht. Nur ist der Umgang mit diesem Datentyp recht verschieden von dem mit numerischen Variablen. Ein Faktor hat „Levels“, die verschiedenen möglichen Ausprägungen, sowie zugehörige „Labels“. Sowohl die Levels als auch die Labels sind „Character Strings“, können also nicht direkt in numerischen Berechnungen verwandt werden. Diese Konstruktion erzeugt Schwierigkeiten, wenn man die numerischen Fähigkeiten von R ausnützen möchte. Denn Faktoren mit passend generierten Labels erzeugen zwar in statistischen Prozeduren besser lesbare Ergebnisse (die Labels werden zur Bezeichnung benutzt), können aber nur begrenzt wie numerische Variable benutzt werden. Zudem muss beim Verweis auf Werte der Faktoren das entsprechende Label angegeben werden, und das heißt, das schon kleine Tippfehler zu Fehlern führen. Nehmen wir unser Rechnungsbeispiel und suchen die Umsätze von Frau Meier: > is.factor(rechnung$kname) [1] TRUE > rechnung$u[rechnung$kname=="Meier"] [1] 1000 1500 1100 2000 2700 ist korrekt, aber die beiden Befehle > rechnung$u[rechnung$kname=="meier"] > rechnung$u[rechnung$kname=="Meier "] liefern jeweils nur die leere Menge numeric(0). Manchmal kann man sich behelfen, indem man Levels, die ursprünglich numerische Werte waren, in numerische Vektoren zurückverwandelt. Dann kann man versuchen, statt mit den Namen mit den zugrundeliegenden Codes zu rechnen. Dazu muss man die Levels des Faktors mit levels() suchen, diese in numerische Werte verwandeln, und das dann auf alle Elemente des Faktors anwenden. > test < rep(1:3,2) > test > [1] 1 2 3 1 2 3 > test2 < factor(test) > test2 [1] 1 2 3 1 2 3 Levels: 1 2 3 > levels(test2) [1] "1" "2" "3" > is.character(levels(test2)) [1] TRUE > as.numeric(levels(test2)) [1] 1 2 3 Datenauswahl und Datentransformation > all.equal(test,as.numeric(levels(test2))[test2]) [1] TRUE Das geht aber nur, wennmanmit numerischenWerten und Vektoren begonnen hat. Z.B. haben wir bisher die SPSS-Datei des Mikrozensus mit der Option use.value.labels=F eingelesen, die dafür sorgt, alle numerischen Daten auch als numerische Vektoren in R darzustellen. Die Voreinstellung im Befehl read.spss() des Pakets foreign ist aber, die sogenannten „Value Labels“ der SPSS-Datei zu benutzen und alle Variablen mit „Value Labels“ in R-Faktoren zu verwandeln, bei denen für die Levels die „Value Labels“ von SPSS benutzt werden. Das sind aber i.d.R. keine (umgewandelten) Zahlen: > library(foreign) > dat < read.spss("mz02_cf.sav",to.data=T) > is.factor(dat$ef35) #Familienstand > [1] TRUE > summary(dat$ef35) Ledig Verheiratet Verwitwet Geschieden 9648 12149 2029 1311 > levels(dat$ef35) [1] "Ledig" "Verheiratet" "Verwitwet" "Geschieden" Soweit sieht alles aus, wie es sein sollte. Aber > as.numeric(levels(dat$ef35)) funktioniert nun nicht mehr, weil die Levels von vornherein „Character Strings“ sind. Und Rekodierungen müssten die jeweils exakten Namen der Labels verwenden. Wenn man nur die Information behalten möchte, ob jemand verheiratet ist, dann kann man etwa schreiben: > verh < dat$ef35 > levels(verh) < c("Nicht Verheiratet","Verheiratet", + "Nicht Verheiratet","Nicht Verheiratet") > summary(verh) Nicht Verheiratet Verheiratet 12988 12149 recode Verschiedene Pakete stellen Möglichkeiten für die einfachere Umkodierung von Variablen und insbesondere von Faktoren bereit. Wir besprechen hier nur die Version des Pakets memisc. Damit läßt sich das obige Beispiel durchsichtiger schreiben: > library(memisc) > verh2 < recode(dat$ef35,"Nicht Verheiratet" < + c("Ledig","Verwitwet","Geschieden"),otherwise="copy") Weitere Pakete, die ähnliche Fähigkeiten bereitstellen, sind u.a. car, epicalc und doBy. . Übungsaufgaben > all.equal(verh,verh2) [1] TRUE Mit der Option otherwise="copy" werden die nicht genannten Label übernommen. Die Voreinstellung ist, nicht genannte Label durch den Wert NA zu ersetzen. Man kann aber auch einen beliebigen anderen Wert einsetzen. Es können an Stelle des zweiten Arguments auch mehrere Ausdrücke mit < auftreten. Wenn wenigstens einer der neuen Werte (der Ausdruck links vom < Zeichen) vom Typ Character ist, dann wird ein Faktor erzeugt. . Übungsaufgaben 1) Erzeugen Sie den folgenden Dataframe mit dem Namen dat pid name dob IQ 1 Susi 1946 79 2 Carmen 1954 131 3 Herbert 1937 122 4 Karl 1932 93 2) Erzeugen Sie aus diesem Dataframe einen neuen Dataframe dat2, der nur die Variablen name und dob enthält, indem Sie den subset Befehl (alternativ: den Selektionsbefehl []) verwenden. 3) Erzeugen Sie aus diesem Dataframe einen neuen Dataframe dat3, der nur die Beobachtungen von Susi und Karl enthält, indem Sie den subset Befehl (alternativ: den Selektionsbefehl []) verwenden. 4) Sortieren Sie den Dataframe dat absteigend nach dob und kopieren Sie das Ergebnis auf den Dataframe dat4. 5) Lesen Sie die Daten des Mikrozensus ein und berechnen Sie das Durchschnittsalter der Befragten (Variable ef30, beachten Sie die Kodierung!). 6) Rekodieren Sie die Variable ef35 (Familienstand) des Mikrozensus , so dass nur noch festgehalten wird, ob jemand ledig ist oder jemals verheiratet war. 7) Betrachten Sie die Variable ef372 (Nettoeinkommen jeder Person im Haushalt). Die Antworten sind in Intervallen angegeben und numerisch kodiert. Rekodieren Sie die Angaben, indem Sie jeweils die mittleren Werte der Intervallober- und -untergrenze einsetzen. Welcher Wert eignet sich für das höchste Einkommensintervall? 8) Berechnen Sie die Summe der Nettoeinkommen je Haushalt nach der obigen Umkodierung. Kann das Ergebnis mit der Variablen ef539 (Haushaltsnettoeinkommen) verglichen werden? Wenn ja, welche Abweichungen würden Sie erwarten? (Sie können dabei Gemeinschaftsunterkünfte unberücksichtigt lassen.)

Chapter Preview

References

Zusammenfassung

Vorteile

- Einführung in die statistische Analyse mit R für Wirtschafts- und Sozialwissenschaftler

- Inklusive hilfreicher Tipps wie "Ansprechende Grafiken mit R gestalten"

Zum Thema

R ist ein Statistikprogramm, das kostenlos über das Internet verbreitet wird und dessen Source Codes frei zugänglich sind.

Aufgrund dieses kostenlosen Angebots gehen immer mehr Dozenten dazu über, neben SPSS auch R zu lehren bzw. SPSS durch R zu ersetzen.

In R steht dem Nutzer die gesamte Bandbreite statistischer Verfahren zur Verfügung. Durch die eigenständige Programmierumgebung ist die Software sehr flexibel und erlaubt notwendige Modifikationen und Erweiterungen verfügbarer Prozeduren.

Zum Werk

Dieses Buch führt leicht verständlich in die statistische Analyse mit R ein. Anhand von Beispielen wird die Umsetzung der wichtigsten Methoden der Statistik, wie sie üblicherweise in den Grundkursen gelehrt werden, mit R vorgestellt.

Das Buch verfolgt entsprechend zwei Ziele:

1. Vorstellung der statistischen Methoden,

2. Benutzung des Werkzeuges R zur Analyse von Daten.

Inhalt

- Grundlagen von R

- Datenbehandlung und graphische Darstellungen mit R

- Datenbeschreibungen (deskriptive Statistik)

- Wahrscheinlichkeitsverteilungen

- Regressionsanalysen

- Optimierungsverfahren

- Simulationen mit R

Neben vielen neuen, wirtschaftsorientierten Beispielen wird nun auch in die Paneldatenanalyse und Stichprobentheorie eingeführt.

Zu den Autoren

Dr. Andreas Behr ist wissenschaftlicher Mitarbeiter am Institut für Statistik und Ökonometrie der Universität Münster.

Dr. Ulrich Pötter ist wissenschaftlicher Mitarbeiter am Institut für Statistik der Universität Bochum.

Zielgruppe

Für Studierende und Dozenten der Wirtschaftswissenschaften im Bachelor an Universitäten und Fachhochschulen.