5  R Grundlagen

5.1 R als Taschenrechner

5.1.1 Zuweisungen

Wir können einer Variablen mithilfe des Zuweisungspfeils <- ein R-Objekt zuweisen. Im einfachsten Fall ist das ein einzelner Wert, später werden das auch Vektoren, Datentabellen, Listen, Funktionen, etc. sein.

x <- 2.5  # ohne Ausgabe des Werts
(y <-12)  # mit Ausgabe des Werts
[1] 12

Im obigen Beispiel wird x die Zahl 2.5 zugewiesen und yder Wert 12. Dabei sei angemerkt, dass der Punkt . in R der Dezimaltrenner ist! Durch die runden Klammen um den gesamten Ausdruck wird das zugewiesene Objekt auch ausgegeben, ohne die Klammern wird das Objekt nicht ausgegeben.

(z <- x + y)
[1] 14.5

Im letzten Beispiel werden aus den zuvor definierten Objekten x und y das Objekt z gebildet. Die Zuweisung <- bindet nur schwach, so dass die jeweils rechten Seiten der Ausdrücke zuerst ausgewertet werden (im obigen Beispiel die Addition von x und y) bevor die Zuweisung erfolgt.

Abbildung 5.1: Im Reiter Environment (oben rechts im RStudio) sieht man welche Objekte in den jeweiligen Umgebungen existieren.

5.1.2 Regeln für Objektnamen

Bei der Benennung von Objekten müssen ein paar Regeln beachtet werden, da Objekte in R nicht ohne weiteres beliebige Namen erhalten können. Man spricht von R-konformen Objektnamen wenn diese die folgenden Regeln erfüllen: Objektnamen dürfen

  • Groß- und Kleinbuchstaben, Punkte (.), Unterstriche (_) und Zahlen enthalten,
  • nicht mit einer Zahl oder dem Unterstrich _ beginnen.

Bemerkungen:

  • Objekte, die mit einem Punkt . beginnen, sind versteckt, das heißt sie sind nicht im Environment und nur mit ls(all.names = TRUE)zu sehen.

  • Objektnamen sind case-sensitive, das heißt Groß- und Kleinschreibung wird von R unterschieden.

Drei <- 3
drei
Error: Objekt 'drei' nicht gefunden
Tipp für Namen:
  • Gängige Namensgebung für R-Objekte sind:
klein_unterstrich     <- 1   # gut
klein.punkte          <- 2   # in R base, eher schlecht
KapitalisiertOhne     <- 3   # schlecht
  • Man sollte versuchen, kurze, aussagekräftige Namen zu vergeben.
kurzer_name                   <- 1      # gut
langer_und_komplizierter_name <- 2      # schlecht
  • Keine Funktionen oder Variablennamen überschreiben
T    <- 1    # nein! T steht für TRUE
c    <- 2    # nein! c ist die Funktion c()
mean <- 3    # nochmal nein! Auch mean() ist eine Funktion.

Bemerkungen:

  • Welche der eigenen Objekte R kennt kann man sich unter Environment im RStudio ansehen oder alternativ mit der Funktion ls().

  • Mit dem Besen (RStudio, Environment) können alle Objekte gelöscht werden; mit der Funktion rm() (Eingabe in die Konsole) können auch einzelne Objekte gelöscht werden.

Damit kann die Konsole von R wie ein überdimensionierter Taschenrechner genutzt werden. Es ist darauf zu achten, dass der Punkt (.) der Dezimaltrenner ist und nicht das Komma (,). Durch das Komma werden zum Beispiel Argumente in einer Funktion voneinander getrennt (siehe Beispiel unten).

5.1.3 Operatorrangfolge

Schon in der 5. Klasse lernt man in der Arithmetik, die Regel Punkt- vor Strichrechnung. Dies bedeutet, dass der Ausdruck a + b \cdot c das gleiche ist wie a + (b \cdot c). Durch die Regel wird also eine implizite Klammerung festgelegt. Dies nennt man die Operatorrangfolge (oder auch die Präzedenz). Legt man nun noch fest ob die Terme gleicher Bindungsstärke von links nach rechts oder von rechts nach links ausgewertet werden, können beliebige arithmetische Terme auf eindeutige Weise ausgewertet werden. Letzteres nennt man die Assoziativität der Operatoren.

Beispiele:

2+3*4     # Plus, Mal (Punkt vor Strich)
[1] 14
10/5/2    # Dividieren (von links nach rechts ausgewertet)
[1] 1
2^3^2     # Exponenzieren (von rechts nach links ausgewertet)
[1] 512
(2^3)^2   # runde Klammern zum explizieten Gruppieren bei Rechnungen
[1] 64
2.5*4     # der Punkt (.) ist der Dezimaltrenner
[1] 10

Beim Programmieren kommen wir nicht mit der einfachen Regel Klammern vor Exponenten vor Punkt- vor Strichrechnung (wie die Regel dann am Ende der Schullaufbahn heißt) aus, da es noch mehr wichtige Operatoren gibt.

In der folgenden Liste sind (fast) alle Operatoren aufgeführt. Bei manchen ist im Moment vielleicht noch nicht klar warum man diese benötigt, aber im Laufe des Kurses werden wir die meisten der Operatoren benötigen.

Für die Tabelle gilt:

  • Die Bindungsstärke der Operatoren nimmt von oben nach unten ab, das bedeutet, das weiter oben stehende Operationen zuerst ausgeführt werden.
  • Die Assoziativität gibt an, ob gleiche bzw. gleichwertige Operatoren von links nach rechts oder von rechts nach links abgearbeitet werden (sofern das sinnvoll ist).
Tabelle 5.1: Die Tabelle zeigt die Bindungsstärken (Präzedenz) der Operatoren. Diese nehmen von oben nach unten ab. Die dazu gehörige Hilfefunktion erhält man mit ?Syntax.
Operator Bedeutung Assoziativität
:: / ::: Zugriff auf Funktionen in Namespace
$ / @ Komponenten extrahieren
[ / [[ Indizieren
^ / ** Exponenzieren: a^b / a**b ist a^b rechts nach links
+x / -x Vorzeichen (unärer Operator) links nach rechts
: :-Operator (binär, Erzeugung von numerischen Vektoren)
%% / %/%/ … / |> Modulo / Ganzzahlige Division / sonstige “%”-Operatoren / Pipe links nach rechts
* / / Multiplikation, Division links nach rechts
+ / - Addition, Subtraktion (binärer Operator) links nach rechts
== / != / > / >= / < / <= Vergleiche links nach rechts
! Logisches NICHT links nach rechts
& Logisches UND links nach rechts
| Logisches ODER links nach rechts
-> Zuweisung rechts links nach rechts
<- Zuweisung links rechts nach links
= Zuweisung links rechts nach links
? Hilfe (unärer und binärer Operator)

Beispiele:

  • Die Potenzrechnung wird von rechts nach links abgearbeitet und bindet stärker als das Vorzeichen:
-2^2^3  
[1] -256

Durch das Setzen von runden Klammern kann eine andere Reihenfolge, komplett analog zur Mathematik, erzwungen werden:

((-2)^2)^3
[1] 64

Wenn man die Operatorrangfolge oder die Assoziativität nicht (gut) kennt, so ist es ratsam Klammern zu setzen um Fehler zu vermeiden.

  • Das Vorzeichen bindet stärker als die Multiplikation, daher ist der folgende Ausdruck in R sinnvoll. Allerdings würde ich Klammern um die -2 zu setzen, um einerseits die Lesbarkeit zu verbessern und andererseits Fehler zu reduzieren.
3*-2
[1] -6
  • Wie wir pben bereits gesehen haben sind Multiplikation * und Division / linksassoziativ und haben die gleiche Bindungsstärke. Der Ausdruck
10/5*2/4
[1] 1

wird also schrittweise von links nach rechts ausgeführt, entspricht damit dem Ausdruck

((10/5)*2)/4
[1] 1
  • Alle Rechnungen werden zuerst ausgeführt bevor die Zuweisung erfolgt, da diese sehr schwach bindet:
x <- 3*(2+1)
x
[1] 9
  • Da die Zuweisungen <- und = rechtsassoziativ sind, also von rechts nach links abgearbeitet werden, können mehrere Zuweisungen gleichzeitig gemacht werden. Im unteren Beispiel wird dem x die 5 zugeordnet und dann dem y der Wert, den das x hat:
y <- x <- 5
y
[1] 5

und analog kann man mit -> mehrere Zuweisungen nach rechts machen.

6 -> y -> z
z
[1] 6
  • Bei der Benutzung des Pipe-Operators, der in Kapitel 5.5, noch erklärt wird, muss man ein wenig vorsichtig sein, wenn arithmetische Operationen involviert sind. Auch hier sollte man immer Klammern setzen um Fehler zu vermeiden.
3*16 |> sqrt() # ist das gleiche wie 3*sqrt(16), aber
[1] 12
16^2 |> sqrt() # ist das gleiche wie sqrt(16^2)
[1] 16
  • Möche man Funktionen aus nicht-geladenen (aber installierten) Paketen nutzen, oder haben Funktionen in verschiedenen Paketen den gleichen Namen, so nutzt man den :: bzw den ::: Operator. Beispielweise sind durch das Laden von Tidyverse die Funktion filter() bzw. lag() aus dem Paket stats nicht mehr direkt zugängig. Möchte man diese verwenden, so muss man stats::lag() aufrufen. Die Operatoren :: bzw. ::: (der Unterschied ist derzeit nicht wichtig!) binden stärker als alle anderen Operatoren.
Abbildung 5.2: Nach dem Laden von Tidyverse sind die Funktionen lag() und filter() aus dem stats-Paket maskiert, das heißt, wenn man die Funktion filter() aufruft wird nun die Funktion aus dem Tidyverse genutzt. Möchte man die Funktion lag()oderfilter()aus dem Paket stats nutzen, so muss man den Namespace angeben:stats::lag()oderstats::filter()`.

Das Konzept des Namespacing ist für diesen Kurs nicht weiter relevant und soll auch nicht weiter vertieft werden.

Selbsttest: Operatorrangfolge

Markieren sie die wahren Aussagen!

  • Falsch. Potenzieren ist rechts-assoziativ, daher ist 2^3^2 = 2^(3^2).
  • Wahr.
  • Falsch. %/% bindet stärker als /
  • Falsch. Da Potenzieren stärker bindet als der :-Operator, werden alle ganzen Zahlen von 1 bis 100 ausgegeben.
  • Wahr. ! ist das logische NICHT, das nur ein Argument hat. Der Operator wird von links nach rechts ausgewertet.
  • Wahr. Was rechts neben dem = oder dem <-steht, wird einem Objektnamen links des Operators zugewiesen.

Markieren sie die wahren Aussagen!

  • Wahr. Die beiden Ausdrücke bedeuten das Gleiche.
  • Wahr. ! ist das logische NICHT, das nur ein Argument hat. Der Operator wird von links nach rechts ausgewertet.
  • Wahr.
  • Wahr. Punktrechnung vor Strichrechnung.
  • Falsch. Potenzieren bindet stärker als das Vorzeichen -, daher ist das Ergebnis -25.
  • Wahr. Es gibt für das Potenzieren zwei verschiedene Operatoren.

Markieren sie die wahren Aussagen!

  • Wahr. Es gibt für das Potenzieren zwei verschiedene Operatoren.
  • Falsch.
  • Wahr.
  • Wahr. Durch die Klammern wird diese zuerst ausgeführt. Daher wird der Vektor 1 bis 5 in Schritten von 1 erzeugt.
  • Wahr. Die Negation NICHT ! bindet stärker als das ODER !, daher ist der Ausdruck TRUE - Im Gegensatz zu !(TRUE | TRUE).
  • Falsch. Wie in der Mathematik üblich wird, von rechts nach links ausgeführt.

Markieren sie die wahren Aussagen!

  • Wahr. Die beiden Ausdrücke bedeuten das Gleiche.
  • Wahr.
  • Wahr. Was rechts neben dem = oder dem <-steht, wird einem Objektnamen links des Operators zugewiesen.
  • Falsch. Das Vorzeichen bindet stärker als die Multiplikation und man darf sogar beide Klammer weglassen und schreiben -2*-2.
  • Falsch. Ausdrücke wie -10:-1 sind sinnvoll definiert.
  • Falsch. Potenzieren ist rechts-assoziativ, daher ist 2^3^2 = 2^(3^2).

Markieren sie die wahren Aussagen!

  • Wahr. Das stimmt. Außerdem sind sie links-assoziativ!
  • Falsch. Potenzieren ist rechts-assoziativ, daher ist 2^3^2 = 2^(3^2).
  • Falsch. Ausdrücke wie -10:-1 sind sinnvoll definiert.
  • Falsch. Da Potenzieren stärker bindet als der :-Operator, werden alle ganzen Zahlen von 1 bis 100 ausgegeben.
  • Falsch. Potenzieren bindet stärker als das Vorzeichen -, daher ist das Ergebnis -25.
  • Falsch. Wie in der Mathematik üblich wird, von rechts nach links ausgeführt.

Markieren sie die wahren Aussagen!

  • Falsch.
  • Falsch. Ausdrücke wie -10:-1 sind sinnvoll definiert.
  • Falsch. Der Pipe-Operator bindet zwar stärker als die Multiplikation, nicht aber als das Potenzieren!
  • Falsch. %/% bindet stärker als /
  • Wahr. ! ist das logische NICHT, das nur ein Argument hat. Der Operator wird von links nach rechts ausgewertet.
  • Wahr. Multiplikation, Division, Addition und Subtraktion sind alle links-assoziativ.

Markieren sie die wahren Aussagen!

  • Wahr. Der Pipe-Operator %>% bzw. auch die native Pipe |> binden genau so stark wie alle %-Operatoren.
  • Wahr.
  • Falsch. Der Operator <- bindet stärker als =. Das heißt während in die Zuweisungen a = b <- 2 beiden Objekten die 2 zugeordnet ist, liefert a <- b = 2 einen Fehler.
  • Wahr. Die Negation NICHT ! bindet stärker als das ODER !, daher ist der Ausdruck TRUE - Im Gegensatz zu !(TRUE | TRUE).
  • Wahr. Was rechts neben dem = oder dem <-steht, wird einem Objektnamen links des Operators zugewiesen.
  • Falsch. %/% bindet stärker als /

Markieren sie die wahren Aussagen!

  • Falsch. Da Potenzieren stärker bindet als der :-Operator, werden alle ganzen Zahlen von 1 bis 100 ausgegeben.
  • Falsch. %/% bindet stärker als /
  • Wahr. Punktrechnung vor Strichrechnung.
  • Falsch. Potenzieren ist rechts-assoziativ, daher ist 2^3^2 = 2^(3^2).
  • Wahr. Was rechts neben dem = oder dem <-steht, wird einem Objektnamen links des Operators zugewiesen.
  • Falsch. Der Operator <- bindet stärker als =. Das heißt während in die Zuweisungen a = b <- 2 beiden Objekten die 2 zugeordnet ist, liefert a <- b = 2 einen Fehler.

Markieren sie die wahren Aussagen!

  • Wahr. ! ist das logische NICHT, das nur ein Argument hat. Der Operator wird von links nach rechts ausgewertet.
  • Wahr. Punktrechnung vor Strichrechnung.
  • Wahr. Die Negation NICHT ! bindet stärker als das ODER !, daher ist der Ausdruck TRUE - Im Gegensatz zu !(TRUE | TRUE).
  • Falsch. Ausdrücke wie -10:-1 sind sinnvoll definiert.
  • Wahr. Multiplikation, Division, Addition und Subtraktion sind alle links-assoziativ.
  • Falsch. Potenzieren bindet stärker als Multiplikation und Division.

Markieren sie die wahren Aussagen!

  • Falsch. Punktrechnung vor Strichrechnung.
  • Falsch. Die Zuweisung geschieht am Ende. Der Operator <- bindet sehr schwach nur = und ? binden noch schwächer.
  • Wahr. ! ist das logische NICHT, das nur ein Argument hat. Der Operator wird von links nach rechts ausgewertet.
  • Wahr. Der Pipe-Operator %>% bzw. auch die native Pipe |> binden genau so stark wie alle %-Operatoren.
  • Falsch.
  • Wahr. Durch die Klammern wird diese zuerst ausgeführt. Daher wird der Vektor 1 bis 5 in Schritten von 1 erzeugt.

5.1.4 Funktionen

Die gewöhnlichen mathematischen Funktionen und auch sehr viele statistische Funktionen sind in R bereits definiert. Der Aufruf erfolgt durch den Namen der Funktion gefolgt von einem Paar runden Klammern in dem das Argument bzw. die Argumente stehen.

sqrt(16)          # Quadratwurzel von 16
[1] 4
exp(1)            # Exponentialfunktion an der 1 ausgewertet
[1] 2.718282
log(16)           # Logarithmus von 16 zur Basis e
[1] 2.772589
log(16, base = 2) # Logarithmus von 16 zur Basis 2
[1] 4
sin(pi/2)         # Sinus von π/2, wobei π die Kreiszahl 3.1415926... ist    
[1] 1

Bei allen Funktionen ist auf die korrekte Schreibweise zu achten, insbesondere macht Groß- und Kleinschreibung einen Unterschied: R ist case-sensitive. Wenn also eine Funktion falsch geschrieben ist, meldet R einen Fehler zurück.

Sqrt(16)          # liefert Fehler, da Funktion nicht existiert
Error in Sqrt(16): konnte Funktion "Sqrt" nicht finden
Tabelle 5.2: Einige mathematische Funktionen und deren Bedeutung. Bei choose() muss sowohl das n als auch das k angegeben werden und bei round() ist der Standard, dass auf ganze Zahlen gerundet wird.
Funktion Bedeutung
abs() / sign() Betragsfunktion / Algebraisches Vorzeichen
sqrt() Quadratwurzel
sin() / cos() / tan() Trigonometrische Funktionen
asin() / acos() / atan() / atan2() Arkusfunktionen (Umkehrfunktionen)
exp() Exponentialfunktion \textsf{e}^x
log() / log10() / log2() Logarithmus zur Basis \textsf{e} / 10 / 2
sinh() / cosh() / tanh() Hyperbolische Funktionen
asinh() / acosh() / atanh() Areafunktionen (Umkehrfunktionen)
factorial() Fakultät (eigentlich: \Gamma(x+1))
choose(n, k) Binomialkoeffizient: n über k : \binom{n}{k}
round(x, digits = 0) Rundet x auf 0 Stellen nach dem Komma
signif(x, digits = 6) Rundet x auf 6 signifikante Stellen
floor() / ceiling() Abrunden / Aufrunden
sum() / prod() Summe / Produkt der Elemente eines Vektors

Beispiele:

choose(49,6)         # 49 über 6 
[1] 13983816
round(pi, 4)         # π auf 4 Nachkommastellen gerundet
[1] 3.1416
round(12345, -3)     # 12345 auf Tausender gerundet
[1] 12000
signif(pi/10000, 3)  # die ersten 3 signif. Stellen von π/10000 
[1] 0.000314
sum(c(2,3,4))        # Summe der Zahlen 2, 3 und 4 (später mehr zu Vektoren)
[1] 9

5.1.5 Konstanten

R hat einige vordefinierte Konstanten (im weitesten Sinne), die man zum Rechnen nutzen kann, oder aber die bei Rechnungen als Ergebnis herauskommen können.

Konstante Bedeutung
pi Mathematische Konstante \pi
Inf / -Inf \infty / -\infty
NaN Keine Zahl (Not a Number)
NULL Leere Menge

Beispiele:

  • Man erhält NaN, wenn eine Rechnung zum Beispiel keine reelle Zahl als Lösung hat.
log(-1)
Warning in log(-1): NaNs wurden erzeugt
[1] NaN
# Bemerkung: mit komplexen Zahlen ginge es... 

log(-1+0i)
[1] 0+3.141593i
  • Anders als in der Mathematik ist Inf bzw. -Inf nicht notwendigerweise wirklich unendlich: auch sehr große Zahlen werden als unendlich behandelt:
log(0)   
[1] -Inf
factorial(170)   # letzte Fakultät, die noch als endliche Zahl dargestellt wird!
[1] 7.257416e+306
factorial(171)   
[1] Inf
Mögliche Fehler:
  • Das Komma wird als Dezimaltrenner genutzt.
  • Bei der Multiplikation wird der Operator * vergesssen.
  • Groß- und Kleinschreibung der Funktionen wird missachtet.
Aufgaben: Rechnen mit R

Bestimmen Sie als kleine Übung die folgenden Ausdrücke in der Konsole oder beantworten Sie die Fragen mit Hilfe von R.

  1. Runden Sie \frac{3}{41} auf 3 Nachkommastellen
  2. 3\cdot e
  3. \sqrt{2 + \frac{1}{\pi}}
  4. Bestimmen Sie \binom{12}{7}
  5. Erstellen Sie das Objekt x indem Sie ihm die Zahl (\ln(10) + 2)^{\frac{1}{4}} zuordnen.
  6. Was machen die Operatoren %/% bzw. %% (probieren Sie es mit ganze Zahlen aus!)
# 1.
round(3/41, digits = 3)
[1] 0.073
# 2.
3*exp(1)
[1] 8.154845
# 3. 
sqrt(2 + 1/pi)
[1] 1.5226
# 4.
choose(12,7)
[1] 792
# 5.
x <- (log(10)+ 2)^(1/4)
x
[1] 1.440232
# 6 
(1:12) %/% 2
 [1] 0 1 1 2 2 3 3 4 4 5 5 6
(1:12) %/% 3
 [1] 0 0 1 1 1 2 2 2 3 3 3 4
(1:12) %/% 5
 [1] 0 0 0 0 1 1 1 1 1 2 2 2
(1:12) %% 2
 [1] 1 0 1 0 1 0 1 0 1 0 1 0
(1:12) %% 3
 [1] 1 2 0 1 2 0 1 2 0 1 2 0
(1:12) %% 5
 [1] 1 2 3 4 0 1 2 3 4 0 1 2
  • Der Operator %/% ist die ganzzahlige Division, gibt eine ganze Zahl aus und zwar wie oft die Zahl rechts des Operators in die Zahl links des Operators (vollständig) passt.

  • Der Operator %% gibt den Rest an, der bei einer ganzzahligen Division übrig bleibt.

5.2 Aufruf von Funktionen

In R sind alle Funktionen auch Objekte. Der Aufruf der Funktionen ist dabei im wesentlichen immer der gleiche:

name_der_funktion(arg1 = wert1,  arg2 = wert2,  arg3 = wert3)

Hinter dem Namen der Funktion steht ein Paar Runde Klammern und in dieser werden die Argumente der Funktion aufgerufen. Dabei ist zu beachten, dass es Argumente gibt, die zwingend angegeben werden müssen und Argumente, die optional sind bzw. einen vordefinierten Wert annehmen, wenn man das Argument nicht angibt.

Beispiel: die Funktion log()

Schauen wir uns die Funktion log() einmal genauer an. Gibt man den Funktionsnamen ohne die runden Klammern ein, so wird nur der Quellcode ausgegeben.

log
function (x, base = exp(1))  .Primitive("log")

Wir sehen an diesem Beispiel, dass die Funktion log() zwei Argumente hat:

  • x ist das erste Argument und es ist ein notwendiges Argument, da ihm kein Wert zugeordnet ist.
  • base ist das zweite Argument, allerdings hat base den vordefinierten Wert exp(1) (also die Euler-Konstante \textsf{e})

Außerdem können wir am Ausdruck .Primitive() sehen, dass die Funktion nicht in R sondern in einer anderen, schnelleren Programmiersprache programmiert ist, was uns an der Stelle aber egal ist. Andere Funktionen können an der Stelle einen länglichen R-Code liefern.

Bemerkung: Notation Argumente

Analog zu den Funktionen, die in diesem Skript immer eine Klammer bekommen, werde ich Argumente immer mit dem Gleichheitszeichen direkt im Anschluss geschrieben. Das heißt im obigen Bespiel wird xzu x= und base zu base= Dadurch soll klarer werden, dass es sich bei den Ausdrücken um Argumente handelt. Manchmal werde ich auch die Standardwerte dazu schreiben, wenn das von Bedeutung ist.

log()               # liefert Fehler, da x nicht angegeben
Error in log(): Argument "x" fehlt (ohne Standardwert)
log(x=16)           # ok, hier: x = 16, base = exp(1)
[1] 2.772589
log(x=16, base=2)   # base ist optional, hier Basis 2
[1] 4
log(16, 2)          # ist das gleiche wie vorheriges Beispiel  
[1] 4

Die Reihenfolge in der Argumente angegeben werden (müssen) ist wichtig, wenn die Argumentnamen nicht angegeben werden! Das erste Argument, das angegeben wird, wird dem ersten Argument der Funktion übergeben. Im obigen Beispiel ist das die 16, die dem Argument x= übergeben wird. Das zweite Argument wird dem zweiten Argumentnamen übergeben und so weiter. Im obigen Beispiel ist klar, welche Bedeutung den jeweiligen Zahlen zukommen.

log(base=2, x=16) 
[1] 4

In der Praxis ist es allerdings so, dass man bei sehr vielen Funktionen nicht alle Argumente aufrufen muss oder möchte, da sie zum Beispiel richtig vordefiniert sind. Andere Argumente stehen ggf. hinten in der Argumentliste, und wir wollen nur diese ändern. In diesen Fällen ist es unumgänglich die Namen der Argumente anzugeben!

Ein Beispiel hierfür wäre die geometrische Funktion geom_point() aus Kapitel 3 die offenbar recht viele Argumente hat.

geom_point
function (mapping = NULL, data = NULL, stat = "identity", position = "identity", 
    ..., na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) 
{
    layer(data = data, mapping = mapping, stat = stat, geom = GeomPoint, 
        position = position, show.legend = show.legend, inherit.aes = inherit.aes, 
        params = list2(na.rm = na.rm, ...))
}
<bytecode: 0x55e41030bfa0>
<environment: namespace:ggplot2>

Allein um die Übersicht zu wahren und da meist nur wenige Argumente geändert werden, schreibt man die Argumentnamen in den Funktionsaufruf.

penguins |> ggplot(aes(x = flipper_length_mm, y = body_mass_g)) + 
            geom_point(shape = 2)

Bemerkungen:

  • Manche Funktionen haben auch gar keine Argumente (die Klammern sind trotzdem erforderlich).
  • Beim nicht korrekten Benutzen von Funktionen erhält man eine Fehlermeldung oder eine Warnung.
ln(16)      # ln keine Funktion
Error in ln(16): konnte Funktion "ln" nicht finden
Log(16)     # Gross- / Kleinschreibung wichtig
Error in Log(16): konnte Funktion "Log" nicht finden
log(-1)     # NaN - Not A Number
Warning in log(-1): NaNs wurden erzeugt
[1] NaN
Aufgaben: Rechnen mit R - Teil 2

Bestimmen Sie als kleine Übung die folgenden Ausdrücke in der Konsole oder beantworten Sie die Fragen mit Hilfe von R.

  1. Welcher Ausdruck ist größer \textsf{e}^{\pi} oder \pi^\textsf{e} ?
  2. Was macht die Funktion sign()?
# 1.
exp(pi)     # ist größer
[1] 23.14069
pi^exp(1)
[1] 22.45916
# 2.
sign(c(-1.2, -3, 0, 0.5, -3, 4, pi))
[1] -1 -1  0  1 -1  1  1

Die Funktion sign() gibt das Vorzeichen einer Zahl (vektorisiert) aus: DAs Ergebnis ist 1, wenn die Zahl positiv ist, -1, wenn die Zahl negativ ist und 0, wenn die Zahl 0 ist.

5.3 Die Hilfe Funktion

Die Funktion help() ist die wichtigste Funktion von allen! Man erhält mir ihr folgende Informationen zu den Funktionen oder Operatoren:

  • Beschreibung der Funktion,
  • die Syntax der Funktion,
  • Beispiele,
  • thematisch ähnliche Funktionen und
  • tiefere Einblicke.

Eine Beschreibung der Funktion kann sehr wichtig sein, da es nicht immer offensichtlich was eine Funktion wirklich macht, welche Ausgabe die Funktion hat und so weiter. Die Syntax ist für das Aufrufen der Funktion von großer Wichtigkeit, da die Namen und die Reihenfolge der Argumente nicht offensichtlich sind. Zudem ist meist auch nicht klar, welche Argumente (und damit welche Funktionalitäten) überhaupt zur Verfügung stehen. Insbesondere bei komplizierten Funktionen sind Beispiele sehr hilfreich um mit den Funktionen warm zu werden und sie richtig und geeignet anzuwenden.

Benutzung der Hilfe-Funktion (Konsole):

help("[")  
help("%*%") # bei Operatoren mit Anführungszeichen
help(plot)  # ohne Klammern (hier: hinter plot) 

oder die kurze Variante:

?"["
?"%*%"
?plot

Zu beachten ist an den oberen Beispielen, dass

  • Operatoren in Anführungszeichen geschrieben werden müssen und
  • die Funktion zu der Hilfe benötigt wird keine Klammer hat.
Tipp

Zu manchen tendenziell umfangreicheren Funktionen gibt es noch die die Funktionen example() oder demo(). Ein Beispiel ist die sehr umfangreiche Funktion plot - mit demo(plot) erhält man eine Reihe Grafen und deren Syntax.

5.4 Vektoren

Die wichtigste Struktur von R sind Vektoren. Eine einfache Variante um Vektoren zu erstellen ist die Funktion c(), was für concatenate (verknüpfen, aneinanderhängen), combine (verbinde, vereinen) oder coerce (zwingen) steht. Letzteres mag überraschen wird aber im Laufe des Kapitels noch klar werden. Alle Elemente eines Vektors haben immer den gleichen Datentyp, zum Beispiel Zeichen(ketten) (character), Zahlen (numeric) oder logische Ausdrücke (logical).

worte <- c("Schwimmen", "Radfahren", "Laufen")

zahlen <- c(3, 14, 15, 9, 2, 6)
zahlen
[1]  3 14 15  9  2  6
wahrheitswerte <- c(TRUE, FALSE, TRUE)

Da mit c() Vektoren verknüpft werden, können damit verschiedene Vektoren zusammengfügt werden, zum Beispiel

x <- c(1, 2, 3)
(x_neu <- c(x, 4, x))
[1] 1 2 3 4 1 2 3

ist x_neu ein numerischer Vektor, der sieben Elemente enthält.

5.4.1 Logische Vektoren

Logische Vektoren enthalten nur TRUE, FALSE oder NA und entstehen in den meisten Fällen durch Vergleiche.

Tipp: Schreibweise

Man kann TRUE und FALSE durch T und F abkürzen.

(alter <- c(17, 16, 21, 20, 19, 17, 19, NA, 24, 17))
 [1] 17 16 21 20 19 17 19 NA 24 17
(volljaehrig <- alter >= 18)
 [1] FALSE FALSE  TRUE  TRUE  TRUE FALSE  TRUE    NA  TRUE FALSE

Sie sind der einfachste Datentyp in R. Oft benötigt man die logischen Werte nicht direkt, sondern sie tauchen IN vERGLEICHEN implizit auf um Entscheidungen zu treffen. Beispiele dafür sind

  • Indizierung von Vektoren (siehe Kapitel 5.4.7),
  • die Funktion filter() in der ein Vergleich steht: ist dieser Vergleich FALSE, so wird die Zeile herausgefiltert, erscheint also nicht in der resultierenden Datentabelle.
# tidyverse muss geladen sein!
mpg |> filter(model == "corvette")
# A tibble: 5 × 11
  manufacturer model    displ  year   cyl trans    drv     cty   hwy fl    class
  <chr>        <chr>    <dbl> <int> <int> <chr>    <chr> <int> <int> <chr> <chr>
1 chevrolet    corvette   5.7  1999     8 manual(… r        16    26 p     2sea…
2 chevrolet    corvette   5.7  1999     8 auto(l4) r        15    23 p     2sea…
3 chevrolet    corvette   6.2  2008     8 manual(… r        16    26 p     2sea…
4 chevrolet    corvette   6.2  2008     8 auto(s6) r        15    25 p     2sea…
5 chevrolet    corvette   7    2008     8 manual(… r        15    24 p     2sea…

Das Konzept des Filtern mit filter() wird in Kapitel 9.3 genauer erklärt.

Aufgaben: Logische Vektoren

1.) Was liefern die Ausdrücke? Überlegen Sie sich die Antwort zuerst bevor Sie es ausprobieren!

c(1, 2, 3, 4, 5) == 2
c(2, 3, -4, 5, -1) >= 3

2.) Erklären Sie die folgenden Zeilen:

alter <- c(18, 15, 21, 25, 26, 16, 22, 23, 22, 17, 18, 21)
sum(alter < 20)
[1] 5

Tipp: Brechen Sie die Aufgabe auf Ihre Einzelteile herunter!

3.) Logische Ausdrücke kann man mit logischen Operatoren NICHT (!) ODER (|) und UND (&) verknüpfen. Was liefern die folgenden Aussagen? Überlegen Sie sich die Antwort zuerst bevor Sie es ausprobieren!

TRUE & TRUE
TRUE & FALSE
!TRUE 
TRUE | FALSE
FALSE | TRUE & FALSE
!(FALSE & TRUE)

Bei dieser Aufgabe kann man die Aufgaben eingeben.

Ergänzende Erklärungen:

  1. Die Summe über einen logischen Vektor liefert die Anzahl aller TRUE-Einträge. Damit entspricht TRUE in der Summe einer 1, wohingegen FALSE einer 0 entspricht.

  2. Hier ist die Präzedenz, also die Operatorrangfolge zu beachten!

5.4.2 Zeichenketten

Zeichenketten sind der komplexeste Datentyp in R. Zeichenketten stehen in Anführungszeichen

namen <- c("Andreas", "Berta", "Carl", "Dagmar", "Else") 

Im Wesentliche können alle Zeichen innerhalb einer Zeichenkette stehen, allerdings müssen manche Sonderzeichen escaped werden, da ihnen innerhalb der Programmiersprache R eine besondere Bedeutung zukommt. Eine Liste erhält man mit help('"').

Mit der Funktion paste() können Zeichenketten zusammengführt werden.

x <- c(1,2,3,4,5)
y <- c("A", "B", "C", "D", "E")

paste(x,y)
[1] "1 A" "2 B" "3 C" "4 D" "5 E"
paste(x, y, sep = "-")
[1] "1-A" "2-B" "3-C" "4-D" "5-E"
Aufgabe: paste()
  1. Wofür ist das Argument collapse= bei der Funktion paste()?
  2. Was ist der Unterschied zwischen paste() und paste0()?
  1. Das Argument collapse= hat zwei Aufgaben: zum einen werden dadurch alle Elemente des Vektors zu einem Element kollabiert, zum anderen wird der Separator für diese Aktion angegeben. Zum Beispiel
LETTERS
 [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
paste(LETTERS, collapse = "+")
[1] "A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z"
  1. Bei paste0() ist der Separator sep="", bei paste() ist er sep=" ".

5.4.3 Warum coerce?

Ist es möglich Objekte verschiedener Datentypen zusammenzuführen, und wenn ja, was passiert dann? Ja, es ist möglich! Die Einträge der Vektoren werden in einen neuen Vektor gezwungen. Der so entstandene Vektor hat dann den Typ des komplexesten auftauchenden Bestandteils.

c(1, pi, TRUE, FALSE)   # ist ein Double (Fließkommazahl)
[1] 1.000000 3.141593 1.000000 0.000000
c("Haus", 3, TRUE)      # ist eine Zeichenkette
[1] "Haus" "3"    "TRUE"
c(TRUE, FALSE, 2)       # ist ein numerischer Vektor
[1] 1 0 2

5.4.4 Erzeugen von bestimmten Vektoren

Der :-Operator

-3:7                      # Vektor in 1er Schritten
 [1] -3 -2 -1  0  1  2  3  4  5  6  7
1.3:6
[1] 1.3 2.3 3.3 4.3 5.3

Der :-Operator erzeugt einen auf- oder absteigenden numerischen Vektor bei dem der Startwert auf der linken Seite des Operators steht und der Endwert auf der rechten Seite. Dabei unterscheiden sich die Einträge des Vektors jeweils um 1 oder -1. Wir der Endwert nicht genau getroffen, so ist der nächst kleine Eintrag der letzte des Vektors.

Die Funktion seq()

Eine Erweiterung des :-Operators ist die Funktion seq() bei der beliebige Schrittgrößen möglich sind.

seq(0, 5, 0.5)            # Vektor in 0.5er Schritten
 [1] 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0

Es ist auch möglich mit Hilfe der Arguments length.out= die Länge des erzeugten Vektors festzulegen. Dabei ist die Schrittgröße konstant und wird dementsprechend berechnet.

seq(2,6, length.out = 12) # Vektor der Länge 12 (äquidistant)
 [1] 2.000000 2.363636 2.727273 3.090909 3.454545 3.818182 4.181818 4.545455
 [9] 4.909091 5.272727 5.636364 6.000000

Die Funktion rep()

Eine weitere praktische Funktion ist die Funktion rep() mit der Vektoren erzeugt werden können, die Wiederholungen enthalten. Dazu gibt es mehrere Möglichkeiten:

  • der Vektor wird komplett wiederholt,
rep(1:3, 4)               # Wiederholt den Vektor 1, 2, 3 viermal
 [1] 1 2 3 1 2 3 1 2 3 1 2 3
  • jeder Eintrag wird so oft wie angegen wiederholt. Dabei muss man darauf achten, dass beide Vektoren gleich lang sind.
rep(c("Eins", "Zwei", "Viele"), c(1,2,5))
[1] "Eins"  "Zwei"  "Zwei"  "Viele" "Viele" "Viele" "Viele" "Viele"
  • mit dem Argument each= wird jedes Argument so oft wie angegeben wiederholt bevor das nächste Argument wiederholt wird.
rep(1:3, each = 4)        # Wiederholt 1, 2, 3 je viermal
 [1] 1 1 1 1 2 2 2 2 3 3 3 3
Aufgaben: Erzeugen von Vektoren

Erzeugen Sie die folgenden Vektoren mit Hilfe der obigen Funktionen / Operatoren:

[1]  4  5  6  7  8  9 10
[1] 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00
 [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
 [1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE
4:10
[1]  4  5  6  7  8  9 10
seq(2,4, 0.25)
[1] 2.00 2.25 2.50 2.75 3.00 3.25 3.50 3.75 4.00
rep(1:3, 6)
 [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
rep(c(TRUE, FALSE, TRUE), each = 4)
 [1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE

5.4.5 Graph einer Funktion

Als praktische Anwendung der Funktion seq() wollen wir nun Graphen von Funktionen darstellen. Man kann R nun nicht einfach einen Funktionsterm geben, der dann einfach so als Grafik dargestellt wird. Statt dessen müssen wir um ggplot2 zu nutzen eine Datentabelle erzeugen, die x- und die y-Koordinaten enthält. Diese Koordinaten werden dann verbunden. Dies ist ziemlich analog dazu wie man es händisch auf einem Blatt Papier machen würde.

Als Beispiel wollen wir eine Normalparabel im Intervall [-2, 2] darstellen. Einen solchen Datentabelle kann man mit der Funktion tibble() generieren.

library(pacman)
p_load(tidyverse)

parabel1 <- tibble(x = seq(-2.5, 2.5, 0.5),  
                   y = x^2)                

parabel2 <- tibble(x = seq(-2.5, 2.5, 0.05),  
                   y = x^2)               
parabel1 |> ggplot(aes(x=x, y=y)) +
            geom_line(linewidth = 1.2) 
Abbildung 5.3: Die Funktion geom_line() verbindet die Punkte miteinander (die Reihenfolge in der Datentabelle ist dabei wichtig!). Die Datenpunkte sind hier aber zu weit auseinander, daher sieht die Parabel nicht glatt aus, sondern ist nur ein Polygonzug.
parabel2 |> ggplot(aes(x=x, y=y)) +
            geom_line(linewidth = 1.2) 
Abbildung 5.4: Die Datenpunkte sind so eng beeinander, dass die Kurve glatt aussieht.
Aufgaben: Code verstehen
  1. Erklären Sie die Funktionsweise von tibble() am einem der obigen Beispiele.
  2. Wie entsteht die y-Koordinate?
  3. Was ist der qualitative Unterschied zwischen parabel1 und parabel2?
  1. Mit tibble() können Datentabellen erstellt werden. Die Einträge sind gleich lange Vektoren, die durch Kommata getrennte werden. Die Mermalsnamen sind die Einträge links der =.

  2. Im ersten eintrag des Tibbles werden mit seq() die Stellen der Funktion erzeugt. Die y-Koordinaten werden aus diesem Vektor berechnet. Im obigen Fall einfach duch die Funktion x^2, was dem R-Code x^2 entspricht.

  3. Die Funktion geom_line() verbindet (x,y)-Koordinaten aus dem Tibble durch jeweils eine Gerade (von oben nach unten!). In parabel1 werden zu wenige Punkte erzeugt, so dass die Parabel nicht glatt wirkt.

Aufgabe: Eine Funktion darstellen

Zeichnen Sie mit Hilfe von ggplot2 die Funktion f(x) = x^2 \cdot \textsf{e}^{-x} im Intervall von [-1, 7].

library(pacman)
p_load(tidyverse)

daten <- tibble(x = seq(-1,7,0.02),
                y = x^2*exp(-x))

daten |> ggplot(aes(x = x, y = y)) + 
     geom_line(linewidth = 1)

5.4.6 Recycling

Ein sehr praktisches Konzept im Umgang mit Vektoren ist das Recycling. Beim Recycling werden Vektoren (ggf. nur Teile von Vektoren) wiederverwendet, so dass Vektoren ungleicher Länge verrechnet oder verglichen werden können.

  • Der kürzere Vektor wird so oft wiederholt bis beide Vektoren gleich lang sind:
c(1, 4) + c(20, 30, 40, 50) 
[1] 21 34 41 54

ist damit das Gleiche wie

c(1, 4, 1, 4) + c(20, 30, 40, 50)
[1] 21 34 41 54
  • Ist der längere Vektor kein ganzzahliges Vielfaches des kürzeren Vektors, so wird eine Warnung (kein Fehler) ausgegeben.
  • Der resultierende Vektor hat immer die Länge des längeren Vektors.

6 ist kein Vielfaches von 4, daher Warnung

1:6 + c(1,10,100,1000)  
Warning in 1:6 + c(1, 10, 100, 1000): Länge des längeren Objektes
     ist kein Vielfaches der Länge des kürzeren Objektes
[1]    2   12  103 1004    6   16

geht auch bei Vergleichen (später dazu mehr) 4 wird mit jedem Vektoreintrag verglichen

4 > 3:6
[1]  TRUE FALSE FALSE FALSE
Aufgaben: Recycling

1.) Was liefern die Ausdrücke

1:6 + 4:6 
c(1,10,100) + 10:13
rep(1:3,2) + c(10,100)

2.) Bei welchen Ausdrücken werden Warnungen ausgegeben?

Bitte!? Das kann man nun wirklich selbst ausprobieren!

5.4.7 Indizieren

Es gibt viele Situationen in denen es sinnvoll ist auf einzelne Elemete oder eine Gruppe von Elementen eines Vektors zuzugreifen. Dies geschieht mit dem mit den eckigen Klammern [] direkt im Anschluss an den Vektor. Dabei gibt es mehere Methoden wie die Auswahl der Elemente erfolgen kann.

Als Beispiel schauen wir uns den folgenden Vektor an:

vornamen        <- c("Alex", NA, "Carl", "Doro", NA, "Frank", "Gerd", "Hugo")
zahlen          <- 11:18
zahlen_mit_na   <- c(11, 12, NA, 14, NA, 16, 17, 18)

Auswahl durch positive ganze Zahlen

Schreibt man in die eckigen Klammern einen positiven, ganzzahligen Vektor, so werden diese Elemente ausgewählt:

vornamen[c(1,4,5)]
[1] "Alex" "Doro" NA    

Es ist auch möglich Einträge zu wiederholen (auch wenn dies in der Praxis nahezu nie vorkommt):

vornamen[rep(3:4, times = 3)]
[1] "Carl" "Doro" "Carl" "Doro" "Carl" "Doro"

Auswahl durch negative ganze Zahlen

Schreibt man einen negativen, ganzzahligen Vektor (oder einen positiven mit einem - davor), so werden diese Elemente ausgelassen:

vornamen[-c(1,4,5)]
[1] NA      "Carl"  "Frank" "Gerd"  "Hugo" 

Es ist natürlich nicht möglich, positive und negative Werte in dem Auswahlvektor zu kombinieren.

Auswahl durch einen logischen Ausdruck

Am häufigsten verwendet man die Auswahl der Einträge über einen logischen Ausdruck. Schauen wir uns dazu ein paar Beispiele an:

zahlen[zahlen < 15]
[1] 11 12 13 14

Um zu verstehen, was hier genau passiert, müssen wir uns klar machen, was im inneren der Klammer passiert: Der Ausdruck

zahlen < 15
[1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE

ist also ein Vektor, der nur aus den Wahrheitwerten TRUE und FALSE, sowie ggf. NAs besteht. Der logische Vektor hat genau die Länge des Vektors x. Im Ausdruck x[x<15] werden nun alle Elemente ausgewählt bei denen der Ausdruck TRUE oder NA ist, wobei zu bemerken ist, dass die Ausgabe für die NAs immer auch ein NA ist, wie das folgende Beispiel zeigt:

y <- 1:3
y[c(FALSE, NA, TRUE)]
[1] NA  3

Man kann auch alle Nicht-NA-Einträge eines Vektors herausfiltern. Dazu benötigt man die Funktion is.na(), beziehungsweise deren Verneinung.

zahlen_mit_na[!is.na(zahlen_mit_na)]
[1] 11 12 14 16 17 18
Aufgabe

Die obigen numerischen Vektoren zahlen und zahlen_mit_na haben die gleiche Länge, so dass die folgenden Ausdrücke sinnvoll sind:

zahlen[zahlen_mit_na < 15]
zahlen_mit_na[zahlen < 15]

Überlegen Sie sich, was diese Ausdrücke liefern und überprüfen Sie das Ergebnis dann mit R.

Auch das kann man mall selbst ausprobieren!

5.5 Der Pipe-Operator

Der Pipe-Operator |> (oder %>% aus Paket magrittr / Tidyverse) ermöglicht eine sehr intuitive Syntax, die insbesondere mit den Tidyverse-Befehlen aber auch für R-Base Funktionen praktisch ist.

Prinzip

Was links vom Operator steht, wird als erstes Argument in der Funktion rechts verwendet.

Formal entspricht x |> f() (auch: x %>% f() also dem Aufruf f(x). Alle weiteren Argumente können der Funktion auf die übliche Weise hinzugefügt werden, wie man am Beispiel sehen kann. Aus dem Funktionsaufruf f(x, y) wird formal mit der Pipe x |> f(y)

Das Ergebnis kann dann wiederum mit der Pipe |> in eine nächste Funktion geschoben werden, und so weiter.

Der große Vorteil liegt darin, dass unübersichtliche Verschachtelungen zu einer linearer Abfolge (von innen nach außen) werden.

Beispiel 1

Im ersten Beispiel soll der folgende geschachtelte Ausdruck mittels Pipe-Operator ausgeführt werden:

sqrt(round(log(x = 2.44, base = 3), digits = 2))
[1] 0.9

Dieser Ausdruck wird von innen nach außen ausgeführt, das heißt zuerst wird der Logarithmus von 2.44 zur Basis 3 berechnet, dann auf zwei Nachkommastellen gerundet und aus dem Ergebnis zieht man die Quadratwurzel.

Verwendet man den Pipe-Operator, so vereinfacht sich die letzte Formel zu

2.44 |>  log(base = 3) |> round(digits = 2) |> sqrt()
[1] 0.9

Man fängt mit der innersten Klammer an 2.44. Den Ausdruck schiebt man in die Funktion log(), wobei base=3 das zweite Argument der Funktion ist. Das Ergebnis aus der Rechnung wird in die Funktion round() geschoben. Diese Funktion round() hat als erstes Argument x dem das Ergebnis aus der Pipe zugewiesen wird. Das zweite Argument der Funktion round() ist digits=0. Möchte man das zweite Argument ändern so muss man dies angeben (siehe oben). Da es sich um das zweite Argument in der Funktion handelt, kann der Argumentname auch unterdrückt werden:

2.44 |>  log(3) |> round(2) |> sqrt()
[1] 0.9

Das Ergbnis aus dieser Rechnung wird dann in die letzte, das heißt äußerste Funktion geleitet.

Beispiel 2

Das zweite Beispiel ist aus dem Tidyverse: es kommt bei der Datenverarbeitung oft vor, dass Daten aufgearbeitet werden. So werden in Datentabellen Zeilen gefiltert, Spalten ausgewählt oder neu erzeugt, Kenngrößen berechnet, Grafiken erzeugt und vieles mehr. Bei diesen Prozessen ist es üblich, dass Daten bearbeitet werden und mit diesen dann weiter gearbeitet wird. Hierfür eignet sich der Pipe-Operator besonders gut.

Im Beispiel unten sind nur zwei Schritte zu sehen (filtern und danach eine Grafik erzeugen). Man kann hier noch einen großen Vorteil in der Pipe-Schreibweise erkennen: soll auf das Filtern verzichtet werden, so kann diese Zeile einfach mit einem # auskommentiert werden. Der restliche R-Code läuft dann trotzdem. Im Fall ohne Pipe ist der Schritt deutlich umständlicher und sehr viel fehleranfälliger.

ohne Pipe:

ggplot(data = filter(mpg, hwy < 25), 
       aes(x = displ, y = hwy)) +
  geom_point()

mit Pipe:

mpg |> 
    filter(hwy < 25) |>  
    ggplot(aes(x = displ, y = hwy)) +
       geom_point()
Mögliche Fehler:
  • Es ist wichtig, dass die Pipes am Ende der Zeilen stehen und nicht am Anfang der nächsten. Würde man eine Pipe an den Anfang einer Zeile stellen, so wäre der Befehl (aufgrund des Zeilenumbruchs) bereits vor der Pipe zu Ende

  • Bei der Benutzung der Pipe ist es wichtig (wie bei allen Operatoren) auf deren Bindungsstärke achten! Insbesondere bindet die Pipe weniger stark als das Exponenzieren! Siehe Kapitel 5.1.3

Aufgaben: Pipe-Operator

Schreiben Sie den folgenden Ausdruck mit Hilfe des Pipe-Operators, und überlegen Sie sich welchen mathematischen Ausdruck Sie da berechnen!

round(exp(log(14, base = 6)), digits = 3)
round(exp(log(14, base = 6)), digits = 3)
[1] 4.362
14 |> log(base=6) |> exp() |> round(digits=3)
[1] 4.362