Programmierung für
Data Science

Vorlesung 1

Prof. Dr. Michael Bücker

0.1 Heute arbeiten wir so

  • Die inhaltliche Grundlage sind die Kapitel Grundlagen und Programmierung im Skript.
  • Jeder Block folgt demselben Rhythmus:
    • kurze Orientierung
    • zwei gemeinsame Kurzübungen
    • eigenständige Arbeitsphase
    • kurze Besprechung
  • In den Kurzübungen klären wir Syntax, typische Fehler und erste Lösungswege gemeinsam.
  • In den Arbeitsphasen bearbeiten Sie größere Aufgaben allein oder in kleinen Teams.
  • Ziel für heute: sicher mit R, RStudio, Objekten, Datenstrukturen und ersten Kontrollstrukturen arbeiten.

Heute bewusst ohne KI

Für diese erste Vorlesung lösen wir die Aufgaben ohne KI-Unterstützung. Für die Grundlagen ist der eigene Denkweg wichtiger; später im Kurs schauen wir uns gezielt an, wie man KI sinnvoll und kritisch einsetzt.

0.2 Tagesstruktur

Zeit Inhalt
08:30 - 10:00 R und RStudio: Posit Workbench, Panes, Konsole, Editor, Tastenkürzel
Orientierung, zwei Kurzübungen, kurze Arbeitsphase
10:15 - 11:45 Hilfe und Pakete: Hilfeseiten lesen, Beispiele ausführen, Paket-Hilfe, erste Funktionen
Orientierung, zwei Kurzübungen, Arbeitsphase mit eigener Recherche
12:30 - 14:00 Objekte und Datenstrukturen: Zuweisungen, Environment, Vektoren, Matrizen, Listen, Data Frames, Faktoren
mehrere Kurzübungen, zwei Arbeitsphasen, gemeinsame Besprechung
14:15 - 15:45 Logische Operatoren und Kontrollstrukturen: any, all, which, if, if / else if / else, ifelse, for, while, FizzBuzz
mehrere Kurzübungen, zwei Arbeitsphasen, Transfer auf Daten
16:00 - 17:30 Eigene Funktionen und Kommentare: Funktionen definieren, Listen zurückgeben, Code strukturieren und dokumentieren
zwei Kurzübungen, Abschlussaufgabe, Besprechung

Pausen und Besprechungen nutzen wir, um offene Fragen direkt zu klären und den weiteren Ablauf bei Bedarf anzupassen.

1 R und RStudio

1.1 Orientierung: Posit Workbench, Panes und Ausführen

  • Für die Vorlesung arbeiten wir in der Posit Workbench mit RStudio Pro.
  • Editor (1): Skripte schreiben und speichern
  • Konsole (2): Befehle direkt ausführen
  • Environment/History (3): Objekte und Verlauf sehen
  • Files/Plots/Packages/Help (4): Dateien, Pakete und Hilfe
  • Ctrl/Cmd + Enter: aktuelle Zeile oder Auswahl ausführen
  • Ctrl/Cmd + 1 und Ctrl/Cmd + 2: zwischen Editor und Konsole springen
5 * (3 - 1)
log(7)
sqrt(16)

Tipp

Dauerhafter Code gehört in den Editor. Von dort aus schicken Sie einzelne Zeilen oder markierte Blöcke gezielt in die Konsole.

1.2 Kurzübung: In RStudio ankommen

  1. Melden Sie sich in der Posit Workbench an und öffnen Sie RStudio Pro.
  2. Benennen Sie die vier wichtigsten Bereiche der Oberfläche.
  3. Berechnen Sie in der Konsole log(7) und (15 + 3)^2.
  4. Öffnen Sie ein neues R-Skript und schreiben Sie:
sqrt(16)
round(pi, 3)
3^4
  1. Führen Sie die drei Zeilen nacheinander mit dem Tastenkürzel aus.
  2. Speichern Sie das Skript als vorlesung1_start.R.
  • Fokus:
  • Anmeldung und Sessionstart
  • Konsole und Editor unterscheiden
  • Skript unter eigenem Namen speichern

1.3 Kurzübung: Tastenkürzel und Code Completion

  1. Legen Sie im Skript zwei weitere Zeilen an:
21 + 14 / 2
abs(-9)
  1. Führen Sie nur die zweite Zeile aus.
  2. Tippen Sie im Editor me, drücken Sie Tab und schauen Sie sich die Vorschläge an.
  3. Unterbrechen Sie eine versehentliche Eingabe einmal mit Esc.
  4. Probieren Sie zusätzlich Ctrl/Cmd + 1, Ctrl/Cmd + 2 und Ctrl/Cmd + L aus.
  • Fokus:
  • einzelne Zeilen gezielt ausführen
  • Tab für Code Completion testen
  • Esc und Ctrl/Cmd + L bewusst ausprobieren

1.4 Arbeitsphase: Ein erstes Skript sauber ausführen

  1. Öffnen Sie ein neues Skript und speichern Sie es als vorlesung1_start.R.
  2. Ergänzen Sie oben einen kurzen Kommentar wie # Erste Schritte in RStudio.
  3. Schreiben Sie darunter mindestens fünf Zeilen Code, darunter:
sqrt(81)
round(exp(1), 3)
abs(-15)
  1. Führen Sie zunächst nur zwei Zeilen gezielt aus.
  2. Ergänzen Sie dann absichtlich eine fehlerhafte Zeile wie logg(7) und lesen Sie die Fehlermeldung.
  3. Korrigieren Sie die Zeile und führen Sie das Skript anschließend vollständig aus.
  4. Kontrollieren Sie, ob alle Ergebnisse ohne Fehlermeldung in der Konsole erscheinen.
  • Erwartet wird ein Skript, das gespeichert ist und ohne Fehler läuft.
  • Nutzen Sie den Editor bewusst als Arbeitsort und die Konsole als Rückmeldung.

1.5 Besprechung: RStudio sicher nutzen

  • Editor für dauerhaften Code, Konsole für schnelles Testen
  • Ergebnisse und Fehlermeldungen erscheinen in der Konsole
  • Hilfe und Pakete liegen standardmäßig im rechten unteren Bereich
  • Wenn nichts markiert ist, wird nur die aktuelle Zeile ausgeführt
  • Tastenkürzel sparen im Alltag sehr viel Zeit

Merksatz

Die Konsole ist zum Ausprobieren da. Alles, was Sie später noch brauchen, sollte in einem Skript stehen.

2 Hilfe und Pakete

2.1 Orientierung: Hilfeseiten und Paket-Hilfe nutzen

  • Bekannte Funktion: ?mean oder help(mean)
  • Unbekannte Funktion: help.search("weighted mean"), ??"weighted mean" oder apropos("mean")
  • Beispiele ausführen: example(mean)
  • Paket-Hilfe: help(package = "datasets")
  • Wichtige Bereiche in der Hilfe: Description, Usage, Arguments, Examples
  • Pakete laden: library(...), installieren: install.packages(...)
?mean
help.search("weighted mean")
example(mean)
help(package = "datasets")

Hinweis

Wenn Sie eine Funktion noch nicht kennen, lesen Sie zuerst Description und Usage, danach Arguments und erst dann die Examples.

2.2 Kurzübung: Hilfeseiten lesen

  1. Finden Sie heraus, was abs() macht.
  2. Öffnen Sie die Hilfeseite von mean.
  3. Lesen Sie in der Hilfe gezielt Usage, Arguments und Examples.
  4. Führen Sie mit example(mean) ein Beispiel aus.
  5. Suchen Sie ohne exakten Funktionsnamen nach "weighted mean".
  6. Probieren Sie zusätzlich apropos("mean") aus.
  • Lesen Sie in der Hilfe gezielt:
  • Description
  • Usage
  • Arguments
  • Examples

2.3 Kurzübung: Paket-Hilfe und Beispieldatensätze

  1. Schauen Sie mit search(), welche Pakete aktuell geladen sind.
  2. Öffnen Sie die Paket-Hilfe von datasets.
  3. Schauen Sie sich die ersten drei Zeilen von iris an.
  4. Betrachten Sie die ersten drei Zeilen und vier Spalten von mtcars.
  5. Vergleichen Sie class(iris) und class(iris$Species).
  6. Falls datasets nicht geladen ist, laden Sie es bewusst mit library(datasets).
  • Fokus:
  • geladene Pakete ansehen
  • Paket-Hilfe von datasets öffnen
  • Datensatzstruktur und Spaltentyp unterscheiden

2.4 Arbeitsphase: Hilfe für unbekannte Funktionen nutzen

  1. Suchen Sie ohne vorgegebenen Funktionsnamen nach einer Funktion für den gewichteten Mittelwert.
  2. Öffnen Sie die passende Hilfeseite und notieren Sie den exakten Funktionsnamen.
  3. Führen Sie ein Beispiel aus der Hilfe aus oder formulieren Sie selbst ein kleines Beispiel.
  4. Öffnen Sie anschließend die Paket-Hilfe von datasets.
  5. Wählen Sie dort einen Datensatz, den Sie noch nicht kennen, zum Beispiel AirPassengers oder ChickWeight.
  6. Prüfen Sie mit class(...), welche Struktur der Datensatz hat, und zeigen Sie die ersten drei Einträge an.
  • Erwartet werden ein gefundener Funktionsname, ein ausgeführtes Beispiel und ein kurzer Blick in einen neuen Datensatz.
  • Arbeiten Sie schrittweise: suchen, lesen, ausprobieren.

2.5 Besprechung: Hilfe systematisch lesen

  • Mit ?funktion oder help(funktion) öffnen Sie eine bekannte Hilfeseite direkt.
  • Mit help.search(...), ?? oder apropos(...) suchen Sie nach unbekannten Funktionen.
  • example(...) zeigt schnell, wie eine Funktion verwendet wird.
  • help(package = "...") ist der richtige Einstieg für Datensätze und Paketüberblicke.

Merksatz

Wenn der Funktionsname unbekannt ist: erst suchen, dann lesen, dann ein Beispiel ausführen.

3 Objekte, Environment und Datenstrukturen

3.1 Orientierung: Objekte, Zuweisungen und Environment

  • Objekte werden in R meist mit <- zugewiesen.
  • Nach einer Zuweisung liegen sie in der Arbeitsumgebung (Environment).
  • Mit ls() sehen Sie alle Objekte, mit rm(...) löschen Sie gezielt.
  • Mit getwd() prüfen Sie das aktuelle Arbeitsverzeichnis.
  • Überschreiben ist erlaubt, aber oft eine Fehlerquelle.
x <- 5
y <- 2
z <- 1

x^y
ls()

3.2 Orientierung: Atomare Datentypen im Überblick

Typ Beschreibung Typ prüfen / erzeugen Beispiel
numeric Dezimalzahlen is.numeric(x), as.numeric(x) 3.14
integer ganze Zahlen is.integer(x), as.integer(x) 5L
logical Wahrheitswerte is.logical(x), as.logical(x) TRUE
character Textzeichenketten is.character(x), as.character(x) "R"
factor kategoriale Werte mit Levels is.factor(x), factor(x) factor(c("rot", "blau"))

Hinweis

Für eine erste Diagnose helfen mode(...), class(...) und str(...): zuerst den Typ prüfen, dann die Struktur lesen.

3.3 Orientierung: Sonderwerte und Typkonvertierung

Wert Bedeutung Typischer Anlass Prüfen
NA fehlender Wert Beobachtung fehlt is.na(x)
NaN ungültiges Rechenergebnis 0 / 0 is.nan(x)
NULL leeres Objekt Element fehlt vollständig is.null(x)
Inf, -Inf positive / negative Unendlichkeit 1 / 0, -1 / 0 is.infinite(x)

Achtung

Typkonvertierung kann Informationen verlieren oder neue fehlende Werte erzeugen, z. B. bei as.numeric(c("3", "R")).

3.4 Orientierung: Datenstrukturen im Überblick

Struktur Dimension Homogen? Typischer Inhalt Erzeugung
vector 1D ja Werte eines Typs c(1, 2, 3)
matrix 2D ja rechteckige Tabelle eines Typs matrix(1:6, nrow = 2)
list 1D nein gemischte Objekte list(a = 1:3, b = "R")
data.frame 2D nein tabellarische Beobachtungen mit verschiedenen Variablentypen data.frame(x = 1:3, y = c("a", "b", "c"))

Hinweis

factor ist keine eigene mehrdimensionale Datenstruktur, sondern ein spezieller Vektor für kategoriale Variablen.

3.5 Orientierung: Datenstrukturen nach Dimension und Datentyp

Dimension Homogene Datentypen Heterogene Datentypen
1 dimensional vector list
2 dimensional matrix data.frame

Merksatz

Homogen bedeutet: Alle Elemente haben denselben atomaren Typ. Heterogen bedeutet: Verschiedene Typen dürfen nebeneinander vorkommen.

3.6 Orientierung: Zugriff auf Vektoren und Matrizen

Struktur Syntax Auswahl Ergebnis
vector x[1] erstes Element Vektor der Länge 1
vector x[c(2, 4)] Elemente an Position 2 und 4 Vektor
vector x[x > 0] alle positiven Werte Vektor
matrix m[2, 3] Zelle in Zeile 2, Spalte 3 einzelner Wert
matrix m[, 2] gesamte zweite Spalte Vektor
matrix m[, 2, drop = FALSE] zweite Spalte, Struktur bleibt erhalten Matrix mit einer Spalte

3.7 Orientierung: Zugriff auf Listen und Data Frames

Struktur Syntax Auswahl Ergebnis
list l[1] erstes Element als Teilmenge list
list l[[1]] Inhalt des ersten Elements Inhalt des Elements
list l$Matrix benanntes Element Inhalt des Elements
data.frame df["Alter"] Spalte als Teilmenge data.frame mit einer Spalte
data.frame df[["Alter"]] Spalte direkt Vektor oder Faktor
data.frame df$Alter benannte Spalte direkt Vektor oder Faktor
data.frame df[1, ] erste Zeile data.frame
data.frame df[1, "Alter"] Zelle in Zeile 1, Spalte Alter einzelner Wert

3.8 Orientierung: Zugriff mit [], [[ ]] und $ bewusst wählen

Operator Geeignet für Idee Standardrückgabe
[] alle indexierbaren Strukturen Teilmenge auswählen Struktur bleibt meist erhalten
[[ ]] list, data.frame genau ein Element holen Inhalt des Elements
$ benannte list, benannter data.frame benanntes Element holen Inhalt des Elements

Achtung

df["Alter"] bleibt ein Data Frame, df[["Alter"]] und df$Alter liefern die Spalte direkt. Wenn die Struktur erhalten bleiben soll, helfen bei Matrizen und Data Frames oft [] und bei Bedarf drop = FALSE.

3.9 Orientierung: Faktoren und Struktur mit str()

  • factor speichert kategoriale Merkmale intern als Codes mit Labels.
  • levels(...) zeigt und verändert Faktorstufen.
  • Neue Ausprägungen müssen zuerst als Level angelegt werden.
  • str(...) macht Faktoren, Listen und Data Frames schnell lesbar.
  • iris und mtcars zeigen gut, welche Variablen metrisch und welche kategorial sind.
automarke_chr <- c("Opel", "BMW", "Mercedes")
automarke_factor <- factor(automarke_chr)

levels(automarke_factor)
str(iris$Species)

Achtung

as.numeric(automarke_factor) liefert die internen Codes der Levels und nicht die sichtbaren Labels.

3.10 Kurzübung: Objekte im Environment verwalten

  1. Legen Sie an:
x <- 5
y <- 2
z <- 1
  1. Geben Sie x aus und berechnen Sie x^y.
  2. Überschreiben Sie x mit dem Wert 7.
  3. Lassen Sie sich alle Objekte mit ls() anzeigen.
  4. Löschen Sie z mit rm(z) und prüfen Sie erneut mit ls().
  5. Zeigen Sie das aktuelle Arbeitsverzeichnis mit getwd() an.
  6. Löschen Sie zusätzlich x und y und prüfen Sie, ob die Arbeitsumgebung leer ist.
  • Fokus:
  • Objekte anlegen und überschreiben
  • ls() und rm(...) bewusst einsetzen
  • Arbeitsverzeichnis mit getwd() prüfen

3.11 Kurzübung: Vektoren und Indizierung

  1. Erstellen Sie:
x <- -5:5
  1. Geben Sie das erste Element, die Elemente an Position 4 und 5 und alle Elemente außer dem ersten aus.
  2. Wählen Sie alle positiven Werte aus.
  3. Überschreiben Sie das erste Element mit 10000.
  4. Geben Sie anschließend den gesamten Vektor aus.
  5. Geben Sie zusätzlich alle Elemente außer Position 1 und 6 aus.
  • Fokus:
  • Auswahl über Positionen
  • Auswahl über Bedingungen
  • einzelne Elemente gezielt überschreiben

3.12 Kurzübung: Matrix und Data Frame

  1. Erstellen Sie:
quadrate <- (1:20)^2
m <- matrix(quadrate, nrow = 4, ncol = 5, byrow = FALSE)
df <- as.data.frame(m)
  1. Greifen Sie auf das Element in Zeile 2 und Spalte 3 von m zu.
  2. Berechnen Sie die Summe der dritten Spalte von m.
  3. Geben Sie aus df die ersten zwei Zeilen der Spalten V2 und V3 aus.
  4. Vergleichen Sie class(df["V2"]), class(df[["V2"]]) und class(df$V2).
  5. Wählen Sie aus m zusätzlich nur die zweite und vierte Spalte aus.
  • Fokus:
  • [Zeile, Spalte] bei Matrix und Data Frame
  • df["V2"], df[["V2"]] und df$V2 unterscheiden
  • Rückgabetyp mit class(...) prüfen

3.13 Kurzübung: Listen und Zugriffe

  1. Erstellen Sie:
l <- list(
  Vektor = 1:10,
  Matrix = matrix(1:12, nrow = 3),
  Character = c("a", "b", "c")
)
  1. Geben Sie das erste Listenelement aus.
  2. Greifen Sie auf das Element in Zeile 2, Spalte 3 von l$Matrix zu.
  3. Vergleichen Sie class(l["Matrix"]) und class(l[["Matrix"]]).
  4. Geben Sie den zweiten Eintrag von l$Character aus.
  5. Prüfen Sie zusätzlich die Struktur der gesamten Liste mit str(l).
  • Fokus:
  • Liste als Container verstehen
  • ["Matrix"] und [[ "Matrix" ]] unterscheiden
  • innerhalb eines Listenelements weiter zugreifen

3.14 Kurzübung: Faktoren und Struktur mit iris und mtcars

  1. Prüfen Sie mit str(iris), welche Struktur iris hat.
  2. Bestimmen Sie die Klasse der Variablen Species.
  3. Lassen Sie sich die Levels von Species anzeigen.
  4. Erstellen Sie ein Objekt autos <- mtcars.
  5. Wandeln Sie in autos die Variablen cyl und am in Faktoren um.
  6. Prüfen Sie anschließend die Struktur von autos[, c("mpg", "cyl", "am")].
  7. Zeigen Sie alle Zeilen aus autos, für die am == 1 gilt, und nur die Spalten mpg, cyl und am.
  • Fokus:
  • Struktur mit str(...) lesen
  • kategoriale Variablen als factor
  • mit Bedingungen Zeilen auswählen

3.15 Arbeitsphase: Datenstrukturen mit datasets

  1. Legen Sie an:
autos <- mtcars
  1. Wandeln Sie cyl, gear und am in Faktoren um.
  2. Prüfen Sie die Struktur von autos.
  3. Erstellen Sie ein Objekt auswahl mit allen Autos, für die mpg > 20 und am == 1 gilt.
  4. Zeigen Sie aus auswahl nur mpg, cyl, gear und am.
  5. Vergleichen Sie class(auswahl["gear"]) und class(auswahl[["gear"]]).
  6. Bestimmen Sie zusätzlich die Zeile mit dem höchsten mpg in autos.
  7. Prüfen Sie zusätzlich mit str(iris), wie sich iris von mtcars unterscheidet.
autos <- mtcars
autos$cyl <- factor(autos$cyl)
autos$gear <- factor(autos$gear)
autos$am <- factor(autos$am)
  • Erwartet wird eine saubere Teilmenge plus ein bewusster Vergleich von [] und [[ ]].
  • Prüfen Sie Zwischenschritte mit class(...) oder str(...).

3.16 Arbeitsphase: Objekte speichern und wieder laden

  1. Legen Sie an:
quadrate <- matrix((1:20)^2, nrow = 4, ncol = 5)
  1. Prüfen Sie mit getwd(), wo Sie aktuell arbeiten.
  2. Speichern Sie quadrate mit save(...) als Datei quadrate.RData.
  3. Löschen Sie quadrate aus dem Environment.
  4. Laden Sie die Datei wieder mit load(...).
  5. Prüfen Sie mit ls(), ob das Objekt wieder verfügbar ist.
  6. Speichern Sie zusätzlich ein zweites Objekt und laden Sie beide gemeinsam wieder.
quadrate <- matrix((1:20)^2, nrow = 4, ncol = 5)
getwd()
save(quadrate, file = "quadrate.RData")
  • Ziel ist ein Objekt, das nach rm(...) nur über die Datei zurückkommt.
  • Achten Sie darauf, zwischen Objektname und Dateiname nicht zu verwechseln.

3.17 Besprechung: Welche Zugriffssyntax passt?

  • Objekte im Environment auflisten: ls()
  • Objekt löschen: rm(x)
  • Mehrere Positionen aus einem Vektor: x[c(2, 4)]
  • Alle Elemente außer einigen Positionen: x[-c(1, 6)]
  • Eine Zelle aus Matrix oder Data Frame: m[2, 3] oder df[3, 2]
  • Ganze Spalte als data.frame: df["V2"]
  • Ganze Spalte als Vektor: df[["V2"]] oder df$V2
  • Verschachteltes Element aus Liste: l[["Matrix"]]
ls()
rm(x)
x[-c(1, 6)]
df["V2"]
df[["V2"]]
l[["Matrix"]]

Merksatz

Bei Unsicherheit immer zuerst fragen: Will ich eine Teilmenge derselben Struktur oder genau den enthaltenen Wert?

4 Logische Operatoren und Kontrollstrukturen

4.1 Orientierung: Logische Operatoren und Skalar vs. Vektor

  • Vergleiche liefern immer TRUE oder FALSE.
  • Häufige Operatoren: <, >, <=, >=, ==, !=, %in%
  • Wichtige Hilfsfunktionen: any(), all(), which(), which.max()
  • x > 3 kann einen ganzen logischen Vektor liefern.
  • any(...) und all(...) verdichten einen Vektor wieder auf genau einen Wert.
  • Für if (...) brauchen wir genau einen logischen Wert.
x <- 5:1
x > 3
any(x > 3)
all(x > 3)

if (any(x > 3)) {
  meldung <- "mindestens ein Treffer"
}

Achtung

if (...) braucht genau ein TRUE oder FALSE. Für ganze Vektoren oder Spalten ist meist ifelse(...) die bessere Wahl.

4.2 Orientierung: Entscheidungen mit if / else if / else

  • if prüft eine Bedingung und führt bei TRUE genau einen Zweig aus.
  • else ergänzt den Fall, dass die Bedingung FALSE ist.
  • else if erweitert die Entscheidung um weitere Fälle.
  • Die Reihenfolge der Bedingungen ist wichtig: Der erste passende Fall gewinnt.
  • ifelse(...) ist etwas anderes und arbeitet elementweise auf Vektoren.
punkte <- 74

if (punkte >= 90) {
  note <- "sehr gut"
} else if (punkte >= 50) {
  note <- "bestanden"
} else {
  note <- "nicht bestanden"
}

Merksatz

Mehrere Fälle formulieren Sie in R mit if / else if / else, nicht mit mehreren voneinander losgelösten if-Blöcken.

4.3 Orientierung: for und while im Vergleich

  • for eignet sich, wenn die Anzahl der Schritte oder ein Indexvektor vorher feststeht.
  • while eignet sich, wenn eine Bedingung solange gelten soll, bis sie kippt.
  • Bei for initialisieren wir oft zuerst ein Zielobjekt und greifen dann mit [i] zu.
  • Bei while brauchen wir immer Startwert, Bedingung und Aktualisierung.
  • Ohne Update oder erreichbares Abbruchkriterium entsteht schnell eine Endlosschleife.
werte <- c(2, 4, 6)
quadrate <- numeric(length(werte))

for (i in 1:length(werte)) {
  quadrate[i] <- werte[i]^2
}

summe <- 0
i <- 1
while (summe < 20) {
  summe <- summe + i
  i <- i + 1
}

Achtung

Eine while-Schleife endet nur, wenn sich die Bedingung im Schleifenkörper irgendwann wirklich ändert.

4.4 Kurzübung: Logische Operatoren anwenden

  1. Legen Sie an:
x <- 5:1
  1. Prüfen Sie, welche Werte größer als 3 sind.
  2. Bestimmen Sie mit any(...), ob Werte kleiner als 2 enthalten sind.
  3. Bestimmen Sie mit all(...), ob alle Werte ungleich 0 sind.
  4. Geben Sie mit which(...) die Positionen der Werte kleiner als 2 aus.
  5. Prüfen Sie mit %in%, ob 5:7 in x enthalten ist.
  6. Bestimmen Sie zusätzlich mit which.max(...), an welcher Position das Maximum steht.
  • Fokus:
  • logische Vektoren
  • any(...) und all(...)
  • which(...), %in% und which.max(...)

4.5 Kurzübung: if / else if / else formulieren

  1. Legen Sie an:
punkte <- 74
  1. Schreiben Sie eine Fallunterscheidung mit drei Ausgängen: "nicht bestanden" für Werte unter 50, "bestanden" für Werte von 50 bis 89, "sehr gut" ab 90.
  2. Speichern Sie das Ergebnis in status.
  3. Testen Sie Ihre Kaskade zusätzlich für punkte <- 42 und punkte <- 95.
  • Fokus:
  • genau ein Skalar als Bedingung
  • drei Fälle in der richtigen Reihenfolge
  • denselben Code mit verschiedenen Eingaben prüfen

4.6 Kurzübung: for-Schleifen mit Index sauber schreiben

  1. Legen Sie an:
df <- data.frame(
  Name = c("Mueller", "Meyer", "Schneider", "Meyer", "Meier"),
  Alter = c(45, 23, 62, 32, 22)
)
  1. Initialisieren Sie die neue Spalte Geburtsjahr zunächst mit NA.
  2. Füllen Sie Geburtsjahr mit einer for-Schleife und dem Referenzjahr 2026.
  3. Erzeugen Sie zusätzlich mit ifelse(...) die Spalte Volljaehrig für Alter >= 18.
  4. Geben Sie den fertigen Data Frame aus.
  • Fokus:
  • Zielobjekt zuerst anlegen
  • Zugriff mit [i]
  • ifelse(...) und Schleife bewusst trennen

4.7 Kurzübung: while-Schleifen sicher verwenden

  1. Legen Sie an:
ziel <- 100
betrag <- 0
monate <- 0
  1. Schreiben Sie eine while-Schleife, die jeden Monat 15 Euro zu betrag addiert.
  2. Erhöhen Sie in jedem Schleifendurchlauf auch monate um 1.
  3. Lassen Sie die Schleife laufen, bis betrag mindestens 100 ist.
  4. Geben Sie am Ende betrag und monate aus.
  • Fokus:
  • Startwert und Bedingung
  • Update im Schleifenkörper
  • Ergebnis erst nach Schleifenende prüfen

4.8 Arbeitsphase: FizzBuzz Schritt für Schritt entwickeln

  1. Erzeugen Sie den Vektor zahlen <- 1:30.
  2. Legen Sie ein Ausgabeobjekt an, das für jede Zahl genau einen Eintrag speichert.
  3. Formulieren Sie zunächst für eine Zahl die Logik mit if / else if / else: FizzBuzz bei Teilbarkeit durch 15, Fizz bei Teilbarkeit durch 3, Buzz bei Teilbarkeit durch 5, sonst die Zahl selbst.
  4. Übertragen Sie diese Logik in eine for-Schleife über alle Werte aus zahlen.
  5. Füllen Sie das Ausgabeobjekt Schritt für Schritt.
  6. Geben Sie das fertige Ergebnis für 1:30 aus.
  • Starten Sie mit ausgabe <- character(length(zahlen)).
  • Für Teilbarkeit brauchen Sie den Operator %%.
  • Wichtig: Prüfen Sie zuerst %% 15 == 0, dann 3, dann 5.

4.9 Arbeitsphase: Kundendaten mit Logik anwenden

  1. Erstellen Sie folgenden Data Frame:
kunden <- data.frame(
  Name = c("Mueller", "Meyer", "Schneider", "Meyer", "Meier"),
  Umsatz = c(120, 650, 430, 880, 210),
  Newsletter = c(TRUE, TRUE, FALSE, TRUE, FALSE)
)
  1. Erzeugen Sie mit ifelse(...) die Spalte VIP für den Fall Umsatz >= 500 und Newsletter == TRUE.
  2. Bestimmen Sie mit which(...), welche Zeilen VIP == TRUE sind.
  3. Schreiben Sie ein if / else, das die Meldung "Es gibt VIP-Kunden" oder "Es gibt keine VIP-Kunden" in meldung speichert.
  4. Legen Sie die Spalte Bonus an und füllen Sie sie mit einer for-Schleife: 20 für VIP-Kunden, sonst 5.
  5. Ergänzen Sie die Textspalte Segment mit einer if / else if / else-Kaskade: "A" für Umsatz >= 800, "B" für Umsatz >= 400, sonst "C".
  6. Prüfen Sie mit any(...), ob ein Bonus größer als 10 ist, und mit all(...), ob alle Umsätze positiv sind.
  7. Geben Sie den fertigen Data Frame aus.
  • Kombinieren Sie hier Vektorlogik, Skalarentscheidung und Schleife.
  • Ergänzen Sie Segment am besten innerhalb derselben for-Schleife wie Bonus.

4.10 Besprechung: Welche Kontrollstruktur passt wann?

  • Vergleiche liefern logische Werte, keine Textausgaben.
  • any(...) und all(...) verdichten mehrere logische Werte auf genau einen Wert.
  • if / else if / else passt für einzelne Entscheidungen mit zwei oder mehr Fällen.
  • ifelse(...) passt für elementweise Vektorlogik.
  • for passt für bekannte Wiederholungen oder einen festen Indexvektor.
  • while passt für Wiederholungen mit offener Laufzeit und klarer Abbruchbedingung.
  • Typische Fehler sind ein Vektor in if, ein fehlendes Update in while oder die falsche Reihenfolge bei FizzBuzz.

Merksatz

Fragen Sie bei jeder Aufgabe zuerst: Entscheide ich einmal, elementweise für viele Werte oder wiederholt über mehrere Schritte?

5 Eigene Funktionen und Kommentare

5.1 Orientierung: Funktionen definieren und Code dokumentieren

  • Funktionen werden wie andere Objekte per Zuweisung definiert.
  • Argumente stehen in runden Klammern, Ergebnisse werden mit return(...) zurückgegeben.
  • Mehrere Rückgabewerte sammelt man oft in einer list.
  • Funktionen sind selbst Objekte und lassen sich ohne Klammern anzeigen.
  • Kommentare mit # machen Code später nachvollziehbar.
rabatt_preis <- function(preis, rabatt) {
  endpreis <- preis * (1 - rabatt)
  return(endpreis)
}

rabatt_preis(preis = 80, rabatt = 0.15)

Tipp

Eine Funktion ist selbst ein Objekt. Sie können sie ohne Klammern anzeigen lassen, um ihren Code noch einmal zu prüfen.

5.2 Kurzübung: Rabattfunktion schreiben

  1. Schreiben Sie eine Funktion rabatt_preis(preis, rabatt).
  2. Die Funktion soll aus einem Preis und einem Rabattanteil den reduzierten Preis berechnen.
  3. Geben Sie das Ergebnis mit return(...) zurück.
  4. Testen Sie die Funktion mit preis = 80 und rabatt = 0.15.
  5. Testen Sie die Funktion zusätzlich mit preis = 120 und rabatt = 0.25.
  • Fokus:
  • zwei Argumente
  • ein Rückgabewert
  • erst rechnen, dann return(...)

5.3 Kurzübung: Rabattfunktion kommentieren und sauber testen

  1. Erstellen Sie ein neues Skript mit einem kurzen Titelkommentar.
  2. Übertragen Sie die Funktion rabatt_preis(...) in das Skript.
  3. Ergänzen Sie im Funktionskörper zwei sinnvolle Kommentare.
  4. Testen Sie die Funktion mit:
rabatt_aktion <- rabatt_preis(preis = 120, rabatt = 0.2)
  1. Testen Sie die Funktion zusätzlich mit einem zweiten Beispiel Ihrer Wahl.
  2. Lassen Sie sich zum Schluss den Funktionscode anzeigen, indem Sie nur den Funktionsnamen eingeben.
  3. Ergänzen Sie oberhalb der Funktion einen einfachen Titelblock mit Datei, Autor und Beschreibung.
  • Beginnen Sie mit einem Kommentarblock wie # Rabattberechnung.
  • Testen Sie die Funktion mit mindestens zwei unterschiedlichen Preisen.

5.4 Arbeitsphase: Eine neue Funktion Schritt für Schritt erweitern

  1. Starten Sie mit folgendem Grundgerüst:
auftragsbericht <- function(preis, kosten, menge) {
  umsatz <- preis * menge
  gesamtkosten <- kosten * menge
  gewinn <- umsatz - gesamtkosten

  # hier Status ergänzen

  return(list(
    umsatz = umsatz,
    gesamtkosten = gesamtkosten,
    gewinn = gewinn
  ))
}
  1. Ergänzen Sie ein if / else if / else, das status auf "Verlust", "Break-even" oder "Gewinn" setzt.
  2. Fügen Sie status zur Rückgabe-Liste hinzu.
  3. Ergänzen Sie einen kurzen Titelblock und zwei Kommentare im Funktionskörper.
  4. Testen Sie die Funktion für (preis, kosten, menge) mit (20, 25, 10), (20, 20, 10) und (30, 18, 10).
  5. Prüfen Sie bei einem Testergebnis gezielt $gewinn und $status.
  • Erwartet wird eine neue Funktion auf Basis des Grundgerüsts.
  • Ergänzen Sie zuerst den status, dann die Rückgabe, dann die Tests.

5.5 Besprechung: Funktionen lesbar und testbar halten

  • Funktionen kapseln wiederkehrende Logik in einem benannten Objekt.
  • Rückgaben sollten klar benannt sein, damit der Zugriff mit $ eindeutig bleibt.
  • Kommentare erklären Absicht und Struktur, nicht jede einzelne Zeichenkette.
  • Ein gutes Grundgerüst hilft beim Start, die eigentliche Logik entsteht dann Schritt für Schritt.
  • Testen Sie Funktionen immer mit mehreren Eingaben, nicht nur mit einem Beispiel.

Merksatz

Eine gute Funktion ist kurz, klar benannt, kommentiert und mit mehreren Beispielen geprüft.