Grafiken sind für die Datenanalyse sehr wichtig. Einerseits können wir sie für explorative Datenanalyse einsetzen, um eventuell verborgene Zusammenhänge zu entdecken oder uns einfach einen Überblick zu verschaffen. Andererseits brauchen wir Grafiken, um Resultate darzustellen und anderen zu kommunizieren.
Schritt 1: Wir beginnen mit einem Datensatz und erstellen ein Plot-Objekt mit der Funktion ggplot().
Schritt 2: Wir definieren sogenannte “aesthetic mappings”, d.h. wir bestimmen welche Variablen auf den X-, bzw. Y-Achsen dargestellt werden sollen, und welche Variablen benutzt werden, um die Daten zu gruppieren. Die Funktion, welche wir dafür benutzen heisst aes().
Schritt 3: Wir fügen dem Plot eine oder mehrere “Layers” oder “Schichten” hinzu. Diese Layers definieren, wie etwas dargestellt werden soll, z.B. als Linie oder als Histogramm. Die Funktionen beginnen mit dem Präfix geom_, z.B. geom_line().
Um **ggplot2* zu benutzen brauchen wir nun noch einen zusätzlichen Operator: +. Diesen kennen Sie bereits als mathematischen Operator, aber in diesem Zusammenhang bedeutet die Verwendung von +, dass wir einzelne Elemente eines Plot-Objektes zusammenfügen.
Nach dieser etwas abstrakten Einführung illustrieren wir diese Schritte an einem praktischen Beispiel.
Am Ende des letzten Kapitels haben wir den Zusammenhang zwischen psychischem Stress und Geschlecht untersucht. Wir laden nun nochmals den Datensatz:
library(tidyverse)
library(haven)
beispieldaten <- read_sav("C:/Users/koar/OneDrive - Kt. SG BLD/Dokumente/Rkurs24/RPubsN/Re_ Statistik mir R/beispieldaten.sav") |>
# Faktoren konvertieren und SPSS-Labels zuweisen
mutate(across(where(is.labelled), haven::as_factor)) |>
# Labels der Bildungsfaktoren vereinfachen
mutate(across(c(bildung_vater, bildung_mutter),
\(x) fct_recode(x,
Hauptschule = "Hauptschulabschluss oder niedriger",
Realschule = "Realschulabschluss (mittlere Reife)",
Abitur = "Fachabitur, Abitur",
Hochschule = "Fachhochschulabschluss, Universitätsabschluss")))
str(beispieldaten)
und erstellen einen Datensatz, der nur die Variablen ID, geschlecht und stress_psychisch enthält.
stress <- beispieldaten |>
select(ID, geschlecht, stress_psychisch) |>
drop_na()
stress
In diesem Datensatz haben wir eine numerische Variable, stress_psychisch und eine Gruppierungsvariable, geschlecht. Wir wollen die Verteilung von stress_psychisch zwischen männlichen und weiblichen Jugendlichen vergleichen. Die Verteilung können wir auf verschiedene Arten grafisch darstellen: mit Punkten, einem Boxplot oder einem Violin-Plot. Diese drei Methoden sind in der Sprache von ggplot2 verschiedene geoms und können so benutzt werden: geom_point(), geom_boxplot() oder geom_violin(). Zusätzlich gibt es noch eine Funktion geom_jitter(), welche die Punkte in einem Punktdiagramm nicht aufeinander zeichnet, sondern mit einem zufälligen horizontalen “jittering” (Flackern) versieht.
Das ggplot2 Package können wir entweder individuell oder als Teil des tidyverse laden:
library(ggplot2)
# oder
library(tidyverse)
Wir beginnen mit einem Datensatz und erstellen ein Plot-Objekt mit der Funktion ggplot(). Diese Funktion hat als erstes Argument einen Dataframe. Dies bedeutet, dass wir den pipe Operator verwenden können:
# 1. Variante
p <- ggplot(data = stress)
# 2. Variante
p <- stress |>
ggplot()
oder
Nun definieren wir mit dem zweiten Argument mapping die aesthetic mappings. Diese bestimmen, wie die Variablen benutzt werden, um die Daten darzustellen, und werden mit der Funktion aes() definiert. Wir wollen die Gruppierungsvariable geschlecht auf der X-Achse darstellen und stress_psychisch soll auf der Y-Achse angezeigt werden. Zusätzlich kann aes() weitere Argumente haben: fill, color, shape, linetype, group. Diese werden dazu benutzt, um den Stufen der Gruppierungsvariablen (Faktoren) unterschiedliche Farben, Formen, Linien, etc. zuzuweisen.
In diesem Beispiel haben wir die Gruppierungsvariable geschlecht und wir wollen, dass die beiden Stufen von geschlecht verschiedene Farben haben und mit verschiedenen Farben “ausgefüllt” werden.
color ist ein Attribut von Linien oder Punkten, fill ist ein Attribut von Flächen.
Wenn wir die aesthetic mappings innerhalb der Funktion ggplot() definieren, gelten sie für alle Layers, d.h. für alle Elemente des Plots. Wir könnten diese mappings auch für jede Layer separat definieren.
p <- stress |>
ggplot(mapping = aes(
x = geschlecht,
y = stress_psychisch,
color = geschlecht,
fill = geschlecht
))
p ist nun ein “leeres” Plot-Objekt. Wir können es uns anschauen, aber es wird noch nichts angezeigt, da es noch keine Layers enthält.
Dem Plot-Objekt p können wir nun mit geom_ Funktionen Layers hinzufügen. Die Syntax funktioniert so: Wir “addieren” zu dem Plot-Objekt p ein geom: p + geom_
Wir versuchen zuerst, die Beobachtungen als Punkte darzustellen:
# die Funktion geom_point() hat ein size Argument
p + geom_point(size = 3)
Die Punkte werden nun in verschiedenen Farben dargestellt, aber innerhalb eines Geschlechts werden Punkte eventuell übereinander geplottet, wenn sie denselben Wert haben (overplotting). Für diesen Fall gibt es die Funktion geom_jitter(), welche Punkte mit einem jittering nebeneinander zeichnet:
p + geom_jitter()
geom_jitter() hat ein Argument width, mit dem wir bestimmen können, wie breit die Streuung der Punkte ist.
p + geom_jitter(width = 0.2)
geom_jitter() hat weitere Argumente: size bestimmt den Durchmesser der Punkte, und alpha bestimmt die Transparenz.
p + geom_jitter(width = 0.2, size = 4, alpha = 0.6)
Eine weitere Möglichkeit wäre, die zentrale Tendenz und Streuung der Daten mit einem Boxplot- oder Violin-Diagramm darzustellen.
p + geom_boxplot()
In einem Boxplot wird der Median dargestellt, das Rechteck repräsentiert die mittleren 50%, und die “whiskers” zeigen 1.5 den Interquartilsbereich. Ausreisser werden mit Punkten dargestellt. Um den Median zu sehen, ist es besser, wenn wir das fill Attribut weglassen:
p <- stress |>
ggplot(mapping = aes(
x = geschlecht,
y = stress_psychisch,
color = geschlecht
))
p + geom_boxplot()
Ein Violin-Plot ist ähnlich wie ein Boxplot, zeigt aber nicht die Quantile, sondern ein kernel density estimate. Ein Violin-Plot sieht am besten aus, wenn wir das fill Attribut verwenden.
p <- stress |>
ggplot(mapping = aes(
x = geschlecht,
y = stress_psychisch,
fill = geschlecht
))
p + geom_violin()
Wenn wir feststellen, dass ein Mapping nicht für alle “Layers” gelten soll, dann können wir es für jede Layer individuell definieren, anstatt in der ggplot() Funktion:
p <- stress |>
ggplot(mapping = aes(
x = geschlecht,
y = stress_psychisch
))
p + geom_boxplot(mapping = aes(color = geschlecht))
# oder einfach
# p + geom_boxplot(aes(color = geschlecht))
Wir können auch mehrere Layers verwenden. Wir müssen lediglich mehrere geom_ Funktionen mit einem + zusammenfügen:
p +
geom_violin(aes(fill = geschlecht)) +
geom_jitter(width = 0.2, alpha = 0.6)
In den bisherigen Beispielen haben wir kein Plot-Objekt erstellt, sondern den Datensatz mit dem pipe Operator an die ggplot() Funktion geschickt, und dann mit + direkt die geoms hinzugefügt. Die Erstellung eines Plot-Objekts p ist also nicht zwingend notwendig, vereinfacht aber die Arbeit mit ggplot2 besonders am Anfang. Ausserdem haben wir weitere Funktionen verwendet, wie z.B. theme_classic(), um den Hintergrund weiss darzustellen. Auf diese zusätzlichen Funktionen kommen wir weiter unten zurück.
stress |>
ggplot(mapping = aes(
x = geschlecht,
y = stress_psychisch,
fill = geschlecht
)) +
geom_violin() +
geom_jitter(width = 0.2, alpha = 0.6) +
theme_classic()
Hinweis:
Wir werden hier nur eine kleine Auswahl der möglichen ggplot2 Funktionen betrachten. Das Package ist sehr umfangreich und hat eine sehr übersichtliche Website, auf der alles dokumentiert ist: ggplot2 Dokumentation
Für die folgenden Beispiele verwenden wir die Datensätze beispieldaten und kinderwunsch. Während wir beispieldaten schon weiter oben eingelesen haben, müssen wir den Datensatz kinderwunsch.sav noch herunterladen, in unserem data-Ordner abspeichern (kinderwunsch.sav) und anschliessend einlesen:
kinderwunsch <- read_sav(“data/kinderwunsch.sav”) |> mutate(geschlecht = haven::as_factor(geschlecht))
Wenn wir nur eine Variable auf der X-Achse grafisch darstellen möchten, müssen wir aber dennoch Werte auf der Y-Achse darstellen. Dies wird oft eine deskriptive Zusammenfassung wie z.B. Häufigkeiten sein.
Wenn wir eine kategoriale Variable grafisch darstellen, verwenden wir oft einen bar chart or bar graph. Dieser stellt z.B. Häufigkeiten der verschiedenen Kategorien anhand eines Rechtecks (rectangular bar) dar. Die Funktion, welche dafür verwendet wird, heisst geom_bar().
Als Beispiel wollen wir die Häufigkeiten der vier Bildungsstufen des Vaters plotten.
Hinweis Wenn wir fill = “lightblue”, color = “black” nicht innerhalb der aes() Funktion verwenden, dann werden diese Argumente nicht als Gruppierungsanweisung aufgefasst. Wir können z.B. mit fill = “lightblue” einfach alle Elemente hellblau einfärben.
p <- beispieldaten |>
select(bildung_vater) |>
drop_na() |>
ggplot(aes(x = bildung_vater))
p + geom_bar(fill = "lightblue", color = "black")
Auch hier können wir zusätzlich eine Gruppierungsvariable angeben, anhand derer wir die Rechtecke farblich kodieren.
p <- beispieldaten |>
select(bildung_vater, westost) |>
drop_na() |>
ggplot(aes(x = bildung_vater, fill = westost))
p + geom_bar()
Standardmässig kreiert ggplot2 einen stacked Bar Chart, d.h. die Rechtecke werden aufeinander gestapelt. Wenn dies nicht erwünscht ist, können wir das Argument position = “dodge” der Funktion geom_bar() verwenden. Damit teilen wir mit, dass die Bars nebeneinander gezeichnet werden sollen.
p + geom_bar(position = "dodge")
Falls die Variable, welche wir grafisch darstellen wollen, nicht kategorial, sondern kontinuierlich ist, bietet sich ein Histogramm an; dies erzeugen wir mit der Funktion geom_histogram(). Als Beispiel betrachten wir den psychischen Stress.
Wir verwenden wieder den bereits oben gebildeten Datensatz stress, der nur die Variablen ID, stress_psychisch und geschlecht beinhaltet:
p <- stress |>
ggplot(mapping = aes(x = stress_psychisch))
p + geom_histogram(binwidth = 0.5)
Statt der binwidth kann mit bins auch die Anzahl der insgesamt zu bildenden Bins angegeben werden:
p + geom_histogram(bins = 20)
Selbsverständlich gibt es auch für Histogramme die Möglichkeit, einen Faktor als Gruppierungsvariable zu verwenden.
p <- stress |>
ggplot(mapping = aes(x = stress_psychisch, fill = geschlecht))
p + geom_histogram(binwidth = 0.5)
Nun stellen wir zwei Variablen eines Datensatzes gemeinsam dar. Auch hier hängen die möglichen geoms vom Datentyp der Variablen ab.
Wenn beide Variablen kontinuierlich sind, können wir deren Zusammenhang anhand eines Scatterplots oder eines Liniendiagrams darstellen. Wir verwenden die Funktionen geom_point(), bzw. geom_line().
Als Beispiel wollen wir den Zusammenhang zwischen psychischem Stress und Lebenszufriedenheit visualisieren.
p <- beispieldaten |>
select(stress_psychisch, leben_gesamt) |>
drop_na() |>
ggplot(mapping = aes(x = stress_psychisch, y = leben_gesamt))
p + geom_point(size = 2, alpha = 0.6)
Die size und alpha Argumente haben wir weiter oben bereits kennengelernt, sowie die Möglichkeit, overplotting mit der Funktion geom_jitter() zu vermeiden. Sowohl geom_jitter() als auch geom_point() haben auch eine colour oder ein color Argument.
p + geom_jitter(colour = "purple")
Die Gruppierung anhand einer kategorialen Variablen funktioniert auch hier. Wir verwenden sowohl die Farbe als auch die Form der Punkte, um die Kategorien besser unterscheiden zu können.
p <- beispieldaten |>
select(stress_psychisch, leben_gesamt, geschlecht) |>
drop_na() |>
ggplot(mapping = aes(
x = stress_psychisch,
y = leben_gesamt,
color = geschlecht,
shape = geschlecht
))
p + geom_jitter(size = 3, alpha = 0.9)
Mit der Funktion geom_line() können wir Liniendiagramme erstellen. Als Beispiel wollen wir in einem neuen Dataframe die Mittelwerte der Gesamtnote der Jugendlichen für die verschiedenen Bildungsniveaus des Vaters berechnen, und dann grafisch darstellen. Bevor wir die Noten-Mittelwerte plotten, konvertieren wir den Faktor bildung_vater zu einer numerischen Variable.
Vertiefung:
Wir könnten bildung_vater auch als Faktor verwenden, müssten dann aber eine Gruppierungsvariable für geom_line() definieren. In diesem Fall würden wir group = 1 verwenden, da wir nur eine Gruppe haben: p + geom_line(group = 1)
bildung_vater <- beispieldaten |>
select(Gesamtnote, bildung_vater) |>
drop_na() |>
group_by(bildung_vater) |>
summarize(Gesamtnote = mean(Gesamtnote)) |>
mutate(bildung_vater_num = as.numeric(bildung_vater))
bildung_vater
p <- bildung_vater |>
ggplot(aes(
x = bildung_vater_num,
y = Gesamtnote
))
p + geom_line()
p + geom_line() +
geom_point(size = 4)
Als Beispiel wollen wir die gemeinsame Häufigkeitsverteilung der Bildung des Vaters und der Bildung der Mutter betrachten.
p <- beispieldaten |>
select(starts_with("bildung")) |>
drop_na() |>
ggplot(aes(
x = bildung_vater,
y = bildung_mutter
))
p + geom_count()
geom_count() zählt die gemeinsamen Häufigkeiten der
Kategorien der beiden Variablen und stellt diese als Durchmesser der
Punkte dar.