Starten Sie das R Projekt, das Sie für diesen Kurs angelegt haben. Öffnen Sie hierfür RStudio und benutzen Sie die Schaltfläche oben rechts oder navigieren Sie zu Ihrem Kursverzeichnis und klicken Sie auf die .Rproj
Datei.
Laden Sie dann die folgenden Packages:
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✓ ggplot2 3.3.5 ✓ purrr 0.3.4
## ✓ tibble 3.1.4 ✓ dplyr 1.0.7
## ✓ tidyr 1.1.3 ✓ stringr 1.4.0
## ✓ readr 2.0.1 ✓ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
library(magrittr)
##
## Attaching package: 'magrittr'
## The following object is masked from 'package:purrr':
##
## set_names
## The following object is masked from 'package:tidyr':
##
## extract
Wir werden diese Woche mit verschiedenen Data Frames arbeiten, die wir vom IPS-Server laden. Die URL legen wir als Variable an und benutzen diese dann in der Funktion file.path()
.
<- "http://www.phonetik.uni-muenchen.de/~jmh/lehre/Rdf"
url <- read.table(file.path(url, "asp.txt"))
asp <- read.table(file.path(url, "intdauer.txt"))
int <- read.table(file.path(url, "coronal.txt"))
coronal <- read.table(file.path(url, "vdata.txt")) vdata
Wenn man sich einen Überblick über Daten verschaffen möchte, sind sogenannte summary statitics (deskriptive Statistiken) häufig hilfreich. Zu solchen deskriptiven Werten zählen z.B. das arithmetische Mittel (Mittelwert), Median, Varianz, Standardabweichung, Minimum, Maximum, usw. Hier zeigen wir zunächst wie man solche Werte ohne Funktionen aus dem tidyverse berechnen kann. Da R eine Statistik-Software ist, sind solche Basis-Funktionen wie zur Berechnung des Mittelwerts immer verfügbar. Im Folgenden demonstrieren wir die wichtigsten Funktionen zur Berechnung von summary statistics anhand der F1-Werte in vdata
:
mean(vdata$F1) # arithmetisches Mittel
## [1] 407.2877
median(vdata$F1) # Median
## [1] 366
var(vdata$F1) # Varianz
## [1] 21254.52
sd(vdata$F1) # Standardabweichung
## [1] 145.7893
min(vdata$F1) # Minimum
## [1] 0
max(vdata$F1) # Maximum
## [1] 1114
range(vdata$F1) # Minimum & Maximum
## [1] 0 1114
quantile(vdata$F1, 0.25) # 1. Quartil
## 25%
## 300
quantile(vdata$F1, 0.75) # 3. Quartil
## 75%
## 509.75
IQR(vdata$F1) # interquartiler Bereich
## [1] 209.75
Das arithmetische Mittel wird berechnet, indem man die Summe einer Anzahl \(n\) an Zahlen bildet, und diese Summe dann durch die Anzahl \(n\) teilt. Hier ist ein sehr einfaches Beispiel:
<- 1:5
zahlen <- sum(zahlen)
summe summe
## [1] 15
<- length(zahlen)
anzahl anzahl
## [1] 5
# Mittelwert:
/anzahl summe
## [1] 3
# zum Vergleich:
mean(zahlen)
## [1] 3
Der Median hingegen ist die mittig liegende Zahl in einer sortierten Zahlenreihe. Nehmen wir wieder obiges Beispiel (die Zahlen sind bereits aufsteigend sortiert):
zahlen
## [1] 1 2 3 4 5
median(zahlen)
## [1] 3
Bei einer geraden Anzahl von Zahlen berechnet man den Median als den Mittelwert der zwei mittig liegenden Werte, zum Beispiel:
<- 1:6
zahlen median(zahlen)
## [1] 3.5
mean(c(3, 4))
## [1] 3.5
Der Median ist robuster gegen sogenannte Ausreißer (engl. outlier) als der Mittelwert. Ausreißer sind Datenpunkte, die deutlich extremer sind als die Mehrheit der Datenpunkte. Hier wieder ein einfaches Beispiel:
<- c(1:5, 100)
zahlen zahlen
## [1] 1 2 3 4 5 100
mean(zahlen)
## [1] 19.16667
median(zahlen)
## [1] 3.5
Die Zahl 100 ist ganz offensichtlich ein Ausreißer im Vektor zahlen
. Der Mittelwert ist wegen dieses Ausreißers jetzt um ein Vielfaches höher als vorher, während der Median sich nur leicht verändert hat.
Varianz und Standardabweichung sind verwandte Maße für die Streuung von Werten um ihren Mittelwert. Genauer gesagt ist die Varianz die Summe der quadrierten Abweichungen der Messwerte von ihrem Mittelwert geteilt durch die Anzahl der Messwerte minus 1, während die Standardabweichung die Quadratwurzel der Varianz ist. Am folgenden Beispiel können Sie nachvollziehen, wie man die Varianz und Standardabweichung “händisch” berechnet:
<- c(12, 6, 24, 3, 17)
zahlen # Mittelwert
<- mean(zahlen)
m m
## [1] 12.4
# quadrierte Abweichungen
<- (zahlen - m)^2
quadr_abw quadr_abw
## [1] 0.16 40.96 134.56 88.36 21.16
# Anzahl der Messwerte
<- length(zahlen)
n n
## [1] 5
# Summe der quadrierten Abweichungen
<- sum(quadr_abw)
summe summe
## [1] 285.2
# Varianz:
<- summe / (n - 1)
varianz varianz
## [1] 71.3
# Mit der Funktion var():
var(zahlen)
## [1] 71.3
Um jetzt die Standardabweichung daraus zu berechnen, die in der Statistik viel häufiger verwendet wird als die Varianz, brauchen wir nur noch die Quadratwurzel aus der Varianz zu ziehen:
<- sqrt(varianz)
std_abw std_abw
## [1] 8.443933
# oder mit sd()
sd(zahlen)
## [1] 8.443933
Ein Quantil teilt Datenpunkte so auf, dass ein bestimmter Teil der Datenpunkte unterhalb des Quantils liegen. Quantil ist ein Überbegriff; je nachdem in wie viele Stücke man die Datenpunkte aufteilt, sagt man auch Perzentil (100 Stücke) oder Quartil (4 Stücke). Der Median ist ebenfalls ein Quantil, denn 50% der Daten liegen immer unter dem Median. In R berechnet die Funktion quantile()
die Quantile. Die Funktion bekommt zuerst die Datenpunkte (also einen numerischen Vektor) und anschließend die Proportion der Datenpunkte, die unter dem zu berechnenden Wert liegen soll. Wichtige Quantile sind das erste und dritte Quartil, also die Schwellwerte, unter denen ein Viertel bzw. drei Viertel aller Datenpunkte liegen.
quantile(vdata$F1, 0.25) # 1. Quartil
## 25%
## 300
quantile(vdata$F1, 0.75) # 3. Quartil
## 75%
## 509.75
IQR(vdata$F1) # interquartiler Bereich
## [1] 209.75
Die Differenz zwischen dem ersten und dritten Quartil wird auch interquartiler Bereich oder Interquartilsabstand (interquartile range) genannt und kann mit der Funktion IQR()
berechnet werden.
Ein Boxplot enthält viele der deskriptiven Informationen, die wir bis jetzt behandelt haben:
1.5 * IQR
liegt. Diese Berechnung der Länge der Whiskers als 1.5 * IQR
gilt für Boxplots, die mit ggplot2
erstellt wurden, aber nicht jeder Boxplot wird so berechnet.Hier sehen Sie den Boxplot für F1
aus dem Data Frame vdata
:
Wie man diesen Boxplot erstellt, erfahren Sie später in dieser Vorlesung.
dplyr
(Fortsetzung)Zu Beginn dieser Vorlesung haben wir summary statistics für F1-Werte aus dem Data Frame vdata
berechnet. Natürlich geht das auch innerhalb der tidyverse-Syntax, nämlich mit der Funktion summarise()
aus dem Package dplyr
. Diese Funktion verändert den Data Frame grundlegend, denn die ursprünglichen Daten werden zu neuen Werten zusammengefasst. Dies betrifft sowohl die Anzahl der Spalten als auch der Anzahl der Zeilen. summarise()
erstellt neue Spalten und keine der originalen Spalten werden beibehalten. Die Funktion bekommt als Argument also den/die neuen Spaltennamen und wie die Werte in dieser neuen Spalte berechnet werden sollen:
%>% summarise(mittelwert = mean(F1)) vdata
## mittelwert
## 1 407.2877
Der Output dieser Pipe ist ein Data Frame mit nur einer Spalte und einer Zeile. Wir können aber auch mehrere deskriptive Werte gleichzeitig berechnen und erhalten dadurch mehr Spalten:
%>% summarise(mittelwert = mean(F1),
vdata std_abw = sd(F1),
summe = sum(F1),
maximum = max(F1),
Q1 = quantile(F1, 0.25))
## mittelwert std_abw summe maximum Q1
## 1 407.2877 145.7893 1214532 1114 300
Die Funktionen mutate()
und summarise()
haben also gemein, dass sie neue Spalten erstellen; während in mutate()
aber alle ursprünglichen Zeilen und Spalten erhalten bleiben, erstellt summarise()
einen ganz neuen Data Frame mit deutlich weniger Zeilen als ursprünglich vorhanden waren (denn hier wurden Werte zusammengefasst).
Was würden Sie jetzt tun, wenn Sie den F1-Mittelwert für nur einen bestimmten Vokal V
aus dem Data Frame berechnen wollen? Vermutlich würden Sie dies wie folgt lösen (für den Vokal V == "E"
):
%>%
vdata filter(V == "E") %>%
summarise(mittelwert = mean(F1))
## mittelwert
## 1 426.2447
Der F1-Mittelwert für “E” ist also ca. 426 Hz. Wenn Sie sich für die vokalspezifischen F1-Mittelwerte interessieren, dann ist es nicht mehr sinnvoll, für jeden einzelnen Vokal den obigen Code zu benutzen. Stattdessen gibt es die Funktion group_by()
. group_by()
bekommt als Argumente alle Spalten, nach denen gruppiert werden soll. summarise()
berechnet die gewünschten summary statistics anschließend pro Gruppe. In unserem Beispiel gruppieren wir nach Vokal und berechnen dann den Mittelwert pro Vokal:
%>%
vdata group_by(V) %>%
summarise(mittelwert = mean(F1))
## # A tibble: 7 × 2
## V mittelwert
## <chr> <dbl>
## 1 % 424.
## 2 A 645.
## 3 E 426.
## 4 I 311.
## 5 O 434.
## 6 U 304.
## 7 Y 302.
Es wurden zwei Spalten erstellt: Die eine enthält die sieben verschiedenen Vokale aus dem originalen Data Frame, die andere die vokalspezifischen F1-Mittelwerte. Sie können natürlich auch nach mehr als einer Spalte gruppieren. Es ist zum Beispiel anzunehmen, dass sich der mittlere F1 nicht nur von Vokal zu Vokal unterscheidet, sondern dass auch der Gespanntheitsgrad Tense
einen Einfluss hat. Deshalb gruppieren wir nach Vokal und Gespanntheitsgrad und berechnen dann den mittleren F1:
%>%
vdata group_by(V, Tense) %>%
summarise(mittelwert = mean(F1))
## `summarise()` has grouped output by 'V'. You can override using the `.groups` argument.
## # A tibble: 14 × 3
## # Groups: V [7]
## V Tense mittelwert
## <chr> <chr> <dbl>
## 1 % - 479.
## 2 % + 368.
## 3 A - 622.
## 4 A + 668.
## 5 E - 488.
## 6 E + 363.
## 7 I - 346.
## 8 I + 276.
## 9 O - 520.
## 10 O + 348.
## 11 U - 348.
## 12 U + 259.
## 13 Y - 338.
## 14 Y + 266.
Wir sehen jetzt also den F1-Mittelwert für nicht gespannte “%”, gespannte “%” (ignorieren Sie die seltsame Vokal-Kodierung), nicht gespannte “A”, gespannte “A”, usw.
Weiterführende Infos: summarise()
warning
Oben sehen Sie eine Warnmeldung, die von summarise()
geworfen wurde. Warnmeldungen sind dazu da, Sie auf etwas aufmerksam zu machen – Sie sollten sie also nicht ignorieren. Diese Warnmeldung zeigt erstmal an, dass das Ergebnis des Codes ein gruppierter Data Frame ist (Objektklasse grouped_df
) und dass die Gruppierungsvariable V
ist:
%>%
vdata group_by(V, Tense) %>%
summarise(mittelwert = mean(F1)) %>%
class()
## `summarise()` has grouped output by 'V'. You can override using the `.groups` argument.
## [1] "grouped_df" "tbl_df" "tbl" "data.frame"
Die Warnmeldung zeigt außerdem, dass man die Gruppierung des Ergebnisses auch verändern kann, indem man das summarise()
-Argument .groups
verwendet. Dieses Argument kann verschiedene Werte annehmen, wie Sie auf der Hilfsseite der Funktion summarise()
nachlesen können.
Bei den vorherigen Code Snippets, bei denen wir group_by()
im Zusammenspiel mit summarise()
verwendet haben, ist die Warnmeldung übrigens deshalb nicht aufgetaucht, weil wir nur nach einer Variable gruppiert haben; im Ergebnis wird diese Gruppierung automatisch aufgehoben.
Es ist wichtig zu verstehen, dass nur nach kategorialen Spalten gruppiert werden kann. Es ergibt keinen Sinn, nach nicht-kategorialen numerischen Spalten zu gruppieren, denn hier gibt es keine Gruppen (jeder Wert ist vermutlich einzigartig). Der Sinn von summarise()
ist es aber ja gerade, deskriptive Statistiken für kategoriale Gruppen zu berechnen.
Zuletzt wollen wir noch die Funktionen n()
und n_distinct()
vorstellen. n()
benötigt keine Argumente und wird nach group_by()
innerhalb summarise()
verwendet, um die Anzahl an Beobachtungen (Zeilen) pro Gruppe zurückzugeben. n_distinct()
bekommt als Argument den Namen einer Spalte und findet heraus, wie viele unterschiedliche (einzigartige) Werte einer Variable es pro Gruppe gibt.
# Anzahl an Zeilen für jede Kombination von V und Tense
%>%
vdata group_by(V, Tense) %>%
summarise(count = n())
## `summarise()` has grouped output by 'V'. You can override using the `.groups` argument.
## # A tibble: 14 × 3
## # Groups: V [7]
## V Tense count
## <chr> <chr> <int>
## 1 % - 214
## 2 % + 212
## 3 A - 218
## 4 A + 214
## 5 E - 215
## 6 E + 210
## 7 I - 214
## 8 I + 210
## 9 O - 214
## 10 O + 214
## 11 U - 215
## 12 U + 208
## 13 Y - 213
## 14 Y + 211
# Anzahl der einzigartigen Sprecher pro Region und sozialer Klasse
%>%
coronal group_by(Region, Socialclass) %>%
summarise(count = n_distinct(Vpn))
## `summarise()` has grouped output by 'Region'. You can override using the `.groups` argument.
## # A tibble: 9 × 3
## # Groups: Region [3]
## Region Socialclass count
## <chr> <chr> <int>
## 1 R1 LM 40
## 2 R1 UM 30
## 3 R1 W 11
## 4 R2 LM 26
## 5 R2 UM 18
## 6 R2 W 36
## 7 R3 LM 22
## 8 R3 UM 31
## 9 R3 W 26
Weiterführende Infos: Funktionen eindeutig beschreiben
Da die Funktionen aus dem tidyverse, insbesonderen aus dplyr
, sehr gängige Namen haben (filter()
, summarise()
, rename()
), werden sie leicht von Funktionen mit demselben Namen aus anderen Paketen maskiert. Wenn Sie also von einer dieser Funktionen einen Fehler bekommen, laden Sie entweder noch einmal das Paket, aus dem die Funktion stammen soll (z.B. library(dplyr)
), oder nutzen Sie die folgende Schreibweise: dplyr::filter()
.
In der alltäglichen Arbeit mit Data Frames kann es sinnvoll sein, den Data Frame nach Zeilen oder Spalten zu ordnen. Für das Ordnen der Zeilen wird arrange()
benutzt, für das Ordnen der Spalten relocate()
. Hier ordnen wir den Data Frame int
aufsteigend nach Dauer:
%>% arrange(Dauer) int
## Vpn dB Dauer
## 10 S2 25.60 55
## 5 S1 23.47 67
## 7 S2 30.08 81
## 14 S1 20.88 103
## 9 S1 21.37 116
## 2 S2 32.54 120
## 4 S2 28.38 131
## 13 S1 26.60 144
## 1 S1 24.50 162
## 6 S2 37.82 169
## 8 S1 24.50 192
## 15 S2 26.05 212
## 3 S2 38.02 223
## 12 S1 44.27 232
## 11 S1 40.20 252
arrange()
kann auch alphabetisch oder nach mehreren Spalten ordnen:
%>% arrange(Vpn, Dauer) int
## Vpn dB Dauer
## 5 S1 23.47 67
## 14 S1 20.88 103
## 9 S1 21.37 116
## 13 S1 26.60 144
## 1 S1 24.50 162
## 8 S1 24.50 192
## 12 S1 44.27 232
## 11 S1 40.20 252
## 10 S2 25.60 55
## 7 S2 30.08 81
## 2 S2 32.54 120
## 4 S2 28.38 131
## 6 S2 37.82 169
## 15 S2 26.05 212
## 3 S2 38.02 223
Um absteigend zu ordnen, wird desc()
(descending) innerhalb von arrange()
genutzt:
%>% arrange(Vpn, desc(Dauer)) int
## Vpn dB Dauer
## 11 S1 40.20 252
## 12 S1 44.27 232
## 8 S1 24.50 192
## 1 S1 24.50 162
## 13 S1 26.60 144
## 9 S1 21.37 116
## 14 S1 20.88 103
## 5 S1 23.47 67
## 3 S2 38.02 223
## 15 S2 26.05 212
## 6 S2 37.82 169
## 4 S2 28.38 131
## 2 S2 32.54 120
## 7 S2 30.08 81
## 10 S2 25.60 55
relocate()
bekommt als Argumente die Namen aller Spalten, die umsortiert werden sollen. Wenn sonst keine weiteren Argumente angegeben werden, werden die Spalten an den Anfang des Data Frames gesetzt. Ansonsten können die Argumente .before
und .after
verwendet werden, um anzugeben, vor oder nach welche Spalten die anderen Spalten gesetzt werden sollen:
%>% slice(1) vdata
## X Y F1 F2 dur V Tense Cons Rate Subj
## 1 52.99 4.36 313 966 106.9 % - P a bk
%>% relocate(Subj) %>% slice(1) vdata
## Subj X Y F1 F2 dur V Tense Cons Rate
## 1 bk 52.99 4.36 313 966 106.9 % - P a
%>% relocate(Subj, Cons) %>% slice(1) vdata
## Subj Cons X Y F1 F2 dur V Tense Rate
## 1 bk P 52.99 4.36 313 966 106.9 % - a
%>% relocate(where(is.numeric), .after = Subj) %>% slice(1) vdata
## V Tense Cons Rate Subj X Y F1 F2 dur
## 1 % - P a bk 52.99 4.36 313 966 106.9
%>% relocate(where(is.character), .before = dur) %>% slice(1) vdata
## X Y F1 F2 V Tense Cons Rate Subj dur
## 1 52.99 4.36 313 966 % - P a bk 106.9
ggplot2
ggplot2
ist eine Library aus dem tidyverse
, die Ihnen sehr viele Möglichkeiten für die Visualisierung von Daten liefert. gg
steht für grammar of graphics. Der Befehl, mit dem Sie eine Abbildung beginnen, ist ggplot()
; das Hauptargument dieser Funktion ist der gewünschte Data Frame. Dann fügt man das sog. aesthetic mapping mittels aes()
, sowie Funktionen für die Art der Abbildung, die Beschriftungen, die Legende, etc., hinzu. Jede Funktion wird mit +
verbunden (nicht mit Pipes!).
Boxplots sind die wohl wichtigsten wissenschaftlich genutzten Abbildungen. In R werden sie mit dem Befehl geom_boxplot()
erstellt. Zuerst zeigen wir, wie der oben verwendete Boxplot erstellt wurde. Die Funktion ggplot()
bekommt den Data Frame vdata
. In den aesthetic mappings aes()
tragen wir ein, dass F1 auf der y-Achse aufgetragen werden soll. Zuletzt bestimmen wir noch, dass ein Boxplot gezeichnet werden soll.
ggplot(vdata) +
aes(y = F1) +
geom_boxplot()
Zugegeben, der Boxplot sieht ein bisschen anders aus als der Boxplot oben. Wie man diesen Plot “verschönert”, lernen Sie nächste Woche. Boxplots eignen sich sehr gut zum Vergleichen von Werten für verschiedene kategoriale Gruppen. Dann werden diese Gruppen (üblicherweise) auf der x-Achse aufgetragen und auf der y-Achse wieder die gewünschten Werte. Hier sehen Sie ein Beispiel für die Dauer verschiedener Konsonanten aus dem Data Frame asp
:
ggplot(asp) +
aes(x = Kons, y = d) +
geom_boxplot()
Boxplots können auch horizontal erstellt werden (wobei das meist weniger übersichtlich ist). Dann werden die Kategorien auf der y-Achse und die Werte auf der x-Achse aufgetragen:
ggplot(asp) +
aes(x = d, y = Kons) +
geom_boxplot()
Manchmal ist ein sogenannter Notch gewünscht; dafür nutzen wir das Argument notch = TRUE
in der Funktion geom_boxplot()
(und ggf. notchwidth
, um die Tiefe des Notches anzupassen):
ggplot(asp) +
aes(x = Kons, y = d) +
geom_boxplot(notch = TRUE)
ggplot(asp) +
aes(x = Kons, y = d) +
geom_boxplot(notch = TRUE, notchwidth = 0.3)
Weiterführende Infos: Aesthetic mappings & Piping Data Frames
Streng genommen sind die aesthetic mappings immer ein Argument der Funktion, die über die Art des Plots bestimmt (also z.B. geom_boxplot()
). Später werden Sie feststellen, dass manche Plots bestimmte aesthetic mappings benötigen bzw. zulassen, die andere Plots nicht verarbeiten können. Wir lagern die aesthetic mappings in den allermeisten Fällen aus der Plot-Funktion aus, weil das übersichtlicher ist. Es steht Ihnen aber frei, die aesthetic mappings in die Funktion als Argument reinzuschreiben:
ggplot(asp) +
geom_boxplot(aes(x = Kons, y = d),
notch = TRUE,
notchwidth = 0.3)
Innerhalb eines ggplot
werden die einzelnen Funktion immer und ausschließlich mit einem Pluszeichen verbunden. Der Data Frame allerdings kann mit einer einfachen Pipe an ggplot()
übergeben werden:
%>%
asp ggplot() +
aes(x = Kons, y = d) +
geom_boxplot()
Das ist besonders hilfreich, wenn Sie vor dem Plotten erst noch weitere Funktionen auf den Data Frame anwenden wollen, bevor sie die daraus entstehenden Daten plotten. Hier filtern wir zum Beispiel zuerst nach Betonung, bevor wir anschließend nur noch die Dauer der betonten Wörter plotten:
%>%
asp filter(Bet == "be") %>%
ggplot() +
aes(x = Kons, y = d) +
geom_boxplot()
Scatterplots werden mit den Funktionen geom_point()
und/oder geom_line()
erstellt. Man kann auch beide Funktionen gleichzeitig verwenden. Auf die x- und y-Achse werden üblicherweise nur numerisch-kontinuierliche Daten aufgetragen. Im Folgenden plotten wir zum Beispiel Lautstärke in Dezibel gegen Dauer.
# Punkte:
ggplot(int) +
aes(x = Dauer, y = dB) +
geom_point()
# Linie:
ggplot(int) +
aes(x = Dauer, y = dB) +
geom_line()
# Beides:
ggplot(int) +
aes(x = Dauer, y = dB) +
geom_line() +
geom_point()
Manchmal ist es hilfreich, vertikale oder horizontale Referenzlinien in einem Plot einzuzeichnen. Horizontale Linien werden mit geom_hline()
erzeugt, vertikale gerade Linien mit geom_vline()
. Um eine horizontale Linie zu zeichnen, muss bekannt sein, an welcher Stelle die Linie die y-Achse schneidet. Deshalb bekommt geom_hline()
immer das Argument yintercept
. Bei geom_vline()
muss mit xintercept
die Schnittstelle der vertikalen Linie mit der x-Achse eingetragen werden. Wir fügen zum obigen Scatterplot zwei gerade Linien hinzu:
ggplot(int) +
aes(x = Dauer, y = dB) +
geom_point() +
geom_vline(xintercept = 150) +
geom_hline(yintercept = 35)
Eine weitere wichtige Abbildungsform sind Barplots, die mit geom_bar()
erzeugt werden. Dabei darf nur entweder x
oder y
in den aesthetic mappings verwendet werden. Das liegt daran, dass auf die jeweils andere Achse grundsätzlich ein count oder eine Proportion aufgetragen wird, die von ggplot
berechnet wird. Der folgende Plot zeigt zum Beispiel, wie viele Vorkommnisse dreier Regionen im Data Frame coronal
zu finden sind.
ggplot(coronal) +
aes(x = Region) +
geom_bar()
Die Balken können wir auch horizontal plotten, indem wir in den aesthetic mappings y
statt x
angeben:
ggplot(coronal) +
aes(y = Region) +
geom_bar()
Die Werte der Balken können Sie ganz einfach nachvollziehen, indem Sie sich die Anzahl der Vorkommnisse der drei Regionen mittels der Funktion table()
anzeigen lassen:
table(coronal$Region)
##
## R1 R2 R3
## 81 80 79
Beim Barplot können Sie aber wie z.B. beim Boxplot noch eine weitere (kategoriale) Variable plotten. Die zweite Variable, die abgebildet werden soll, wird mit dem Argument fill
angegeben, das die Levels der Variable als Füllfarben darstellt. Sie werden nächste Woche u.a. lernen, wie man Farben selbst bestimmen kann. Im Folgenden sieht man, wie häufig die Frikative Fr
“s” (rot) und “sh” (blau) jeweils in den drei Regionen produziert wurden.
ggplot(coronal) +
aes(x = Region, fill = Fr) +
geom_bar()
Lassen Sie uns mittels der zuvor gelernten Funktionen für Grouping und Summarising die Werte in diesem Plot nachvollziehen. Dafür gruppieren wir nach Region und Frikativ und lassen uns dann mit n()
innerhalb von summarise()
die Anzahl der Zeilen im Data Frame pro Gruppenkombination bestimmen.
%>%
coronal group_by(Region, Fr) %>%
summarise(count = n())
## `summarise()` has grouped output by 'Region'. You can override using the `.groups` argument.
## # A tibble: 6 × 3
## # Groups: Region [3]
## Region Fr count
## <chr> <chr> <int>
## 1 R1 s 58
## 2 R1 sh 23
## 3 R2 s 59
## 4 R2 sh 21
## 5 R3 s 66
## 6 R3 sh 13
Die Funktion geom_bar()
kann als Argument noch position
bekommen…
# ...um Proportionen anstatt einer absoluten Anzahl darzustellen:
ggplot(coronal) +
aes(x = Region, fill = Fr) +
geom_bar(position = "fill")
# ...um die Balken nebeneinander zu stellen:
ggplot(coronal) +
aes(x = Region, fill = Fr) +
geom_bar(position = "dodge")
Histogramme zeigen die Verteilung von numerisch-kontinuierlichen Datenpunkten, indem sie den Wertebereich in mehrere kleine Bereiche einteilt. Ähnlich wie beim Barplot zeigen dann Balken (bins) an, wie viele Werte in einem bestimmten Wertebereich liegen. In ggplot
werden Histogramme mit geom_histogram()
erstellt. In den aesthetic mappings legen wir mit dem Argument x
fest, welche Daten wir anschauen wollen, zum Beipspiel die F1-Verteilung:
ggplot(vdata) +
aes(x = F1) +
geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Um die einzelnen Balken besser voneinander unterscheiden zu können, lassen wir die Balken weiß umranden, indem wir geom_histogram()
das Argument color = "white"
übergeben:
ggplot(vdata) +
aes(x = F1) +
geom_histogram(color = "white")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Wir können auch selbst bestimmen, wie breit die Balken sein sollen, nämlich mit binwidth
. Im Moment umfasst ein Balken ca. 40 Hz. Die folgenden Abbildungen zeigen die exakt selben Daten, aber mit Balken von 10 Hz und Balken von 100 Hz:
ggplot(vdata) +
aes(x = F1) +
geom_histogram(color = "white",
binwidth = 10)
ggplot(vdata) +
aes(x = F1) +
geom_histogram(color = "white",
binwidth = 100)
Sie sehen, dass dies für die Repräsentation der Daten einen großen Unterschied macht – gehen Sie also immer mit Bedacht vor, wenn Sie die binwidth von Histogrammen verändern.
Mit dem Histogramm verwandt ist die Wahrscheinlichkeitsdichte (engl. probability density). Die einzige Änderung, die wir dafür vornehmen müssen, ist aes()
das Argument y = ..density..
zu übergeben. Dies verändert die y-Achse so, dass statt der Anzahl an Datenpunkten die Wahrscheinlichkeitsdichte der Datenpunkte angezeigt wird. Per definitionem ist die Fläche unter den Balken der Wahrscheinlichkeitsdichte insgesamt 1.
ggplot(vdata) +
aes(x = F1, y = ..density..) +
geom_histogram(color = "white",
binwidth = 100)
Die Wahrscheinlichkeitsdichte wird berechnet als count / (n * binwidth)
, wo n
die Anzahl aller Datenpunkte ist. In dem Histogramm oben (mit binwidth = 100
) liegen zum Beispiel 285 Datenpunkte (count) im Wertebereich zwischen 150 Hz und 250 Hz. Die Wahrscheinlichkeitsdichte für diesen Balken wird also wie folgt berechnet:
<- 285
count <- nrow(vdata)
n <- 100
binwidth <- count / (n * binwidth)
dens dens
## [1] 0.0009557344
Dieser Wert stimmt mit dem density-Wert überein, den wir in der Wahrscheinlichkeitsdichteverteilung für denselben Balken sehen.
Die Fläche dieses Balkens in der Wahrscheinlichkeitsdichteverteilung wird berechnet als binwidth * binheight
:
<- binwidth * dens
area area
## [1] 0.09557344
Wenn man die Fläche aller Balken berechnet und summiert, ist die Gesamtfläche 1.
Stellen Sie sich nun ein Wahrscheinlichkeitsdichte-Histogramm vor, das aus unendlich vielen Balken besteht (die dementsprechend unendlich schmal sein müssen). Sie erhalten nicht mehr einzelne Balken sondern eine kontinuierliche Funktion, die sich Wahrscheinlichkeitsdichteverteilung (probability density function) nennt. Auch dafür kennt ggplot2
eine Funktion: geom_density()
.
ggplot(vdata) +
aes(x = F1) +
geom_density()
Hier gilt genau wie bei dem Histogramm mit der Wahrscheinlichkeitsdichte, dass das Integral (die Fläche) unter der Kurve 1 ist. Weshalb das wichtig ist, erfahren Sie übernächste Woche.
Weiterführende Infos: Histogramme und Probability Density
Für weitere Informationen schauen Sie sich gerne Wilke’s Fundamentals of Data Visualization in R, Kapitel 7 an.