3 Data Frames

Eine äußerst wichtige Datenstruktur in R ist der Data Frame. Das ist eine zwei-dimensionale Tabelle. Die Zeilen werden auch observations genannt und die Spalten variables (nicht zu verwechseln mit den Variablen, d.h. abgespeicherten Werten und Objekten, wie im vorherigen Kapitel besprochen!). In der Phonetik arbeiten wir sehr häufig mit Data Frames, z.B. wenn wir akustische Informationen aus Sprachaufnahmen oder Messungen aus einem Perzeptionsexperiment extrahiert haben und diese auswerten oder statistisch analysieren wollen.

3.1 Import & Export

In R gibt es verschiedene Möglichkeiten, eine Tabelle im Format .csv oder .txt einzulesen. Wenn Sie eine Tabelle von Ihrer Festplatte einlesen wollen, können Sie im Panel mit dem Environment in der Werkzeugleiste auf Import Dataset klicken und sich von dem Assistenten leiten lassen. Der Befehl, den der Assistent zum Laden des Data Frames verwendet, wird übrigens in der Konsole angezeigt.

In diesem Kurs werden wir u.a. Data Frames von einer Webseite benutzen, daher müssen wir den Befehl zum Einlesen selbst schreiben. Der Befehl, den wir verwenden, lautet read.table(), und bekommt als wichtigstes Argument in Anführungszeichen den Pfad (bzw. die URL) zu dem Data Frame (aber schauen Sie auf die Hilfeseite dieser Funktion, um alle Argumente und weitere verwandte Funktionen zum Einlesen von Daten zu sehen):

ai <- read.table("http://www.phonetik.uni-muenchen.de/~jmh/lehre/Rdf/ai.txt")

Da wir im Verlauf der Vorlesung mehrere Data Frames von derselben Webseite verwenden werden, können wir das Einlesen etwas cleverer gestalten, damit wir nicht immer wieder die komplizierte URL abtippen oder kopieren müssen. Dafür legen wir eine Variable mit der URL als Schriftzeichenobjekt an und verwenden dann die Funktion file.path(), mittels derer die URL und der Dateiname zusammengefügt werden:

url <- "http://www.phonetik.uni-muenchen.de/~jmh/lehre/Rdf"
file.path(url, "ai.txt")
## [1] "http://www.phonetik.uni-muenchen.de/~jmh/lehre/Rdf/ai.txt"
# zusammen mit dem Befehl zum Einlesen:
ai <- read.table(file.path(url, "ai.txt"))

Das Gegenstück zu read.table() ist write.table(), womit Sie einen Data Frame abspeichern können. Diese Funktion bekommt zuerst den Namen des Objekts, das abgespeichert werden soll, dann den Pfad samt gewünschtem Dateinamen (./ steht für das aktuelle Verzeichnis), und als weiteres optionales Argument nutzen wir row.names = FALSE, damit es nicht eine Spalte mit den (hier nicht vorhandenen) Zeilennamen in dem abgespeicherten Data Frame gibt.

write.table(ai, file.path("./", "ai.txt"), row.names = FALSE)

Natürlich können Sie Data Frames nicht nur einlesen, sondern auch selbst erstellen. Dafür wird der Befehl data.frame() verwendet. Diese Funktion bekommt als Argumente die Spaltennamen und anschließend die Werte, die in der Spalte stehen sollen. Hier ein Beispiel:

df <- data.frame(F1 = c(240, 220, 250, 210, 280, 520, 510, 605, 670, 613),
                 vowel = rep(c("i","o"), each = 5))
df
##     F1 vowel
## 1  240     i
## 2  220     i
## 3  250     i
## 4  210     i
## 5  280     i
## 6  520     o
## 7  510     o
## 8  605     o
## 9  670     o
## 10 613     o

Data Frames haben eine eigene Objektklasse:

class(df)
## [1] "data.frame"

3.2 Eigenschaften

Wenn wir mit Datenstrukturen arbeiten, die viele Informationen enthalten, ist es wichtig, uns mit dem Objekt vertraut zu machen. R bietet viele nützliche Funktionen, um sich Data Frames anzuschauen und etwas über deren Eigenschaften zu erfahren:

# Data Frame in einem Sub-Fenster anschauen
View(ai)
# Nur die ersten oder letzten paar Zeilen (Beobachtungen) ausgeben
head(ai)
##     F1 Kiefer  Lippe
## 1  773 -25.48 -24.60
## 2  287 -27.03 -26.44
## 3 1006 -27.25 -27.59
## 4  814 -26.06 -27.17
## 5  814 -26.15 -25.93
## 6  806 -26.37 -24.45
tail(ai)
##      F1 Kiefer  Lippe
## 20  888 -25.99 -26.85
## 21  988 -26.27 -28.27
## 22  650 -26.50 -24.31
## 23 1026 -27.10 -24.64
## 24  992 -28.41 -28.31
## 25  896 -26.57 -25.69
# Reihen- und Spaltenanzahl
nrow(ai)
## [1] 25
ncol(ai)
## [1] 3
dim(ai)
## [1] 25  3
# Spaltennamen (Variablennamen)
colnames(ai)
## [1] "F1"     "Kiefer" "Lippe"
names(ai)
## [1] "F1"     "Kiefer" "Lippe"

3.3 Auf Spalten zugreifen

Obwohl wir in den kommenden Kapiteln mit der modernen tidyverse-Syntax arbeiten werden, wollen wir hier zeigen, wie man in traditioneller Weise auf Spalten in einem Data Frame zugreifen kann. Manchmal werden Sie nicht darum herum kommen, diese traditionelle Notation zu verwenden.

Wenn Sie in Ihr Environment schauen, sehen Sie, dass dort unter “Values” die ganzen einfachen Variablen und Vektoren stehen und unter “Data” finden Sie die zwei Data Frames ai und df. Als Informationen zu den Data Frames stehen im Environment immer die Anzahl an observations (Zeilen) und variables (Spalten), z.B. 25 obs. of 3 variables. Wenn Sie auf das kleine blaue Icon links neben dem Namen des Data Frames klicken, sehen Sie die Spaltennamen, welcher Objektklasse die Spalten angehören (int für integer, num für numerics bzw. doubles, usw.) und die ersten paar Werte aus der Spalte. Dieselben Informationen erhalten Sie, wenn Sie die Funktion str() (structure) auf einen Data Frame anwenden:

str(ai)
## 'data.frame':    25 obs. of  3 variables:
##  $ F1    : int  773 287 1006 814 814 806 938 1005 964 931 ...
##  $ Kiefer: num  -25.5 -27 -27.2 -26.1 -26.2 ...
##  $ Lippe : num  -24.6 -26.4 -27.6 -27.2 -25.9 ...
str(df)
## 'data.frame':    10 obs. of  2 variables:
##  $ F1   : num  240 220 250 210 280 520 510 605 670 613
##  $ vowel: chr  "i" "i" "i" "i" ...

Vor jeder Spalte in dieser Auflistung steht ein Dollarzeichen. Genau so können Sie auf Spalten in einem Data Frame zugreifen: Sie schreiben den Namen des Data Frames, dann (ohne Lehrzeichen!) das Dollarzeichen, und anschließend (wieder ohne Leerzeichen!) den Spaltennamen:

df$F1
##  [1] 240 220 250 210 280 520 510 605 670 613

Sie sehen, dass eine Spalte an und für sich nichts anderes ist als ein Vektor! Das heißt, Sie können die Funktionen, mit denen wir zuvor Vektoren manipuliert haben, jetzt auch auf Spalten in Data Frames anwenden:

length(df$F1)
## [1] 10
table(df$vowel)
## 
## i o 
## 5 5

Weiterführende Infos: Factors in Data Frames

Für den Data Frame df, den wir oben selbst angelegt haben, sehen Sie im Environment, dass die Spalte vowel der Objektklasse factor angehört, und dass dieser factor zwei levels hat – obwohl wir die Spalte vowel mit Schriftzeichen gefüllt hatten! Die Funktion data.frame(), mit der wir df erstellt haben, hat ein Argument namens stringsAsFactors, das, wenn nicht anders angegeben, automatisch TRUE ist. Das heißt, beim Erstellen des Data Frames wurden die Schriftzeichen in der Spalte vowel in einen factor umgewandelt. Die zwei verschiedenartigen Werte (Kategorien) in dieser Spalte sind “i” und “o”, dementsprechend hat dieser factor zwei levels.

Wenn Sie sich nochmal die Informationen zu dem Data Frame df im Environment oder Ihrer Konsole anschauen, werden Sie feststellen, dass die Spalte vowel nicht nur ein Faktor mit zwei Levels ist, sondern dass die ersten Werte in dieser Spalte komischerweise Zahlen sind und nicht “i” und “o”. Das liegt daran, dass Faktoren im Hintergrund (also für die NutzerInnen meist unsichtbar) als integer abgespeichert werden. Diese integer sind mit den einzigartigen Levels des Faktors assoziiert. Wenn also in unserem Environment bei der Spalte vowel der Wert 1 steht, dann repräsentiert dies das Level “i”, der Wert 2 repräsentiert das Level “o”.

Wenn Sie beim Erstellen des Data Frames verhindern möchten, dass strings in factors umgewandelt werden, verwenden Sie das Argument stringsAsFactors = FALSE:

df <- data.frame(F1 = c(240, 220, 250, 210, 280, 520, 510, 605, 670, 613),
                 vowel = rep(c("i","o"), each = 5),
                 stringsAsFactors = FALSE)