Data Science 1 - Programmieren & Visualisieren
Saskia Otto
Universität Hamburg, IMF
Wintersemester 2023/2024
Funktion | Beschreibung |
---|---|
plot() |
Generische Funktion mit vielen Methoden (kontextabhängig) |
barplot() |
Säulen- bzw. Balkendiagram |
boxplot() |
Boxplot |
contour() |
Plot mit Höhenlinien |
coplot() |
sog. ‘conditional plot’ |
curve() |
Kurven über einem Intervall für eine Funktion |
hist() |
Histogramm |
image() |
Erstellt kontextabhängige ‘Bildraster’ (auch in 3D) |
mosaicplot() |
Mosaikplot für kategorielle Daten |
pairs() |
Streudiagramm-Matrix für paarweise Gegenüberstellungen |
pie() |
Tortendiagramm |
qqplot() |
QQ-Plot |
?plot
und ?plot.default
werden viele Argumente von Grafikfunktionen genannt und erklärt.par()
.?par
listet wesentlich mehr Argumente, die auch in den high-level Funktionen genutzt werden können.Argument | Beschreibung |
---|---|
adj | Ausrichtung von Text (zentriert,…) |
axes | Achsen sollen (nicht) eingezeichnet werden |
bg | Hintergrundfarbe der Grafik |
bty | Art der Box um die gezeichnete Grafik |
cex | Größe der Schriftzeichen in der Grafik |
col | Farben (der Linien, der Punkte, etc.) |
las | Ausrichtung der Achsenbeschriftung |
lty,lwd | Linientyp (gestrichelt,…) und Linienbreite |
main,sub | Überschrift und Unterschrift |
mfrow | mehrere Grafiken in einem Bild |
pch | Darstellung eines Punktes |
type | Typ der Darstellung (Linien, Punkte, Nichts) |
xlab,ylab | x-/y-Achsenbeschriftung |
xlim,ylim | Größe der Grafik in x-/y-Richtung |
Funktion | Beschreibung |
---|---|
abline() |
Zeichnet eine kontextabhängige Linie |
arrows() |
Zeichnet Pfeile |
axis() |
Zeichnet Achsen (jede Achse einzeln!) |
grid() |
Zeichnet ein Gitternetz |
legend() |
Erstellt eine Legende im Plot |
lines() |
Zeichnet schrittweise Linien |
mtext() |
Schreibt Text in den Rand (s.unten) |
points() |
Zeichnet Punkte |
polygon() |
Zeichnet ausgefüllte Polygone |
rect() |
Zeichnet (vektorwertig) ein Rechteck |
segments() |
Zeichnet (vektorwertig) Linien |
text() |
Schreibt Text in den Plot |
title() |
Beschriftet den Plot |
Screen device (default) - Fenster im Programm
File device - Ausgabeformat als Rasterdatei (JPEG, PNG, TIFF,..) oder Vektordatei (PDF, EPS)
Important
Das Schließen mit dev.off()
ist besonders wichtig, sonst werden alle folgenden Grafiken mit in dem PDF gespeichert und nicht in der Konsole angezeigt!
Weblink: https://exts.ggplot2.tidyverse.org
Fotos von Radomil Binek, Danielle Langlois, und Frank Mayfield (von links nach rechts); Zugriff über Wikipedia(unter CC-BY-SA 3.0 Lizenz).
ggplot()
ggplot(
data = iris,
mapping = aes(
x = Sepal.Length,
y = Petal.Length,
colour = Species)
) +
geom_point() +
geom_smooth(method = "lm") +
scale_colour_manual(values =
c("orange","cyan3", "#68228B")) +
facet_wrap(~Species, nrow = 2) +
coord_flip() +
guides(colour = guide_none()) +
labs(x = "Länge Kelchblatt (cm)",
y = "Länge Kronblatt (cm)")
ggplot(
data = iris,
mapping = aes(
x = Sepal.Length,
y = Petal.Length,
colour = Species)
) +
geom_point() +
geom_smooth(method = "lm") +
scale_colour_manual(values =
c("orange","cyan3", "#68228B")) +
facet_wrap(~Species, nrow = 2) +
coord_flip() +
guides(colour = guide_none()) +
labs(x = "Länge Kelchblatt (cm)",
y = "Länge Kronblatt (cm)") +
theme_dark()
ggsave()
Das letzte angezeigte Diagramm (im ‘screen device’) wird als PDF in 4x4 inch gespeichert (auch Standardeinstellung).
Starte mit dieser Funktion und übergebe einen Datensatz an die Funktion: ggplot(data)
Als nächstes müssen die Datenvariablen den Koordinaten zugeordnet werden damit ein leeres Koordinatensystem dargestellt wird. Dies geschieht in der aes()
Funktion. Weitere visuelle Eigenschaften (sog. aesthetics) sind z.B. Größe, Farbe, Form, etc.
ggplot()
gilt für alle Ebenen.geom_XXX()
Funktion gilt nur für diese Ebene.
geom_XXX()
: Kombiniere ein geometrisches Objekt/Grundelement, welches die Daten repräsentiert, mit den Abbildungseigenschaften, einer Statistik und einer Positionsanpassung, z.B. geom_point()
oder geom_col()
.
Sog. ‘scale’ Funktionen bestimmen wie Datenwerte in visuelle Eigenschaften übersetzt werden (überschreiben die Standardeinstellungen), wie z.B.
scale_fill_manual()
.
facet_XXX()
Funktionen erstellen kleinere Diagramme, die verschiedene Teilmengen der Daten anzeigen; nützlich zur Untersuchung von Interaktionen mit kategorialen Variablen.
Funktionen wie
coord_flip()
bestimmen die Darstellung des XY-Koordinatensystems und somit die Positionierung der Daten.
Mit der guides()
Funktion und weiteren guide_XXX()
Helferfunktionen kann die Anzeige der Achsen und Legende bestimmt werden.
Sog. ‘theme’ Funktionen bestimmen die Anzeige aller Nicht-Datenelemente des Plots. Es können alle Einstellungen mit einem kompletten Thema wie
theme_classic()
überschrieben oder einzelne Einstellungen mit theme()
verändert werden.
Das aktuell angezeigte ggplot Diagramm lässt sich mit ggsave()
speichern: ggsave("plot.png", width = 5, height = 5)
→ speichert den Plot als PDF in 5x5 inch ab.
# ------------------------------ Vorbereitung ----------------------------------
#### Laden von Paketen
library(tidyverse) # laedt 9 Pakete
#### Eigene Funktionen
# Variantionskoeffizient
cv <- function(x) {
sd(x)/mean(x)
}
# -------------------- Import und Datenaufbereitung ----------------------------
#### Import von CSV-Dateien
# Import des weiten (falsch strukturierten) Datensatzes --> KLAPPT NICHT
iris <- read.csv("iris.csv", sep = ";")
iris <- read.delim("iris.csv", sep = ";", header = FALSE)
# Import des in Calc transponierten (und dann als CSV-Datei gespeicherten)
# Datensatzes --> KLAPPT
iris <- read.csv("iris_transponiert.csv")
#### Datensichtung
iris
# View(iris)
head(iris)
tail(iris)
class(iris)
nrow(iris)
ncol(iris)
dim(iris)
names(iris)
typeof(iris$Sepal.Length)
typeof(iris$Species)
# Diese Funktion fasst die obigen zusammen --> IMMER VERWENDEN!
str(iris)
#### Aufgabe aus Uebungswoche 1: Daten zuerst nach Artnamen alphabetisch
# sortieren und dann innerhalb der Arten nach Kelchblattlaenge absteigend
arrange(iris, Species, desc(Sepal.Length))
# ------------ Alternative Variante (ohne Vorbehandlung in Calc) ---------------
# --> weiten Datensatz mit Funktion aus 'readr' Paket einlesen und anpassen
#### Import
iris2 <- read_delim("iris.csv", delim = ";", col_names = FALSE)
iris2
class(iris2) # ein tibble
#### Datenaufbereitung
iris2 <- t(iris2)
class(iris2)
iris2_names <- iris2[1, ]
iris2 <- iris2[-1, ]
iris2
colnames(iris2) <- iris2_names
rownames(iris2) <- NULL
iris2 <- iris2 |>
as.data.frame() |>
mutate(across(Sepal.Length:Petal.Width, as.double))
# Pruefen ob die Umwandlung richtig ist
head(iris2)
str(iris2)
# ------------------- Numerische deskriptive Statistik -------------------------
#### Berechnung verschiedener Statistiken pro Variable (hier Kronblattlaenge)
# Lageparameter
mean(iris$Petal.Length)
median(iris$Petal.Length)
# Streuungsparameter
min(iris$Petal.Length)
max(iris$Petal.Length)
range(iris$Petal.Length)
var(iris$Petal.Length)
sd(iris$Petal.Length)
sd(iris$Petal.Length)/sqrt(length(iris$Petal.Length))
cv(iris$Petal.Length) # mit eigener Funktion (siehe oben)
quantile(iris$Petal.Length, probs = c(0.25, 0.5, 0.75))
#### Berechnung der Statistiken fuer mehrere Spalten -> hier in einer Schleife
# Leere Liste erstellen
meine_statistiken <- vector("list", length = 4)
names(meine_statistiken) <- names(iris)[1:4]
# for-Schleife mit 4 Iterationen (fuer Spalte 1-4 in iris)
for (i in 1:4) {
meine_statistiken[[i]] <- c(
Min = min(iris[[i]]),
unteres_Quartil = quantile(iris[[i]], probs = 0.25),
Median = median(iris[[i]]),
Mittelwert = mean(iris[[i]]),
oberes_Quartil = quantile(iris[[i]], probs = 0.75),
Max = max(iris[[i]]),
Varianz = var(iris[[i]]),
Standardabweichung = sd(iris[[i]]),
Standardfehler = sd(iris[[i]])/sqrt(length(iris[[i]])),
Variationskoeffizient = cv(iris[[i]])
)
}
meine_statistiken
#### Shortcut-Funktion: summary()
summary(iris)
# Bei Faktoren ist die summary Anzeige anders als beim Typ 'character'
iris |>
mutate(Species = as.factor(Species)) |>
summary()
#### Eigene (gruppierte) Statistiken fuer verschiedene Spalten mit 'tidyverse'
iris |>
summarise(mean_sl = mean(Sepal.Length))
iris |>
summarise(across(Sepal.Length:Petal.Width, .fns = list(mean = mean, sd = sd)))
# Statistiken gruppiert nach Species berechnen geht fast genauso
iris |>
group_by(Species) |>
summarise(mean_sl = mean(Sepal.Length))
iris |>
group_by(Species) |>
summarise(across(Sepal.Length:Petal.Width, .fns = list(mean = mean, sd = sd)))
# ------------------- Grafische deskriptive Statistik --------------------------
#### Berechnung von Mittelwert und Standardabweichung
iris_summary <- iris |>
group_by(Species) |>
summarise(
PL_mean = mean(Petal.Length),
PL_sd = sd(Petal.Length)
) |>
# die Artnamen anpassen (hier Gattungsnamen anfuegen) und als Faktor speichern
mutate(Species = factor(paste0("Iris ", Species))) |>
# nun die Reihenfolge der Faktorstufen nach PL_mean sortieren
mutate(Species = fct_reorder(.f = Species, .x = PL_mean, .desc = TRUE))
# Datensatz pruefen
iris_summary
# Grafik erstellen mit dem 'ggplot2' Paket (in 'tidyverse enthalten')
iris_summary |>
ggplot(aes(x = Species, y = PL_mean)) +
geom_col(fill = "#004586") +
geom_errorbar((aes(ymin = PL_mean - PL_sd, ymax = PL_mean + PL_sd)),
width = 0.2) +
ylab("Blütenblattlänge (in cm)") +
xlab("Schwertlilienart (Gattung Iris)") +
theme_bw()
# ------------------------------ Vorbereitung ----------------------------------
#### Laden von Paketen
library(tidyverse)
# library(readODS)
# library(readxl)
#### Eigene Funktionen
# -------------------- Import und Datenaufbereitung ----------------------------
#### Import von Calc- und Excel-Dateien (ODS- und XLSX-Format)
# Import einer ODS-Datei mit dem 'readODS' Paket
kabeljau <- readODS::read_ods("DS1_W03_Streudiagramm_Kabeljau.ods",
sheet = "Daten_Visualisierung")
str(kabeljau)
# Import einer XLSX-Datei mit z.B. dem 'readxl' Paket
kabeljau2 <- readxl::read_excel("DS1_W03_Streudiagramm_Kabeljau.xlsx",
sheet = "Daten_Visualisierung")
str(kabeljau2)
#### Datensichtung und -transformation
# Anpassen der Spaltennamen
names(kabeljau) <- c("verzehr", "wachstum")
str(kabeljau)
# Wertebereich pruefen
summary(kabeljau)
# ---------------------- Lineare Regression: Berechnung ------------------------
# (-> Lektion L03 in DSB-02-Datenexploration mit R)
#### Manuelle Berechnung
# Um Tipparbeit zu sparen, speichern wir die Spalten als einzelne Vektoren
x <- kabeljau$verzehr
y <- kabeljau$wachstum
# Steigungsparameter b berechnen
b <- cov(x = x, y = y)/ var(x) # der shortcut mit der Kovarianz und Varianz
b
# Achsenabschnitt a berechnen
a <- mean(y) - b*mean(x)
a
# Das Bestimmtheitsmass R^2 berechnen
y_obs <- a + b*x # die vorhergesagten Werte
ss_gesamt <- sum( (y - mean(y))^2 ) # Summenquadrate Gesamt
ss_regression <- sum( (y_obs - mean(y))^2 ) # Summenquadrate der Regression
R2 <- round(ss_regression/ss_gesamt, 4)
R2
##### Zum Vergleich die Regression automatisch berechnen mit lm()
# Erstellung des Modells
mod <- lm(formula = wachstum ~ verzehr, data = kabeljau)
mod
# Ausgabe nur der beiden Koeffizienten
coef(mod)
# Ausgabe aller wichtigen Statistiken des Modells, inklusive von R^2
# (mehr dazu in Data Science 2)
summary(mod)
# ------------------- Lineare Regression: Visualisierung ----------------------
#### Visualisierung mit den Basisfunktionen (-> Lektion L02 und L03 in DSB-02)
# Sog. high-level Funktion plot()
plot(x = kabeljau$verzehr, y = kabeljau$wachstum,
pch = 15, cex = 1.2, col = "#004586",
xlab = "Verzehr/Konsum (J/g/Tag", ylab = "Wachstum (J/g/Tag")
# Sog. low-level Funktionen, die Elemente in den angezeigten Plot einfuegen
abline(a = a, b = b)
title(
main = paste0("wachstum = ", round(a, 3), " + ", round(b, 3), "*verzehr"),
sub = paste0("Bestimmtheitsmaß R^2 = ", R2)
) # (paste0() verkettet Zeichen miteinander)
#### Visualisierung mit ggplot2 (-> siehe swirl-Kurs DSB-04)
kabeljau |>
ggplot(aes(x = verzehr, y = wachstum)) + # initiert Plot
geom_point(colour = "#004586", shape = 15, size = 3) +
# Punktelemente hinzufuegen
geom_abline(slope = b, intercept = a) +
# Achsenbeschriftung anpassen und Titel hinzufuegen
labs(x = "Verzehr/Konsum (J/g/Tag", y = "Wachstum (J/g/Tag",
title = str_c("wachstum = ", round(a, 3), " + ", round(b, 3), "*verzehr"),
subtitle = str_c("Bestimmtheitsmaß R^2 = ", R2)) +
# das Layout anpassen
theme_classic()
bshydro15 |>
mutate(
fquarter = factor(lubridate::quarter(date_time)),
fwday = factor(lubridate::wday(date_time))
) |>
ggplot(aes(x=fquarter, y=fwday)) +
geom_count() +
scale_size_area(max_size = 7) +
labs(title = "geom_count()",
subtitle = "sog. Count Plot",
x="Jahresquartal", y="Wochentag") +
theme(text = element_text(size = 13),
axis.text = element_text(size = 10))
bshydro15 |>
drop_na() |>
ggplot(aes(x=temp, y=psal)) +
geom_bin2d() +
labs(title = "geom_bin2d()",
subtitle = "sog. Heatmap - 2d bin counts",
x = "Temperatur", y = "Salinität") +
scale_fill_gradient2(
trans = "log",
breaks = c(1, 10, 50, 250),
guide = guide_legend(
title = "Häufigkeit (log)")
) +
theme(text = element_text(size = 13),
axis.text = element_text(size = 10))
iris |>
group_by(Species) |>
summarise(
Mean = mean(Sepal.Length),
SD = sd(Sepal.Length)
) |>
ggplot(aes(x = Species, y = Mean,
fill = Species)) +
geom_col() +
geom_errorbar(aes(ymin = Mean-SD,
ymax = Mean+SD), width = 0.2) +
labs(
title = "geom_col() und geom_errorbar()",
subtitle = "Säulendiagramm mit Fehlerbalken",
x = "Art", y = "mittlere Sepalblattlänge"
) +
guides(fill = "none") +
theme(text = element_text(size = 13),
axis.text = element_text(size = 10))
iris |>
group_by(Species) |>
summarise(
Mean = mean(Sepal.Length),
SD = sd(Sepal.Length)
) |>
ggplot(aes(x = Species, y = Mean)) +
geom_pointrange(aes(ymin = Mean-SD,
ymax = Mean+SD)) +
labs(
title = "geom_pointrange()",
subtitle = "sog. Point-Range-Plot",
x = "Art", y = "mittlere Sepalblattlänge"
) +
theme(text = element_text(size = 13),
axis.text = element_text(size = 10))
CO2 |>
group_by(Type, Treatment) |>
summarise(
Mean = mean(uptake),
SD = sd(uptake)
) |>
ggplot(aes(x = Type, y = Mean,
fill = Treatment)) +
geom_col(position = "dodge") +
geom_errorbar(aes(ymin = Mean-SD,
ymax = Mean+SD), width = 0.2,
position = position_dodge(.9)) +
labs(
title = "geom_col(position='dodge') und \ngeom_errorbar(position = position_dodge())",
subtitle = "Gruppiertes Säulendiagramm mit Fehlerbalken",
x = "Typ", y = "mittlere CO2-Aufnahme",
fill = "Behandlung"
) +
theme(text = element_text(size = 13),
axis.text = element_text(size = 10),
plot.title = element_text(size = 12),
plot.subtitle = element_text(size = 11)
)
data(penguins, package = "palmerpenguins")
# Version 1: den Anteil selbst berechnen
# und dann geom_col() verwenden:
# penguins |>
# group_by(species, island) |>
# summarise(counts = n()) |>
# ggplot(aes(x = factor(1), y = counts,
# fill = species)) +
# geom_col(position = "fill", width = 1) +
# coord_polar(theta = "y") +
# labs(
# title = "geom_col() und coord_polar()",
# subtitle = "Tortendiagramm (pie chart)",
# fill = "Pinguinart"
# ) +
# theme_void()
# Version 2: mit geom_bar()
penguins |>
ggplot(aes(x = factor(1), fill = species)) +
geom_bar(width = 1) +
scale_fill_manual(values = c("#a16a7f", "#9ba16a", "#6a7fa1")) +
coord_polar(theta = "y") +
labs(
title = "geom_bar() und coord_polar()",
subtitle = "Tortendiagramm (pie chart)",
fill = "Pinguinart"
) +
theme_void() +
theme(axis.text = element_blank(),
text = element_text(size = 13))
penguins |>
group_by(species, island) |>
summarise(counts = n()) |>
ggplot(aes(x = island, y = counts,
fill = species)) +
geom_col(position = "fill") +
scale_fill_manual(values =
c("#a16a7f", "#9ba16a", "#6a7fa1")) +
labs(
title = "geom_col(position = 'fill')",
subtitle = "Gestapeltes Säulendiagramm",
x = "Insel", y = "Anteil der Häufigkeit",
fill = "Pinguinart"
) +
theme(text = element_text(size = 13),
axis.text = element_text(size = 10))
huron <- data.frame(year = 1875:1972,
level = as.vector(LakeHuron))
ggplot(huron, aes(year)) +
geom_ribbon(aes(ymin = level - 1,
ymax = level + 1), fill = "grey70") +
geom_line(aes(y = level), colour = "grey65") +
labs(
title = "geom_ribbon()",
subtitle = "Banddiagramm (ribbon chart)",
x = "Jahre", y = "Huronsee \nPegelstand (in Fuß)"
) +
theme(text = element_text(size = 15),
axis.text = element_text(size = 10))
cod |>
ggplot(aes(x = year, y = ssb)) +
geom_area(aes(fill = area)) +
labs(
title = "geom_area()",
subtitle = "(Gestapeltes) Flächendiagramm",
x = "Jahr",
y = "Gesamtgröße Kabeljau-Bestand (in Tonnen)",
fill = "Gebiet"
) +
guides(fill = guide_legend(nrow = 3,
title.position = "bottom")) +
theme(text = element_text(size = 14),
axis.text = element_text(size = 10),
legend.position = "bottom",
legend.justification = "left",
legend.text = element_text(size = 9))
Versuchen Sie einen der beiden Plots mit dem iris
Datensatz in base R bzw. ‘ggplot2’ zu reproduzieren:
Versuchen Sie folgenden Plot mit dem iris
Datensatz in base R zu reproduzieren und diesen als PDF abzuspeichern:
Cheatsheet zum ggplot2 Paket frei verfügbar unter diesem Link.
Dann testen Sie doch Ihr Wissen in folgendem Abschlussquiz und probieren Sie diese Challenges..
Bei weiteren Fragen: saskia.otto(at)uni-hamburg.de
Diese Arbeit is lizenziert unter einer Creative Commons Attribution-ShareAlike 4.0 International License mit Ausnahme der entliehenen und mit Quellenangabe versehenen Abbildungen.
Kurswebseite: Data Science 1