Arbeiten mit Daten

Werbung
Arbeiten mit Daten
Session 3
1
Lesen und Schreiben von Daten
Größere Datenmengen werden üblicherweise nicht manuell in die R Konsole eingegeben, sondern aus
Files eingelesen. Hierbei gibt es grundsätzlich mehrere verschiedene Möglichkeiten, die in den nächsten
Abschnitten besprochen werden.
1.1
Daten in Binärfiles
Einlesen der Daten aus einem R-Data-File. R bietet die Möglichkeit Daten aus der Konsole in sogenannte Datenfiles abzuspeichern. Diese Speicherung erfolgt standardmäßig in binärer Form und ist somit
weitaus speichereffizienter als das Speichern in ASCII Files (Textfiles). Diese Speichereffizienz wirkt sich
hauptsächlich beim Abspeichern von Zahlen aus. Die Speicherung in einem ASCII File verbraucht für
jede Zahl 16 Zeichen, also 16 Byte. Die binäre Speicherung hingegen verbraucht lediglich 64 Bit also 8
Byte und ist zudem in der Lage eine höhere Genauigkeit abzubilden. Das Speichern in R Daten Files
erfolgt durch den Befehl save(x, filenamen, ascii = FALSE) oder wenn der gesamte Workspace gesichert
werden soll: save.image(file = ”.RData”, ascii = FALSE). Die entsprechenden Befehle zum Laden lauten
load(. . . ) und load.image(. . . ). load() lädt hierbei alle Elemente der entsprechenden Datei in den Speicher.
Um dies zu vermeiden und um Hauptspeicher zu sparen, steht die Funktion attach() zur Verfügung, welche
die R Konsole nur über die Existenz der Daten in dem File ”informiert”. Wird eine Variable von einem
Programm oder der Konsole benötigt, dann wird diese automatisch in den Speicher geladen.
1.2
Daten in ASCII Files
Die Speicherung von Zahlen als Zeichen ist zwar ineffizient, bietet sich aber oft als die einzige Lösung an,
wenn man Daten zwischen verschiedenen Plattformen portieren muss. Eine standardardisierte Möglichkeit
Daten in ASCII Form zu speichern, stellt das sogenannte Comma Seperated Value (CSV) File Format dar.
Hierbei werden in einer Textdatei Werte - durch gewisse Trennzeichen (zB Komma, Return, Semikolon,
. . . ) von einander getrennt - gespeichert. Man verwendet zum Lesen der Daten in ein CSV-File, die
Funktion read.table(file, header = FALSE, sep = ””, dec = ”.”, row.names, col.names, na.strings =
”NA”, comment.char = ”#”). Diese bietet eine Vielzahl von möglichen Einstellungen, die die Struktur
der einzulesenden Datei beschreiben. Es kann zum Beispiel angegeben werden, ob die Datei als erste Zeile
eine sogenannte header Zeile aufweist, also eine Zeile in der die Namen der Variablen angegeben sind.
Ist dies nicht der Fall, kann man alternativ die Namen über die Variable col.names spezifizieren. Weiters
existieren Möglichkeiten zum Anpassen des verwendeten seperators, des Dezimalzeichens (dec) und der
Zeichenkette, die einen Fehlenden Wert (na.strings) bzw ein Kommentar (comment.char ) signalisiert. Zum
Schreiben von CSV Dateien wird der Befehl write.table(. . . ) mit einer ähnlichen Parameterliste verwendet.
Während der Befehl load(. . . ) Daten in dem Format wieder herstellt in dem sie gespeichert wurden,
gibt read.table(. . . ) ein sogenanntes data frame zurück (siehe Sektion 2).
1.3
Direkter Datenbankzugriff
Es ist auch möglich Daten direkt aus einer Datenbank oder zum Beispiel aus Excel in R einzulesen. Diese
Möglichkeiten werden hier aus Zeitgründen nicht behandelt.
1
2
Data Frames
Statistische Daten werden in R meist in data frames gespeichert. Data Frames sind zum Beispiel auch der
Output der Funktion read.table(. . . ). Ein Data Frame speichert Beobachtungen (cases), welche für statistische Auswertungen verwendet werden können. Grundsätzlich haben Data Frames eine Matrixstruktur,
wobei eine Spalte alle Daten zu einem Merkmal und eine Zeile alle Daten zu einem case enthält. Wir lesen
nun Daten aus der Datei electionAustria.csv ein
> (elections <- read.table(file=’’electionsAustria.csv’’, sep=’’;’’, dec=’’,’’))
Wahlb. OVP SPO FPO Grüne andere
25.11.1945 3449606 49.80 44.60 NA NA 5.60
09.10.1949 4391815 44.00 38.70 11.70 NA 5.60
22.02.1953 4586870 41.30 42.10 10.90 NA 5.70
13.05.1956 4614464 46.00 43.00 6.50 NA 4.50
10.05.1959 4696603 44.20 44.80 7.70 NA 3.30
18.11.1962 4805351 45.40 44.00 7.00 NA 3.60
06.03.1966 4886818 48.40 42.60 5.40 NA 3.60
01.05.1970 5045841 44.70 48.40 5.50 NA 1.40
10.10.1971 4984448 43.10 50.00 5.50 NA 1.40
05.10.1975 5019277 42.90 50.40 5.40 NA 1.30
06.05.1979 5186735 41.90 51.00 6.10 NA 1.00
24.04.1983 5316436 43.20 47.60 5.00 NA 4.20
23.11.1986 5461414 41.30 43.10 9.70 4.80 1.10
07.10.1990 5628912 32.10 42.80 16.60 4.80 3.70
09.10.1994 5774000 27.70 34.90 22.90 7.30 7.20
17.12.1995 5768039 28.30 38.10 22.00 4.80 6.80
03.10.1999 5838373 26.90 33.20 26.90 7.40 5.60
24.11.2002 5912592 42.30 36.50 10.00 9.50 1.70
01.10.2006 6107686 34.33 35.34 11.04 11.05 8.24
> summary(elections)
Die Befehl summary() angewandt auf ein Data Frame Objekt, zeigt eine kurze Zusammenfassung der
Daten an. Für jede Spalte werden sowohl Extremwerte (max, min), alle Quartile als auch der Erwartungswert und die Anzahl der fehlenden Beobachtungen ausgegeben. Die Funktion summary() ist nicht nur für
Data Frames, sondern auch für viele andere Objekttypen (zB Ergebnisse von Schätzungen) definiert und
dient dazu sich einen raschen, summarischen Überblick über die in einem Objekt gespeicherten Daten zu
verschaffen.
Eine weitere Möglichkeit sich einen Überblick über die Struktur eines Objektes zu verschaffen, bietet
der Befehl str(dataframe). Er zeigt an wieviele Objekte welchen Types sich in dem Data Frame bzw in
den einzelnen Spalten befinden.
> str(elections)
’data.frame’: 19 obs. of 6 variables:
$ Wahlberechtigte: int 3449606 4391815 4586870 4614464 4696603 4805351 4886818 ...
$ OVP : num 49.8 44 41.3 46 44.2 45.4 48.4 44.7 43.1 42.9 ...
$ SPO : num 44.6 38.7 42.1 43 44.8 44 42.6 48.4 50 50.4 ...
$ FPO : num NA 11.7 10.9 6.5 7.7 7 5.4 5.5 5.5 5.4 ...
$ Grüne : num NA NA NA NA NA NA NA NA NA NA ...
$ andere : num 5.6 5.6 5.7 4.5 3.3 3.6 3.6 1.4 1.4 1.3 ...
2
Um direkt auf die Daten zuzugreifen, verwendet man die Indizierung mittels des $ Symboles. Hierbei
geht man wie folgt vor.
> elections$SPO
[1] 44.60 38.70 42.10 43.00 44.80 44.00 42.60 48.40 50.00 50.40 51.00 47.60 43.10 ...
Man verwendet $ also zum Indizieren eines bestimmten Feldes des Objektes elections. Für diese Indizierung braucht man den Namen der entsprechenden Spalte. Um sich die Namen eines Data Frames anzeigen
zu lassen verwendet man den Befehl names(dataframe) oder colnames(dataframe), der die Namen der
Spalten anzeigt. Um sich die Namen der Zeilen anzeigen zu lassen, wird er Befehl rownames(dataframe)
verwendet. Man kann diese Funktionen auch verwenden, um die Namen in einem Data Frame zu ändern.
> rownames(elections) <- c(’’1945’’, ’’1949’’, ’’1953’’, ’’1956’’, ’’1959’’, ...)
Alternativ kann kam auf die Daten in einem Data Frame mittels Indizierung durch Zahlen zugreifen:
so gibt zum Beispiel der Befehl
> spo <- elections[3]
> mode(spo)
[1] ’’list’’
die dritte Spalte des Data Frames (die Ergebnisse der SPÖ) als Liste (mit Labels) zurück. Der Befehl
> spo <- elections[[3]]
> mode(spo)
[1] ’’numeric’’
hingegen liefert die selben Werte allerdings diesmal als Vektor - ohne die Struktur aus dem Data
Frames (ohne die Labels).
Nachträgliche Datenmanipulation kann ebenfalls auf beide oben beschriebenen Arten durchgeführt
werden, also zum Beispiel
> elections$Wahlberechtigte <- round(elections$Wahlberechtigte/1000)*1000
oder
> elections[1] <- round(elections[1]/1000)*1000
3
Fehlende Werte (NA) Oft enthalten Daten fehlende Werte, welche in R NA genannt werden. Wendet
man eine Funktion auf Daten an, die fehlende Werte enthalten, dann ist das Ergebnis in vielen Fällen
wieder NA.
> mean(elections$Grüne)
[1] NA
Da die Grünen nicht seit Anbeginn der zweiten Republik existieren, sind in dem Data Frame elections
bis zum Jahr 1986 NA Werte bei den Grünen eingetragen. Daher liefert die Funktion mean() den Wert NA.
Andere Funktionen zeigen ein ähnliches Verhalten (var(), diverse Plots, . . . ). Um dennoch den gewünschten
Mittelwert auszurechnen, muss man die Daten entweder von NA bereinigen oder der verwendeten Funktion
mitteilen diese zu ingnorieren. Ersteres is mit der Funktion na.omit(data) möglich, welche eine um die
NAs bereinigte Datenstruktur zurückgibt. Vorsicht bei Dataframes werden hierbei alle Reihen, die ein
zumindest ein NA enthalten weggelassen!
> elections$Grüne
[1] NA NA NA NA NA NA NA NA NA NA NA NA
[13] 4.80 4.80 7.30 4.80 7.40 9.50 11.05
> mean(na.omit(elections$Grüne))
[1] 7.092857
Die zweite Methode wird durch die Übergabeparameter na.action (Werte: na.pass oder na.fail ) und
na.rm (Werte: T oder F) gesteuert.
> mean(elections$Grüne, na.rm = T)
[1] 7.092857
Die Funktion is.na(data) überprüft, ob eine Datenstruktur NAs enthält. Der Rückgabewert hat die
selbe Struktur wie daten, die Werte sind allerdings vom Typ logical.
> is.na(elections$Grüne)
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[13] FALSE FALSE FALSE FALSE FALSE FALSE FALSE
> sum(is.na(elections$Grüne))
[1] 12
> if(sum(is.na(elections$Grüne))>0) { ... } else { ... }
In der letzten Zeile wird in dem if statement abgefragt, ob der Vektor elections$Grüne zumindest ein
NA enthält.
Not a Number (NaN) und Inf Manche Berechnungen führen zu einem nicht definierten Ergebniss
(zB ∞−∞). Solche Berechnungen liefern statt einer Zahl den Wert NaN. Manche Berechnungen wiederum
resultieren in dem Wert unendlich (Inf).
4
> 0/0
[1] NaN
> Inf-Inf
[1] NaN
> 1/0
[1] Inf
> log(0)
[1] -Inf
Ob das Ergebnis einer Berechnung endlich bzw eine Zahl ist, kann mit is.finite(data) und is.nan(data)
getestet werden.
2.1
Zusammenführen von Data Frames
Ähnlich zu den Möglichkeiten, die in man SQL durch diverse join Befehle hat, lassen sich in R durch
die Funktion merge(. . . ) Data Frames zusammenfügen. Die Funktion fügt zwei Data Frames anhand
übereinstimmender Spaltenwerte zusammen. So werden zB die beiden Datenframes
vorname
Max
Emilia
Fritz
nachname
Mustermann
Mustermann
Maier
gehalt
1200
2500
1500
vorname
Max
Fritz
Herbert
nachname
Mustermann
Maier
Huber
alter
22
65
3
mit dem Befehl
> merge(data1, data2)
zu
vorname nachname
Fritz
Maier
Max
Mustermann
gehalt alter
1500 65
1200 22
Es werden also nur jene Zeilen in das Resultat übernommen, welche in allen Spalten, die in beiden Data
Frames vorhanden sind, übereinstimmen (entspricht SQL inner join). Man verwendet die Option all.x=T,
all.y=T oder all=T, um entweder alle Einträge des ersten (SQL: left join), des zweiten (SQL: right join)
oder beiden ((SQL: outer join) Data Frames in das Ergebnis zu zwingen (fehlende Werte werden mit NAs
aufgefüllt).
3
Faktoren
Mittels Faktoren können in R Ordinal- und Nominalskalen realisiert werden. Man definiert Faktoren mit
der Funktion factor(x, levels, labels). Ein Faktor enthält einerseits Daten und andererseits eine Variable
levels, welche alle möglichen Levels angibt. Levels können mit der labels Option benannt werden. Die
Option levels ermöglicht es explizit alle zulässigen Levels anzugeben.
5
> geschlecht <- c(’’m’’, ’’w’’, ’’w’’, ’’w’’, ’’m’’, ’’w’’, ’’m’’, ’’m’’)
> (f1 <- factor(geschlecht)
[1] m w w w m w m m
Levels: m w
> f2 <- factor(geschlecht, levels =c(’’m’’, ’’w’’), labels = c(’’männlich’’, ’’weiblich’’))
[1] männlich weiblich weiblich weiblich männlich weiblich männlich männlich
Levels: männlich weiblich
Die Funktion levels() ermöglicht es sicht die Levels eines Faktors ausgeben zu lassen und schreibend
auf dieselben zuzugreifen. Letzteres ist nützlich, wenn man Levels umsortieren, umbenennen oder zusammenfassen will.
> (levels(f2) <- levels(f2)[c(2, 1)])
[1] ’’weiblich’’ ’’männlich’’
> (levels(f2) <- c(’’Frau’’, ’’Mann’’))
[1] ’’Frau’’ ’’Mann’’
Die Funktion unique(data) extrahiert, alle vorkommenden Levels aus einem gegebenen Datenvektor.
> unique(geschlecht)
[1] ’’m’’ ’’w’’
Geordnete Faktoren Bis jetzt haben wir nur ungeordneten Faktoren kennen gelernt (obwohl durch
die Angabe von levels eine gewisse Ordnung definiert wurde, die aber - außer in Spezialfällen - keine
Auswirkungen hat). Soll R Faktoren als explizit ordenbare Faktoren (also ordinalskaliert) behandeln,
dann verwendet man statt des Befehles levels(. . . ) den Befehel ordered(. . . ). Dieser hat im Wesentlichen
den selben Syntax mit dem einzigen Unterschied, dass die Reihenfolge der Levels in dem levels Argument
als Ordnung zwischen den Levels interpretiert wird.
> bildung <- c(’’vs’’, ’’hs’’, ’’hs’’, ’’ahs’’, ’’ahs’’, ’’fh’’, ’’hs’’, ’’uni’’)
> (f <- ordered(bildung, levels=c(’’vs’’, ’’hs’’, ’’ahs’’, ’’fh’’, ’’uni’’)))
[1] vs hs hs ahs ahs fh hs uni
Levels: vs < hs < ahs < fh < uni
Nicht geordnete Faktoren können mit der Funktion ordered(factor) geordnet werden, die Ordnung
entsteht dadurch aus der Ordnung der Levels in dem ungeordneten Faktor.
Metrische Variablen können mit der Funktion cut() in Faktoren umgewandelt werden.
> zigarettenKonsum <- c(0, 1, 25, 0, 35, 15, 12, 0, 60, 0, 5, 0, 20, 10, 30)
> cut(zigarettenKonsum, breaks=c(-0.1, 0, 10, 30, 100), labels=c(’’NR’’, ’’LR’’, ’’R’’, ’’SR’’
[1] NR LR R NR SR R R NR SR NR LR NR R LR R
Levels: NR LR R SR
6
tapply() Die Funktion tapply(x, factors, fun) kann dazu verwendet werden, die Funktion auf die Teilmengen von x anzuwenden, die den selben Level in dem übergebenen Faktor haben (siehe Hausübung
Beispiel 5).
4
Beispiele
1. Generiere eine 1000 × 1000 Matrix von Zufallszahlen (benutze zB die Funktion runif(. . . )) und
speichere das Resultat in ein ASCII File (Textfile) und als R Datenfile. Vergleiche die Dateigrößen.
2. Lade 3 Finanzdatenreihen (historische Aktienkurse) mit täglichen Daten über 3 Jahre von http:
//finance.yahoo.com/ herunter und bringe diese in eine Form, dass Sie sich als Data Frame einlesen
lassen. Verwende alle Felder (open, high, low, close, . . . ).
3. Generiere ein neues Data Frame indem Du die alle Einträge außer die Schlußkurse aus Beispiel 2
löschst und berechne mittels einer selbst geschriebenen Funktion die täglichen Returns rt der Aktien
t
wobei xt der Kurs zum Zeitpunkt t ist). Speichere die Returns in ein Data Frame.
(ie rt = xxt−1
4. Generiere einen Data Frame (Dimension 10 × 3) mit beliebigen Spaltenlabels (zB Spalte1, Spalte2,
Spalte3).
(a) Speichere dieses Data Frame unter Verwendung von write.table(), wobei das Trennzeichen ’:’
und das Kommazeichen ’,’ sein soll.
(b) Lösche alle Variablen im Workspace und lies die soeben gespeicherten Daten wieder in R ein.
5. Betrachte die folgenden beiden Vektoren
g = (m, m, m, w, w, w, m, m, w, m, m, w, w, w, m, m, m, m, w, m)
und
r = (4, 2, 2, 4, 1, 1, 2, 2, 3, 1, 2, 3, 0, 4, 1, 2, 1, 1, 0, 1)
Der Vektor g beschreibt das Geschlecht und der Vektor r die Rauchgewohnheiten einer Population
mit 20 Individuen (0 entspricht hierbei einem Nichtraucher und 4 einem schweren Raucher).
(a) Erstelle Faktoren aus den Vektoren r und g und vergib passende Namen für die Levels.
(b) Benutze die Funktion table(. . . ), um Häufigkeitstabellen für die beiden Faktoren zu erstellen.
(c) Benutze die Funktion tapply(. . . ), um das mittlere Alter der Personen in den einzelnen Raucherlevels zu berechnen. Das Alter der Testpersonen sei hierbei durch den Vektor
a = (28, 86, 62, 99, 61, 50, 52, 57, 36, 44, 70, 48, 92, 42, 76, 79, 79, 89, 41, 92)
gegeben. Wiederhole die Analyse mit der zweidimensionalen Klassifikation nach Geschlecht und
Raucherlevels.
6. Lade das Datenfile Session3BSP6.R von der Homepage herunter.
(a) Lade die beiden Data Frames in R und benutze den Befehl merge(. . . ), um inner, left, right
und outer joins der beiden Variablen zu erstellen.
(b) Verwende die Funktion cut(. . . ), um die Variable Einkommen in dem Data Frame, das durch
den inner join entsteht, zu Kategorisieren (4 Kategorien).
(c) Erstelle eine Häufigkeitstabelle.
7
Herunterladen