Vorlesung 2

Heute zuerst ohne KI
Lösen Sie die Aufgaben heute zunächst ohne KI. Für Daten, Pakete und Fehlermeldungen ist der eigene Diagnoseweg im Moment wichtiger.
| Zeit | Inhalt |
|---|---|
| 08:30 - 10:00 | Import und erste Einblicke: Textdateien lesen, RStudio-Import, str, head, summaryOrientierung, zwei Kurzübungen, Arbeitsphase mit CSV-Datei |
| 10:15 - 11:45 | Data Wrangling I: Tidy Data, filter, select, mutate, summarisegemeinsamer Einstieg, dann größere Datenaufgabe |
| 12:30 - 14:00 | Data Wrangling II, Joins und Datenbanken: Pipes, group_by, left_join, DBI, dbplyr, fifa23Join-Kurzübungen, dann Arbeitsphasen mit fifa23 und videogames |
| 14:15 - 15:45 | Visualisierung: Base R, ggplot2, passende Diagrammwahl, ExportOrientierung, zwei Kurzübungen, längere Arbeitsphase |
| 16:00 - 17:30 | Quarto und Transfer: Aufbau einer .qmd-Datei, Chunks, Optionen, Mini-Reportgemeinsamer Einstieg, Abschlussaufgabe, Besprechung |
Pausen und Besprechungen nutzen wir wieder, um offene Fragen sofort zu klären und den Schwierigkeitsgrad bei Bedarf anzupassen.
csv oder tsv.read.table(...) die allgemeine Importfunktion, read.csv(...) die einfache Variante für Standard-CSV.readLines(...) lässt sich vor dem Einlesen schnell prüfen, wie eine Datei aufgebaut ist.Achtung
Große Datensätze sollten Sie nie einfach komplett in die Konsole drucken. Für den ersten Überblick sind head(...), tail(...) und str(...) fast immer die bessere Wahl.
| Funktion | Wozu? | Typischer Einsatz |
|---|---|---|
str(df) |
Struktur, Typen und erste Werte | sofort nach dem Import |
names(df) |
Spaltennamen prüfen | nachsehen, wie Variablen heißen |
dim(df) |
Zeilen und Spalten gemeinsam prüfen | erster Größencheck |
nrow(df), ncol(df) |
Zeilen oder Spalten getrennt prüfen | schnelle Rückfrage |
head(df, n) |
erste Zeilen ansehen | Import plausibilisieren |
tail(df, n) |
letzte Zeilen ansehen | Randbereiche prüfen |
summary(df) |
Variablen zusammenfassen | auffällige Werte und NAs erkennen |
Tipp
Die sinnvolle Standardreihenfolge nach dem Import ist oft: str(...), dim(...), head(...), summary(...).
read.csv einlesenreadLines(file, n = 3), wie die Datei aufgebaut ist.read.csv(file) als Objekt rad ein.class(rad), in welcher Struktur der Datensatz vorliegt.head(rad, 2) die ersten zwei Zeilen aus.str, names und summarystr(rad), welche Variablen im Datensatz enthalten sind.names(rad) alle Spaltennamen ausgeben.dim(rad), nrow(rad) und ncol(rad) die Größe des Datensatzes.tail(rad, 3) aus.summary(rad), welche Variablen numerisch und welche kategorial wirken.summary(...) interpretierendata/zaehlstelle_neutor_2017.csv als Objekt rad ein.str(rad) und die Größe mit dim(rad).kalte_stunden mit allen Zeilen, für die Temperatur <= 0 gilt.kalte_stunden nur die Spalten Datum, Anzahl, Temperatur und Wetter.kalte_stunden als Datei kalte_stunden.csv ohne zusätzliche Zeilennummern.names(...) und dim(...).NA erkannt.Merksatz
Import ist noch nicht Analyse. Erst wenn Struktur, Namen und Größenordnung plausibel sind, lohnt sich die eigentliche Datenarbeit.

Merksatz
Base-R-Äquivalente kennen Sie aus den Grundlagen. In diesem Block arbeiten wir bewusst mit dplyr, damit die Datenlogik und nicht der Syntaxvergleich im Vordergrund steht.
filter(...)filter(...) behält genau die Zeilen, für die alle Bedingungen TRUE ergeben.!is.na(...), um fehlende Werte bewusst auszuschließen.Achtung
filter(...) verändert nur Zeilen. Wenn sich plötzlich Spalten ändern, wurde meist die falsche Funktion gewählt.
select(...)select(...) reduziert oder ordnet Spalten um.starts_with(...) oder contains(...).Tipp
Lesen Sie select(...) immer als Spaltenentscheidung: Was soll im Datensatz sichtbar bleiben?
mutate(...)mutate(...) ergänzt neue Variablen oder überschreibt bestehende.Merksatz
mutate(...) liefert wieder einen Datensatz gleicher Länge. Es wird ergänzt, nicht verdichtet.
mutate(...)dense_rank(...), lag(...) oder kumulative Summen.group_by(...).Hinweis
Window-Funktionen beantworten nicht die Frage „Wie viele?“ oder „Wie groß im Mittel?“, sondern erzeugen neue Werte pro Beobachtung.
summarise(...)summarise(...) fasst viele Zeilen zu Kennzahlen zusammen.group_by(...) entsteht meist eine Zeile für den gesamten Datensatz.group_by(...) entsteht eine Zeile pro Gruppe.Merksatz
summarise(...) verändert die Bedeutung der Zeilen. Nach einer Verdichtung steht nicht mehr jede Zeile für eine einzelne Beobachtung.
nycflights13 und dplyr.df_2hdelay mit allen Flügen, für die arr_delay > 120 gilt.year, month, day, origin, dest und arr_delay.head(...), ob die Struktur plausibel ist.nrow(...) aus, wie viele Flüge im Ergebnis enthalten sind.summarise verdichtenflights ein Objekt mit den Spalten origin, dest, dep_delay und arr_delay.mutate(...) eine neue Variable delay_total = dep_delay + arr_delay.summarise(...) den größten und den durchschnittlichen Wert von arr_delay.arr_delay enthalten sind.Fragestellung: Welche Ziele sind im Januar von Newark (EWR) aus besonders verspätungsanfällig?
flights mit month == 1, origin == "EWR" und nicht fehlender arr_delay.dest, dep_delay und arr_delay.delay_total = dep_delay + arr_delay.dest) zusammen:
filter, select, mutate, summarise sauber trennenfilter(...) verändert Zeilen.select(...) verändert Spalten.mutate(...) ergänzt oder verändert Variablen.summarise(...) verdichtet einen Datensatz zu Kennzahlen.Merksatz
Fragen Sie bei jedem Schritt zuerst: Verändere ich Beobachtungen, Variablen oder verdichte ich den Datensatz?
%>% übergibt das linke Ergebnis als erstes Argument an die nächste Funktion.Tipp
Lesen Sie Pipe-Code zunächst von oben nach unten. Fragen Sie sich bei jeder Zeile: Was ist jetzt das aktuelle Objekt?
group_by(...) markiert, für welche Gruppen nachfolgende Funktionen rechnen sollen.summarise(...) oder mutate(...) nutzt diese Gruppierung.summarise(...) entsteht meist eine Zeile pro Gruppe.Merksatz
group_by(...) rechnet noch nichts aus. Die Wirkung sieht man erst im nächsten Schritt.
mutate(...)mutate(...) kann gruppiert arbeiten.Hinweis
Die Kombination group_by(...) plus mutate(...) ist didaktisch wichtig, weil hier oft unbemerkt gruppenspezifische Ergebnisse entstehen.
nycflights13 ist carrier ein typischer Schlüssel zwischen flights und airlines.left_join(...) behält alle Zeilen der linken Tabelle.inner_join(...) behält nur Zeilen mit Treffern auf beiden Seiten.
Achtung
Ein Join ist nicht nur „Spalten anhängen“. Entscheidend ist, ob die Schlüsselvariablen wirklich eindeutig und fachlich passend sind.
nycflights13flights ist die zentrale Faktentabelle.airlines ergänzt Namen zu carrier.airports ergänzt Informationen zu Start- und Ziel-Flughäfen.weather liefert stundenweise Kontextdaten.
Tipp
Prüfen Sie vor jedem Join erst das Datenmodell: Schlüssel, Granularität und erwartete Zeilenzahl des Ergebnisses.
fifa23 als erste dbplyr-Datenbankfifa23 eignet sich gut für den Einstieg, weil Spieler, Vereine und Ligen fachlich leicht verständlich sind.players (18.533 Zeilen), clubs (667) und optional leagues (52).players$club_team_id -> clubs$club_id, players$league_id -> leagues$league_id.Merksatz
Ein Datenbankschema ist kein Beiwerk. Es zeigt Ihnen, welche Tabellen zusammenpassen und welche Join-Schlüssel fachlich sinnvoll sind.
videogames als zweite Übungsdatenbankvideogames ist kleiner und analytischer: Spiele, Publisher, Plattformen und Verkäufe sind sauber getrennt.sales (65.296 Zeilen), game (11.360), publisher (577).sales$game_id -> game$id, sales$publisher_id -> publisher$id.Tipp
Bearbeiten Sie zuerst die fifa23-Aufgabe. Wenn Verbindung, tbl(...), Join und collect() sicher laufen, wechseln Sie zur zweiten Datenbank.
DBI, Backends und dbplyrDBI stellt die Verbindung zur Datenbank her.RPostgres ist hier der passende Treiber für PostgreSQL.dbplyr übersetzt dplyr-Code in SQL.collect() bleiben Tabellen lazy in der Datenbank.show_query(...) prüfen Sie, welchen SQL-Code dbplyr erzeugt.Hinweis
Vor collect() arbeitet dbplyr noch nicht mit einem Data Frame in R, sondern schiebt die Operation möglichst lange in PostgreSQL.
flights eine Pipeline, die
arr_delay >= 0 behält,origin gruppiert,airlines aus dem Paket nycflights13.flights_airlines, das flights und airlines über carrier mit left_join(...) verbindet.carrier, name, origin und arr_delay.head(...), ob Airline-Namen nun sichtbar sind.nrow(...), ob sich die Zahl der Zeilen durch den Join verändert hat.carrierleft_join(...) lesen und anwendenfifa23fifa23 her.dbListTables(con), ob players, clubs und leagues vorhanden sind.players <- tbl(con, "players").short_name, overall, age und nationality.overall >= 90, sortieren Sie absteigend und zeigen Sie den SQL-Code.collect() nach R.fifa23-Clubs mit starken Kadern identifizierenfifa23 her.players <- tbl(con, "players") und clubs <- tbl(con, "clubs").players auf overall >= 80 und entfernen Sie fehlende club_team_id.players und clubs über club_team_id = club_id.team_name die Anzahl dieser Spieler und den mittleren overall.mean_overall, zeigen Sie den SQL-Code und laden Sie das Ergebnis nach R.videogames-Verkäufe nach Publishern analysierenvideogames her.sales <- tbl(con, "sales"), game <- tbl(con, "game") und publisher <- tbl(con, "publisher").region_name == "Europe".sales mit game und publisher.Sports und berechnen Sie je publisher_name die gesamte num_sales.collect() nach R.collect() bewusst einsetzenleft_join(...) ist oft der sichere Standard, wenn alle Zeilen der linken Tabelle erhalten bleiben sollen.show_query(...) hilft, die Wirkung von dbplyr transparent zu machen.collect() sollte bewusst spät kommen, damit große Datenmengen nicht zu früh nach R geladen werden.Merksatz
Fragen Sie bei dbplyr immer doppelt: Arbeite ich noch lazy in PostgreSQL oder schon mit einem Data Frame in R, und welche Tabelle ergänzt meine aktuelle Beobachtungseinheit?
| Fragestellung | Base-R-Funktion | Typischer Input | Geeignet für |
|---|---|---|---|
| Zusammenhang zweier numerischer Variablen | plot(...) |
x, y |
Streudiagramme |
| Verteilung einer numerischen Variablen | hist(...) |
ein numerischer Vektor | Histogramme |
| Gruppen vergleichen | boxplot(...) |
Vektor oder Formel y ~ gruppe |
Boxplots |
| Kategorien zählen oder Werte je Kategorie zeigen | barplot(...) |
Vektor oder Tabelle | Balkendiagramme |
Hinweis
Base R ist besonders stark, wenn Sie schnell eine erste, robuste Grafik brauchen. Für systematischen Aufbau und konsistente Erweiterung ist ggplot2 meist angenehmer.
ggplot2 als Systemggplot2 trennt klar zwischen Daten, Mapping und Geometrie.ggplot(data, aes(...)) + geom_*()labs(...), scale_*(), theme(...) oder facet_*() verfeinern den Plot.aes(...) und festen Stilwerten außerhalb von aes(...).Achtung
aes(color = factor(cyl)) mappt Farbe auf Daten. geom_point(color = "steelblue") setzt nur einen festen Stil. Genau diese Unterscheidung ist eine der häufigsten Fehlerquellen.
plot(...) ein Streudiagramm für wt gegen mpg aus mtcars.abline(...) zusätzlich die lineare Regressionsgerade ein.ggplot aufbauenggplot2.wt gegen mpg aus mtcars.factor(cyl).labs(...).theme_minimal().data, aes, geom_pointBearbeiten Sie eine der folgenden Fragen mit einer passenden Grafik in Base R oder ggplot2.
arr_delay in flights Vorschlag: Histogramm ohne fehlende Wertearr_delay zwischen JFK, LGA und EWR Vorschlag: Boxplotdep_delay und arr_delay Vorschlag: Scatterplot auf einer Stichprobe von 2000 Flügenflights_sample <- flights %>%
filter(!is.na(dep_delay), !is.na(arr_delay)) %>%
slice_sample(n = 2000)ggsave(...) oder über ein Base-R-Grafikgerätggplot2 gehört datenabhängige Darstellung in aes(...), feste Gestaltung außerhalb.ggplot2 ist ggsave(...) oft der bequemste Exportweg.dev.off().Merksatz
Eine gute Grafik beantwortet eine konkrete Frage. Erst danach kommen Farbe, Theme und Exportformat.
.qmd) verbindet YAML, Markdown und Code-Chunks.---
title: "Mini-Report"
author: "Max Mustermann"
format: html
---
## Einleitung
```{r}
summary(mtcars$mpg)
```
Tipp
Wenn Sie Quarto lernen, denken Sie nicht zuerst an perfekte Berichte, sondern an einen sauberen Workflow aus Text, Code und Ergebnis an einem Ort.
| Option | Wirkung | Typischer Einsatz |
|---|---|---|
eval |
Code ausführen oder nicht | Beispiele zeigen, aber nicht rechnen |
echo |
Quellcode im Ergebnis zeigen oder verbergen | Arbeitsblatt vs. Bericht |
warning |
Warnungen anzeigen oder unterdrücken | sauberere Ausgabe |
message |
Paketmeldungen anzeigen oder unterdrücken | weniger Rauschen |
fig-cap |
Bildunterschrift setzen | Abbildungen dokumentieren |
Hinweis
Chunk-Optionen lösen kein inhaltliches Problem. Sie steuern nur, wie der vorhandene Code im Dokument erscheint.
Schauen Sie sich das folgende Grundgerüst an und bearbeiten Sie es direkt:
---
title: "Mini-Report"
format: html
---
## Datenüberblick
```{r}
head(mtcars)
```
author.## Datenüberblick einen kurzen erklärenden Satz ein.head(mtcars) durch summary(mtcars$mpg).fig-cap.echo und eval nicht dasselbe sind.echo vs. evalErstellen Sie eine Datei mini-report.qmd mit folgendem Mindestumfang:
title, author und format: html.Als Datenquelle können Sie z. B. mtcars, airquality oder den bereits importierten Datensatz rad verwenden.
---
title: "Mini-Report"
author: "..."
format: html
---
Merksatz
Quarto ist kein Extra neben der Analyse. Es ist die Form, in der Analyse, Code und Ergebnis sauber zusammengeführt werden.

Programmierung für Data Science – Vorlesung 2 – Prof. Dr. Michael Bücker