var1 <- 2 * 4
var1[1] 8
In Kap. 1 hast du RStudio eingerichtet, in Kap. 2 dein erstes Quarto-Dokument gebaut. Jetzt geht es an die Sprache, in der du in diesem Buch alles formulierst: R. Variablen, Funktionen, Datentypen und der Pipe-Operator sind die Bausteine, mit denen du in den folgenden Kapiteln Datensätze einliest, transformierst, analysierst und visualisierst.
Anders als die SPSS-Syntax — die im Kern eine Befehlssprache mit festem Vokabular ist — schreibst du in R selbst Funktionen, baust Werte zu Vektoren, kombinierst sie zu Datensätzen. Diese kleine Hürde am Anfang zahlt sich später aus: dieselben Bausteine tragen dich vom Einstieg bis zur Bachelorarbeit.
Forschungsjournal: Wo stehst du in deiner Mini-Studie? Du hast in Kapitel 1 die IDE eingerichtet und in Kapitel 2 den Berichts-Workflow verstanden. Jetzt lernst du die Sprachelemente, mit denen du gleich Survey-Items rekodierst, Skalen baust und Modelle rechnest. Beispiele in diesem Kapitel sind bewusst sozial- und politikwissenschaftlich gewählt — du wirst dieselben Operationen ab Kapitel 4 auf echte ALLBUS-Variablen anwenden.
#-Kommentaren für dein zukünftiges Ich verständlich halten.==, &, %in%, …) einsetzen.NA) umgehen und sie aus Berechnungen ausschließen.|> lesen und schreiben.|> und dem älteren %>% aus magrittr einordnen.Eine Variable speichert einen Wert. In R weist du Werte über den Zuweisungspfeil <- zu:
var1 <- 2 * 4
var1[1] 8
var1 (links) ist der Variablenname; 2 * 4 (rechts) der Ausdruck, dessen Ergebnis (8) gespeichert wird.
Wenn du die Zuweisung in runde Klammern setzt, wird das Ergebnis gleichzeitig in der Konsole angezeigt:
(var2 <- 2 * 4)[1] 8
Vorsicht: <- statt =. Aus anderen Programmiersprachen kennst du = als Zuweisungsoperator. R akzeptiert es in vielen Kontexten, der idiomatische Operator ist aber <-. Grund: = wird in R innerhalb von Funktionsaufrufen für Argumente verwendet (mean(x = data)). Wenn du <- für Zuweisung und = für Argumente strikt trennst, vermeidest du subtile Fehler.
Tastenkürzel für <-: option + - (macOS) bzw. alt + - (Windows/Linux).
Eine Variable muss mit einem Buchstaben beginnen und darf danach Buchstaben, Zahlen, Punkte (.) und Unterstriche (_) enthalten. Leerzeichen sind nicht erlaubt.
Für lesbaren Code halten sich Sozialwissenschaftler:innen meist an eine von zwei Konventionen:
snake_case — alles klein, Worte mit Unterstrich verbunden: mittelwert_alter. Tidyverse-Standard.camelCase — erstes Wort klein, weitere groß beginnend: mittelwertAlter. Verbreitet im Stata- und JavaScript-Umfeld.Wähle eine und bleibe konsequent. In diesem Buch nutzen wir snake_case.
# Gut
mittelwert_alter
faktor_skala
islamophobie_skala
# Schlecht (inkonsistent)
Mittelwert.alter
mittelwertAlter_neu
# Verboten (Leerzeichen)
mittelwert alterAlles, was hinter einem # steht, wird von R ignoriert — du nutzt das, um deinen Code zu erklären:
# Stichprobengröße der Mini-Studie
n_befragte <- 5246 # ALLBUS 2023, gesamtKommentare sind das, was deinem zukünftigen Ich (oder Reviewer:innen) den Code in drei Wochen wieder verständlich macht. Schreibe sie für die Frage Warum? — nicht für das, was der Code ohnehin schon sagt.
„Everything that exists is an object. Everything that happens is a function call.” — John Chambers
Eine Funktion ist ein benanntes Werkzeug, dem du Argumente übergibst und das ein Ergebnis zurückgibt. Eine generische Funktion sieht so aus:
funktionsname(arg1 = wert1, arg2 = wert2, ...)funktionsname — was die Funktion macht.arg1, arg2 — wie sie ihre Arbeit konfiguriert.arg1 = wert1) oder positional übergeben werden.Einige Argumente haben Default-Werte: sie müssen nicht angegeben werden, weil der häufigste Wert voreingestellt ist.
seq(from = 1, to = 10, by = 2) # explizit[1] 1 3 5 7 9
seq(1, 10, 2) # positional, identisch[1] 1 3 5 7 9
Tipp: ?funktion. Wenn du die Argumente einer Funktion vergessen hast, gibt ?funktion (z. B. ?seq) die Hilfe in RStudio aus. Innerhalb der Klammern öffnet Tab ein Dropdown mit allen Argumenten.
| Funktion | Wirkung |
|---|---|
c(...) |
erzeugt einen Vektor aus den Argumenten (combine) |
seq(from, to, by) |
erzeugt eine Sequenz |
1:5 |
reguläre Sequenz (1, 2, 3, 4, 5) |
rep(x, times, each) |
wiederholt x
|
head(x, n) |
die ersten n Elemente |
tail(x, n) |
die letzten n Elemente |
length(x) |
Anzahl der Elemente |
round(x, digits) |
rundet Zahlen |
Drei Gruppen von Operatoren brauchst du immer wieder.
Arithmetisch.
| Operator | Wirkung |
|---|---|
+ |
Addition |
- |
Subtraktion |
* |
Multiplikation |
/ |
Division |
^ |
Potenzieren |
%% |
Modulo (Rest) |
Vergleich. Geben einen logischen Wert TRUE/FALSE zurück.
| Operator | Wirkung |
|---|---|
== |
gleich |
!= |
ungleich |
<, <=
|
kleiner (gleich) |
>, >=
|
größer (gleich) |
%in% |
enthalten in Menge |
Vorsicht: == ist nicht =. Für Vergleiche verwendest du immer == (doppeltes Gleichheitszeichen). Einzelnes = ist für Funktionsargumente reserviert — mean(x = data) setzt x, vergleicht aber nichts.
Logisch. Verknüpfen Wahrheitswerte.
| Operator | Wirkung |
|---|---|
& |
UND |
| |
ODER |
! |
NICHT |
Ein kleines Beispiel:
alter <- c(22, 45, 67, 18, 33)
alter > 30[1] FALSE TRUE TRUE FALSE TRUE
alter >= 18 & alter <= 65[1] TRUE TRUE FALSE TRUE TRUE
[1] TRUE FALSE FALSE FALSE TRUE
Diese Operatoren wirst du in Kap. 4 ständig brauchen, wenn du Fälle mit filter() auswählst.
In R ist alles ein Objekt — ein Wert, ein Datensatz, ein statistisches Modell, sogar eine Funktion. Die wichtigsten Datentypen für sozialwissenschaftliche Arbeit:
Ein Vektor ist eine eindimensionale Sammlung gleicher Datentypen. Drei Typen wirst du am häufigsten sehen:
Vorsicht: TRUE/FALSE schreiben, nicht T/F. Die Kurzschreibweisen funktionieren — sind aber überschreibbar, deshalb in der Praxis fehleranfällig. Schreibe immer TRUE und FALSE aus.
Mit Indizes greifst du auf einzelne Elemente zu:
zahlen[1] # erstes Element[1] 1
zahlen[2:4] # zweites bis viertes[1] 2 3 4
zahlen[-1] # alle ausser dem ersten[1] 2 3 4 5
Ein Faktor ist ein Vektor mit definierten Ausprägungen (levels) — für kategoriale Variablen wie Geschlecht oder Bildung.
Faktoren sind wichtig für Regressionsmodelle — die erste Ausprägung wird automatisch zur Referenzkategorie. Mit relevel() (Base R) oder forcats::fct_relevel() (tidyverse) änderst du die Reihenfolge.
Hintergrund: haven_labelled vs. Faktor. Wenn du Daten aus SPSS einliest (Kap. 4), bekommst du Spalten vom Typ <haven_labelled>. Das ist kein Faktor — sondern ein numerischer Vektor mit Labels als Begleitinformation. Mit to_label() (mariposa) wandelst du sie bei Bedarf in einen klassischen Faktor.
Ein Tibble ist die moderne Form des Data Frames im tidyverse — eine Tabelle mit Zeilen (Fälle) und Spalten (Variablen). Du baust es mit tibble():
# A tibble: 4 × 2
geschlecht alter
<fct> <dbl>
1 Mann 34
2 Frau 41
3 Mann 28
4 Divers 52
Auf eine einzelne Spalte greifst du mit $ oder [[]] zu:
befragte$alter[1] 34 41 28 52
befragte[["alter"]][1] 34 41 28 52
befragte[1, "alter"] # erste Zeile, Spalte "alter"# A tibble: 1 × 1
alter
<dbl>
1 34
In der Praxis liest du Datensätze fertig aus SPSS-, Stata- oder Excel-Dateien ein (siehe Kap. 4). Selbst-gebaute Tibbles brauchst du fast nur für kleine Demonstrationen.
Eine Liste kann verschiedene Objekttypen unterschiedlicher Länge sammeln. Ergebnisse statistischer Analysen sind in R meistens Listen — ein Regressionsergebnis enthält Koeffizienten, Residuen, Modellgüte usw. Du musst sie selten selbst erstellen, aber regelmäßig lesen können:
NA
In echten Datensätzen fehlen oft einzelne Werte — eine Befragte hat eine Frage übersprungen, ein Messwert war ungültig, eine Auskunft wurde verweigert. R kodiert das mit einem speziellen Wert: NA (Not Available).
x <- c(1, 2, NA, 4, 5)
x[1] 1 2 NA 4 5
is.na(x) # welche Elemente sind NA?[1] FALSE FALSE TRUE FALSE FALSE
Rechnungen mit NA ergeben NA. Das ist Absicht: der Mittelwert von „1, 2, ?, 4, 5” ist eigentlich unbekannt.
Damit Funktionen wie mean(), sd() & Co. trotzdem rechnen, übergibst du na.rm = TRUE:
Hintergrund: Mehrere Arten von Missing. SPSS unterscheidet system-missing (leeres Feld) von user-missing (z. B. „keine Angabe” als Code -9). In R gibt es per Default nur ein generisches NA — beim SPSS-Import behält mariposa die user-missing-Codes aber als tagged NA, sodass du den Grund des Fehlens jederzeit nachschauen kannst. Mehr dazu in Kap. 4.
R erlaubt es, Funktionen ineinander zu verschachteln — der Output einer Funktion wird zum Input der nächsten:
Das funktioniert, aber je mehr Schritte du verschachtelst, desto schwerer wird der Code zu lesen — du musst ihn von innen nach außen lesen, was unserer natürlichen Leserichtung widerspricht. Für genau dieses Problem gibt es eine elegante Lösung: den Pipe-Operator. Ein Pipe verkettet Funktionsaufrufe linear, statt sie zu verschachteln. R kennt zwei Varianten — wir nutzen die native Pipe |>.
|>
Mit der nativen Pipe schreibst du dieselbe Pipeline linear — von links nach rechts statt von innen nach außen:
[1] 1.1 1.2 1.3
Lies das wie einen Satz: „Nimm zahlen, dann runde auf 1 Nachkommastelle, dann zeige die ersten 3.”
Tastenkürzel: cmd/strg + shift + M. Stelle in RStudio unter Tools → Global Options → Code → Use native pipe operator die Option ein, damit das Shortcut |> statt %>% einfügt.
Hintergrund: Wert nicht ans erste Argument? Standardmäßig übergibt |> den Wert als erstes Argument der nächsten Funktion. Wenn er an eine andere Stelle gehen soll, nutzt du seit R 4.2 den Platzhalter _ — er muss als benanntes Argument stehen:
allbus |>
lm(islamophobie ~ age, data = _)Bei den meisten Tidyverse-Funktionen brauchst du das nicht — sie nehmen den Datensatz ohnehin als erstes Argument.
%>% aus magrittrDu wirst in der R-Welt überall den Pipe %>% (aus dem tidyverse-Paket magrittr) sehen — in Tutorials, in Stack-Overflow-Antworten, in vielen R-Paketen intern. %>% und |> sind funktional fast identisch:
Beide funktionieren in tidyverse-Code, beide liefern dieselben Ergebnisse. Wir nutzen in diesem Buch durchgängig |>, weil er Teil der Sprache selbst ist (kein Paket nötig) und ein klein wenig schneller — aber wenn du in fremdem Code %>% siehst, ist das kein Problem.
Hintergrund: Wo %>% etwas anders ist. Der magrittr-Pipe hat einen Platzhalter ., der überall positionierbar ist: x %>% lm(y ~ ., data = .). Der native _ muss benannt sein. Bei den meisten Tidyverse-Funktionen brauchst du den Platzhalter nicht — das erste Argument ist immer der Datensatz.
Verschwundene Operatoren. %$%, %T>%, %<>% aus magrittr waren früher gelegentlich nötig (z. B. um Pipes durch Plotting-Funktionen zu führen). In diesem Buch brauchen wir sie nirgends — mariposa-Funktionen sind durchgehend data-first und pipe-freundlich.
Hier eine echte Pipeline aus Kap. 4, die zeigt, wofür Pipes wirklich nützlich sind:
allbus <- read_spss("ALLBUS2023.sav") |>
rec(mm02, rules = "rev", suffix = "r") |>
rec(mm05, rules = "rev", suffix = "r") |>
mutate(
islamophobie = row_means(pick(mm01, mm02r, mm03, mm04, mm05r, mm06),
min_valid = 5)
)Du liest: Datensatz einlesen → mm02 umpolen → mm05 umpolen → Skala bilden. Ohne Pipe wäre das ein verschachteltes Etwas, das du nur mit Mühe rückwärts lesen könntest.
Erstelle einen Vektor mit den Zahlen 10 bis 20, runde jede Zahl auf eine Dezimalstelle (auch wenn schon ganzzahlig), berechne den Mittelwert. Schreibe das einmal verschachtelt und einmal mit Pipe.
Erzeuge ein Tibble mit zwei Variablen: id (1 bis 5) und wert (zufällige Zahlen — runif(5, 0, 10) ist eine Möglichkeit). Greife danach auf die dritte Zeile zu.
demo <- tibble(
id = 1:5,
wert = runif(5, 0, 10)
)
demo
demo[3, ]Baue einen Faktor bildung mit den Ausprägungen "niedrig", "mittel", "hoch". Setze "mittel" als Referenzkategorie. Tipp: levels = setzt die Reihenfolge bei factor().
Stell dir vor, du hast eine kleine Umfrage zu Vertrauen in den Bundestag (0 = kein Vertrauen, 10 = volles Vertrauen) bei sieben Befragten gemacht: vertrauen <- c(3, 8, NA, 7, 5, NA, 9). (NA = „keine Angabe”.) Bestimme (a) den Mittelwert ohne fehlende Werte, (b) wie viele Befragte hohes Vertrauen (> 5) angegeben haben, (c) ob mindestens eine Person die Frage übersprungen hat.
Du hast in der Vertrauens-Übung gerade einzelne Kennwerte berechnet. Schreibe nun in einer Pipeline: filtere alle NA-Werte heraus, behalte nur Werte ≥ 5 (hohes Vertrauen), berechne den Mittelwert. Schreibe die Lösung sowohl verschachtelt als auch mit Pipe — welche Version findest du lesbarer?
Stelle dir vor, du würdest später dieselbe Pipeline auf den ALLBUS-Vektor pt03 (Vertrauen in den Bundestag, ~5.000 Fälle) anwenden — der Code wäre derselbe.
Anschluss: In den folgenden Kapiteln rufst du genau diese Operationen mit tidyverse-Verben (filter(), summarise()) auf — die |>-Pipe bleibt dieselbe.
<- Variablen zu und kennst die Konvention snake_case.# für dein zukünftiges Ich und Reviewer:innen.? nach.%in%.NA um und nutzt na.rm = TRUE in Berechnungsfunktionen.|> für lesbaren, linearen Code.%>% und weißt, dass |> der heutige Standard ist.Im nächsten Kapitel arbeiten wir mit echten Daten: dem ALLBUS 2023.