9  Basics der Programmiersprache R

Kurz und (fast) schmerzlos

9.1 Operatoren und grundlegende Funktionen

Arithmetische Operatoren

Operator Beschreibung Beispiel
+ Addieren 4 + 5 = 9
- Subtrahieren 5 - 4 = 1
* Multiplizieren 4 * 4 = 16
/ Dividieren 1 / 2 = 0.5
^ Potenzieren 2^0.5 = 1.414214
%% Modulo bilden 7 %% 5 = 2
  • Modulo bilden = Bestimmung des Rests einer ganzzahligen Division

Beispiel

1e5 / 33
[1] 3030.303
pi %% 3
[1] 0.1415927
1 / 3 + 1 / 2
[1] 0.8333333
6^8
[1] 1679616
  • Werte werden ohne spezielle print-Anweisung ausgegeben
  • Standardmäßig werden Fließkommaoperationen durchgeführt
  • Lassen Sie Platz um die Operatoren (außer um ^)

Variablen 1/2

x <- 32
y <- 7 / 8
x * y
[1] 28
  • Daten und Berechnungsergebnisse werden in Variablen gespeichert
  • Der Zuweisungsoperator in R ist <- (Tastenkombination alt + -)
  • Variablen im Environment gelistet (RStudio oben rechts)
  • Namen von Variablen müssen mit einem Buchstaben beginnen

Variablen 2/2

X <- pi
x <- 2
a.b <- 100
x * X * a.b
[1] 628.3185
  • pi ist eine vorbelegte Variable mit Näherung für \(\pi\)
  • Groß- und Kleinschreibung wird berücksichtigt
  • Der Punkt ist ein ganz normaler Buchstabe und kein Operator

Weitere Zuweisungsoperatoren

Zuweisung nach rechts

33 -> x
x
[1] 33
  • Die Schreibweise <- funktioniert auch so -> rum

Es geht aber auch traditionell

x = 200
x
[1] 200
  • Wenn Ihnen das lieber ist, verwenden Sie =
  • Bei einer Schreibweise bleiben

Primitive Datentypen

Datentyp Literale Art
logical TRUE, FALSE Wahrheitswert
integer 5L, 125L Ganze Zahl
double 1, 1.75, 1e10 ‘Reelle’ Zahl
character "Hello World!" Zeichenkette

  • Datentypen werden nicht explizit angegeben (anders als in Java)
  • Voreinstellung für Zahlen ist double

Vordefinierte Konstanten

Konstante Bedeutung
Inf und -Inf Unendlich und minus Unendlich
NaN Rechenoperation ergibt keine reelle Zahl, z.B. \(\sqrt{-1}\)
NULL Ein leeres Objekt
NA Unbekannter Datenwert (Not Available)

Mathematische Funktion

Funktionen Beschreibung
sin(x), cos(x), tan(x), … Trigonometrische Funktionen
abs(x), sqrt(x) Absolutwert, Wurzel
log(x), exp(x) Natürlicher Logarithmus und Exponentialfunktion
log2(x), log10(x) Logarithmus mit anderen Basen

Beispiele

exp(1)
[1] 2.718282
log2(4096)
[1] 12

Funktionen zur Typumwandlung

Funktion Bedeutung
as.numeric(x) Konvertiert in eine Zahl
as.character(x) Konvertiert in eine Zeichenkette
as.logical(x) In Wahrheitswert konvertieren
  • Funktion as.logical
    • Zahlenwert 0 entspricht FALSE,
    • Andere Zahlenwerte entsprechen TRUE

Beispiele

3 * as.numeric("1.81")
[1] 5.43
as.character(pi)
[1] "3.14159265358979"
as.logical(0)
[1] FALSE
as.logical(0.1)
[1] TRUE

Vergleichsoperatoren und Verknüpfungen

Operator Bedeutung
a < b, a <= b Kleiner und kleiner gleich
a > b, a >= b Größer und größer gleich
a == b, a != b Exakt gleich und nicht gleich
near(a, b) Fast gleich
is.na(x) Test of x gleich NA

Verknüpfung Bedeutung
a & b Logisches und
a | b Logisches oder
!a Negation

Beispiele

NA == 10
[1] NA
NA == NA
[1] NA
is.na(NA)
[1] TRUE
is.na(10)
[1] FALSE
2 * 10 == 20
[1] TRUE
pi < 3.14
[1] FALSE
as.character(3 * 9 + 1) == 28
[1] TRUE
TRUE | FALSE
[1] TRUE
TRUE & FALSE
[1] FALSE
!(TRUE & FALSE)
[1] TRUE

Rechengenauigkeit

sqrt(2) ^ 2 == 2
[1] FALSE
1 / 49 * 49 == 1
[1] FALSE

→ Rundungsfehler, Zahlen mit rund 15 Nachkommastellen

near(sqrt(2)^2, 2)
[1] TRUE
near(1 / 49 * 49, 1)
[1] TRUE

→ Vergleichen mit near()

Weitere nützliche Funktionen 1/2

Funktion Beschreibung
paste0(...) Verbindet mehrere Werte zu Character
paste(..., sep = " ") Wie paste0 aber mit Trennzeichen
signif(x, digits = 6) Rundet auf Anzahl von signifikanten Stellen
round(x, digits = 0) Runden auf Anzahl von Stellen

Weitere nützliche Funktionen 2/2

paste(1, 2, 3, 4, 5, 6)
[1] "1 2 3 4 5 6"
paste(1, 2, 3, 4, 5, 6, sep = ", ")
[1] "1, 2, 3, 4, 5, 6"
paste0(1, 2, 3, 4, 5, 6)
[1] "123456"
signif(9283649, 4)
[1] 9284000
paste0("pi = ", round(pi, digits = 4))
[1] "pi = 3.1416"

Optionale Parameter von Funktionen

round(x, digits = 0)

Funktion round besitzt Parameter x (die Zahl die gerundet werden soll) und einen optionalen Parameter digits (Anzahl der Stellen). Wird digits nicht angegeben, dann verwendet R den Wert 0. Beim Funktionsaufruf kann man den Namen des Parameters weglassen (kürzer) oder angeben (meist besser zu verstehen).

round(pi)
[1] 3
round(pi, 1)
[1] 3.1
round(pi, digits = 2)
[1] 3.14

Funktionen mit vielen Parametern

`paste(..., sep = " ")

Der Funktion paste können beliebig viele Parameter übergeben werden. Der Name des optionalen Parameters muss angegeben werden.

paste(1, 2, 3)
[1] "1 2 3"
paste(1, 2, 3, 4, 5, 6, "$")
[1] "1 2 3 4 5 6 $"
paste(1, 2, 3, 4, 5, 6, sep = "$")
[1] "1$2$3$4$5$6"

Hilfe zu R-Funktionen

  • In RStudio in den Funktionsnamen klicken und Taste F1 drücken
    • Hilfetexte in der Regel nicht ganz einfach zu lesen
    • Oft werden verwandte Funktionen gemeinsam erklärt
    • Das fällt Ihnen mit der Zeit leichter

Suchen im Internet

  • Auf Google mit Suchanfragen der Form “r Suchphrase”
  • Problem: Häufig zu viele Antworten oder die falsche Information
  • Erst denken, dann googeln, dann nochmal denken
  • Nichts aus dem Internet abtippen, das Sie nicht verstehen
  • Meistens ist .org besser als .com

9.2 Datenstrukturen

Datenstrukturen in R

Datenstruktur Beschreibung
Vektor Reihe von Elementen mit gleichem Datentyp
Matrix Wie Vektor aber mit Zeilen und Spalten
Array Wie Matrix aber beliebig viele Indizes
List Wie Vektor aber verschiedene Datentypen
Dataframe Liste, jedes Element ein Vektor, Spalten haben Namen

→ Dataframe = Datensatz einer Erhebung

Vektoren

Für uns wichtig

  • Vektoren als Eingabewerte (zum Beispiel beim Plotten)
  • Rechenoperationen für Vektoren (Mittelwert etc.)

→ Hier nur die Dinge, die wir auch benötigen

Erzeugen von Vektoren 1/2

Funktion Beschreibung
a:b Erzeugt einen Vektor von a bis b mit Inkrement 1
c(x1, x2, x3) Erzeugt einen Vektor mit den Werten x1, x2, x3
seq(a, b, by = inc) Erzeugt einen Vektor von a bis b mit Inkrement inc
seq(a, b, length.out = n) Erzeugt einen Vektor von a bis b mit n Elementen
rep(x, times = n) Hängt das Array oder die Zahl x n-mal hintereinander
rep(x, each = n) Wiederholt jedes Element in x n-mal

  • a:b wie in Matlab (aber kein 1:0.1:2)
  • c steht für combine
  • Inkrement = Zunahme
  • seq wie Sequenz
  • rep wie repetition = Wiederholung

Erzeugen von Vektoren 2/2

1:6                     # Zahlen 1 bis 6
[1] 1 2 3 4 5 6
1:-6                    # Rückwärts
[1]  1  0 -1 -2 -3 -4 -5 -6
"1999":"2005"           # Mit Strings
[1] 1999 2000 2001 2002 2003 2004 2005
c(1:3, 4:9)             # Vektoren
[1] 1 2 3 4 5 6 7 8 9
c("A", "B", "C", 1:3)   # Typkonvertierung
[1] "A" "B" "C" "1" "2" "3"
seq(1, 5, by = 0.7)     # Ohne zweiten Wert
[1] 1.0 1.7 2.4 3.1 3.8 4.5
seq(1, 5, length.out=6) # Inkrement
[1] 1.0 1.8 2.6 3.4 4.2 5.0
rep(c(4, 2), times = 3) # Vektor mehrfach
[1] 4 2 4 2 4 2
rep(c(4, 2), each = 3)  # Elemente mehrfach
[1] 4 4 4 2 2 2
rep(c(4, 2), each = 4)  # Elemente mehrfach
[1] 4 4 4 4 2 2 2 2

Operatoren & Funktionen für Vektoren

x <- 1:5
y <- 5:1
x + y
[1] 6 6 6 6 6
1 + x
[1] 2 3 4 5 6
x * y
[1] 5 8 9 8 5
sqrt(x)
[1] 1.000000 1.414214 1.732051 2.000000 2.236068

→ Ausführung Elementweise

Kuriositätenkabinett

a <- 0:8
b <- c(1, 11)
c <- 99

Damit

a + b
[1]  1 12  3 14  5 16  7 18  9
a %% 2 == 0
[1]  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE FALSE  TRUE
a[a %% 3 == 0]
[1] 0 3 6
c[1]
[1] 99

Funktionen für Vektoren 1/2

Funktion Bedeutung
c(a, b, ...) Vektor erzeugen (geht auch mit Vektoren)
length(a) Länge eines Vektors
sum(a), prod(a) Summe oder Produkt der Elemente
rev(a) Reihenfolge umdrehen
unique(a) Unterschiedliche Elemente
a %in% b Ist Wert a in Vektor b enthalten?

Funktionen für Vektoren 2/2

a <- rep(1:3, 2)
a
[1] 1 2 3 1 2 3
c(a, c(5, 19))
[1]  1  2  3  1  2  3  5 19
length(a)
[1] 6
sum(a)
[1] 12
rev(a)
[1] 3 2 1 3 2 1
unique(a)
[1] 1 2 3
1 %in% a
[1] TRUE
9 %in% a
[1] FALSE

Statistische Funktionen für Vektoren

Funktion Beschreibung
min(x), max(x) Kleinster und größter Wert
mean(x) Mittelwert
var(x) Varianz
sd(x) Standardabweichung
cor(x, y) Korrelationskoeffizient
quantile(x, probs = c(q1, q2, ...) Quantilwerte
summary(x) Gibt Fünf-Punkte-Zusammenfassung aus

Zum Beispiel

summary((0:100)^2)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      0     625    2500    3350    5625   10000 

Korrelationskoeffizient

Zu Fuß

x <- 1:10
y <- x + 0.5 * x^2
n <- length(x)
xmid <- 1 / n * sum(x)
ymid <- 1 / n * sum(y)
sum((x - xmid) * (y - ymid)) / sqrt(sum((x - xmid)^2) * sum((y - ymid)^2))
[1] 0.9815865

Mit R-Funktion

cor(x, y)
[1] 0.9815865

Benannte Vektoren

stundenlohn <- c("Kellner:in" = 8.5, "Ingenieur:in" = 50)
stundenlohn
  Kellner:in Ingenieur:in 
         8.5         50.0 
stundenlohn[1]
Kellner:in 
       8.5 
stundenlohn["Kellner:in"]
Kellner:in 
       8.5 
mean(stundenlohn)
[1] 29.25

→ Viele Anwendungen, zum Beispiel bei Farbskala

Dataframes

Dataframe erzeugen mit tibble()

d <- tibble(
  X = 0:4,
  Y = c(1.2, 3.2, 0.5, 0.9, 1.1),
  Z = c("A", "B", "C", "D", "E")
)
  • Merkmale und Werte in der Form Name = Vektor
  • Wir lesen Dataframes in der Regel aus Dateien (Excel, CSV, etc.)
  • tibble() aus tidyverse von Hadley Wickham

Dataframe ausgeben

d
show(d)
# A tibble: 5 × 3
      X     Y Z    
  <int> <dbl> <chr>
1     0   1.2 A    
2     1   3.2 B    
3     2   0.5 C    
4     3   0.9 D    
5     4   1.1 E    
str(d)
tibble [5 × 3] (S3: tbl_df/tbl/data.frame)
 $ X: int [1:5] 0 1 2 3 4
 $ Y: num [1:5] 1.2 3.2 0.5 0.9 1.1
 $ Z: chr [1:5] "A" "B" "C" "D" ...

Erste Ausgabe mit Bibliothek gt (Am Anfang konfiguriert)

Auf Spalten zugreifen

d$X
[1] 0 1 2 3 4
d$Z
[1] "A" "B" "C" "D" "E"
d$Z[4]
[1] "D"

  • d$X liefert die Werte zum Merkmal X als Vektor
  • Auf einzelne Werte kann dann mit [idx] zugegriffen werden
  • idx wie Index
  • Indizierung beginnt bei 1

Beispiel: Regressionsgerade/Bestimmtheitsmaß

xmid <- mean(d$X)
ymid <- mean(d$Y)
beta <- sum((d$X - xmid) * (d$Y - ymid)) / sum((d$X - xmid)^2)
alpha <- ymid - beta * xmid
R2 <- sum((alpha + beta * d$X - ymid)^2) / sum((d$Y - ymid)^2)
paste0("alpha = ", alpha, ", beta = ", beta, ", R2 = ", signif(R2, 5))
[1] "alpha = 1.88, beta = -0.25, R2 = 0.14115"

Hinweis: Geht auch kürzer

m <- lm(Y ~ X, data = d)
summary(m)

Call:
lm(formula = Y ~ X, data = d)

Residuals:
    1     2     3     4     5 
-0.68  1.57 -0.88 -0.23  0.22 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)
(Intercept)   1.8800     0.8721   2.156    0.120
X            -0.2500     0.3560  -0.702    0.533

Residual standard error: 1.126 on 3 degrees of freedom
Multiple R-squared:  0.1411,    Adjusted R-squared:  -0.1451 
F-statistic: 0.493 on 1 and 3 DF,  p-value: 0.5332

9.3 Datum und Uhrzeit

Komplizierter als man auf den ersten Blick vielleicht denkt

  • Wie addieren Sie einen Tag zu einer Woche?
  • Hat jedes Jahr 365 Tage?
  • Hat jeder Tag 24 Stunden?
  • An welchem Wochentag sind Sie geboren?

Einfach(er) mit dem lubridate-Paket (in tidyverse enthalten)

Date-Time, Date und Time

Datum und Uhrzeit
now()          # Date-Time (Zeitstempel)
[1] "2026-03-27 03:05:56 UTC"
today()        # Date      (Datum)
[1] "2026-03-27"
as_hms(now())  # Time      (Zeit)
03:05:56.418255

Date-time mit ymd_hms und Varianten

ymd_hms("2016-11-30 10:30:10", tz = "Europe/Berlin")
[1] "2016-11-30 10:30:10 CET"
dmy_hm("30 8 2012 10:30", tz = "Europe/Berlin")
[1] "2012-08-30 10:30:00 CEST"
mdy_h("8/30/2012:10")
[1] "2012-08-30 10:00:00 UTC"

  • Datum und Uhrzeit aus Zeichenkette einlesen, Trennzeichen fast beliebig
  • ymd_..., dmy_..., mdy... je nachdem ob Jahr, Tag oder Monat zuerst
  • ..._hms, ..._hm, ..._h je nach Zeitangabe
  • Zeitzone mit angeben falls nicht UTC (Coordinated Universal Time)
  • CET Central European Time, CEST Central European Summer Time

Date mit ymd und Varianten

ymd("2016-11-30")
[1] "2016-11-30"
dmy("30 8 2012")
[1] "2012-08-30"
mdy("8/1/1998")
[1] "1998-08-01"

  • Datum aus Zeichenkette einlesen, Trennzeichen fast beliebig
  • ymd, dmy, mdy je nachdem ob Jahr, Tag oder Monat zuerst
  • Tipp beim Ausprobieren: Tag > 12 verwenden um Fehler zu finden
  • In Deutschland meistens Tag/Monat/Jahr
  • Ausgabe in der Schreibweise JJJJ-MM-TT

Time mit as_hms() und hms::hms()

as_hms(48630)                                    # Sekunden seit Mitternacht
13:30:30
as_hms("13:30:30")                               # Aus Zeichenkette
13:30:30
as_hms(dmy_hms("1:6:1987 13:30:30"))             # Aus Date-Time
13:30:30
hms::hms(hours = 13, minutes = 30, seconds = 30) # Mit Zahlenwerten
13:30:30

  • Mit as_hms() Zeit bestimmen, die seit 0 Uhr verstrichen ist
  • Falls Zahlenwerte vorliegen: Funktion hms::hms()

Funktionen make_date() und make_datetime()

make_date(year = 2000, month = 10, day = 10)
[1] "2000-10-10"
make_datetime(year = 2000, month = 10, day = 10, hour = 10)
[1] "2000-10-10 10:00:00 UTC"
make_datetime(year = 2000, month = 10, day = 10, hour = 10, tz = "Europe/Berlin")
[1] "2000-10-10 10:00:00 CEST"

Datumskomponenten: Jahr und Monat

d <- dmy_hms("15.04.2025 12:22:01")
year(d)
[1] 2025
month(d)
[1] 4
month(now())
[1] 3
month(d, label = TRUE)
[1] Apr
12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < ... < Dec
month(d, label = TRUE, abbr = FALSE)
[1] April
12 Levels: January < February < March < April < May < June < ... < December
  • Namen year und month selbsterklärend
  • Monatsname mit label = TRUE
  • Langer Name mit abbr = FALSE
  • Levels: Richtige Sortierung, nicht alphabetisch

Datumskomponenten: Tag

d <- dmy_hms("15.04.2025 12:22:01")
day(d)
[1] 15
yday(d)
[1] 105
wday(d)
[1] 3
wday(d, label = TRUE)
[1] Tue
Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat
wday(d, label = TRUE, abbr = FALSE)
[1] Tuesday
7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday
  • day = Wievielter Tag im Monat
  • yday = Wievielter Tag im Jahr
  • wday = Wievielter Tag in der Woche (Sonntag = 1)
  • Namen des Tages mit label = TRUE, lange Form mit abbr = FALSE

Zeitdifferenzen 1/2

Alter von Friedrich Merz in Tagen am Tag 2026-03-27

today() - dmy("11.11.1955")
Time difference of 25704 days

Wie lange braucht die Berechnung einer Wurzel?

d1 <- hms::as.hms(now())
x <- sqrt(93482756)
d2 <- hms::as.hms(now())
d2 - d1
Time difference of 0.001434803 secs

Zeitdifferenzen 2/2

Ende März um halb drei

d <- dmy_hm("30.3.2019 14:30", tz = "Europe/Berlin")

23 Stunden später

d + dhours(23)
[1] "2019-03-31 14:30:00 CEST"
  • dhours(): Zeitdauer in physikalischen Stunden

Auch 23 Stunden später

d + hours(23)
[1] "2019-03-31 13:30:00 CEST"
  • hours(): Zeitdauer in Stunden auf der Uhr

\(\rightarrow\) Vergleichen Sie die Zeiten!

9.4 ‘Normal’ rechnen mit Datum/Zeit

In Zahl konvertieren mit as.numeric()

as.numeric(ymd_hms("1970-1-1 0:0:11", tz = "UTC"))
[1] 11
as.numeric(ymd("1970-1-12"))
[1] 11
as.numeric(as_hms(ymd_hms("1988-11-11 0:0:11", tz = "Europe/Berlin")))
[1] 11

  • Date-time: Sekunden seit Beginn des Jahres 1970 (in UTC)
  • Date: Tage seit Beginn des Jahres 1970
  • Time: Sekunden seit Beginn des Tages
  • Konvention: 01.01.1970 00:00 Uhr ist “absoluter Nullpunkt”

‘Normal’ rechnen mit Zeitdifferenzen

d1 <- as_hms(now())
d2 <- as_hms(now())
d2 - d1
Time difference of 0.0009763241 secs
  • Ergebnis vom Typ ‘Time Difference’ und keine Zahl
1000 * as.numeric(d2 - d1)
[1] 0.9763241
  • Mit as.numeric() in Zahl konvertieren
  • Faktor 1000: Ausgabe in Millisekunden

Datum runden

d <- dmy_hm("30.3.2019 14:32", tz = "Europe/Berlin")

floor_date(d, unit = "hour")
[1] "2019-03-30 14:00:00 CET"
ceiling_date(d, unit = "5 minutes")
[1] "2019-03-30 14:35:00 CET"

  • Abrunden mit floor_date()
  • Runden mit round_date()
  • Aufrunden mit ceil_date()
  • Einheit, zu der gerundet werden soll, mit unit = XXX angeben
  • Man kann auch zu einem Vielfachen einer Einheit runden

Formatierte Ausgabe mit sprintf()

Mit sprintf können Ausgaben ein bisschen schöner gestaltet werden. Dabei steht %i für eine ganze Zahl und %5.3f eine Fließkommazahl insgesamt fünf Zeichen breit mit 3 Nachkommastellen.

x <- 1 / 3

sprintf("%i Hallo! x = %5.3f", 45, x)
[1] "45 Hallo! x = 0.333"

Den Wert von Variablen kann man auch in den Text einbauen. Hier ein Beispiel

\[1 / 3 \approx 0.3333333\]

mit einer Variablen in einer Formel.

Das waren die Basics von R

Auswahl der Themen

  • Sehr stark eingeschränkt
  • Nur das absolut Notwendige (subjektive Auswahl)

Nicht behandelt

  • Kontrollstrukturen: Schleifen und Verzweigungen
    • Für unsere Zwecke nicht notwendig
    • Es gibt elegantere Alternativen
  • Eigene Funktionen erstellen
    • Wir schaffen das (erst einmal ohne)