2  Funktionen

Bevor wir zum Bearbeiten des Datensatzes übergehen, wollen wir uns kurz Funktionen in R ansehen, wie diese aufgebaut sind und wie wir selbst Funktionen schreiben können. Dies wird uns in den folgenden Kapiteln das Leben vereinfachen.

2.1 Aufruf von Funktionen

Der Aufruf einer Funktion erfolgt durch den Namen der Funktion gefolgt von einem Paar runden Klammern in dem das Argument bzw. die Argumente stehen.

sqrt(x = 16)            # Quadratwurzel von 16
[1] 4
exp(x = 1)              # Exponentialfunktion an der 1 ausgewertet
[1] 2.718282
log(x = 16)             # Logarithmus von 16 zur Basis e
[1] 2.772589
log(x  = 16, base = 2)  # Logarithmus von 16 zur Basis 2
[1] 4
c(2,3,5,7,11)           # Vektor mit den Einträgen 2, 3, usw.
[1]  2  3  5  7 11

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()`:
! konnte Funktion "Sqrt" nicht finden
Tabelle 2.1: Einige mathematische und statistische Funktionen, die in den nächsten Kapiteln nützlich sein könnten, 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 (ggf. Argumente)
abs() / sign() Betragsfunktion / Algebraisches Vorzeichen
sqrt() Quadratwurzel
factorial() Fakultät (eigentlich: \Gamma(x+1))
choose() Binomialkoeffizient: n über k : \binom{n}{k} (n, k)
round() Rundet x auf 0 Stellen nach dem Komma (digits=0)
signif() Rundet x auf 6 signifikante Stellen (digits=6)
floor() / ceiling() Abrunden / Aufrunden
sum() / prod() Summe / Produkt der Elemente eines Vektors
mean() arithmetisches Mittel
sd() (Stichproben-)Standardabweichung
median() Median
quantile() Quantile von x, Standard probs=seq(0, 1, 0.25)

Beispiele:

choose(n = 49, k = 6)              # 49 über 6 
[1] 13983816
round(x = pi, digits = 4)          # π auf 4 Nachkommastellen gerundet
[1] 3.1416
round(x = 12345, digits = -3)      # 12345 auf Tausender gerundet
[1] 12000
signif(x = pi/10000, digits = 3)   # die ersten 3 signif. Stellen von π/10000 
[1] 0.000314
sum(c(2,3,NA), na.rm = TRUE)       # summiert einen Vektor und ignoriert `NA`s
[1] 5

Beim Aufrufen einer Funktion gibt es zwei Möglichkeiten wie die Argumente richtig zegeordnet werden:

  • Argument an der richtigen Stelle (positional matching) und
  • Name des Arguments (named matching).

Betrachten wir beispielsweise die Logarithmusfunktion

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

Diese hat das Argument x= an der ersten Stelle und das Argument base= an der zweiten Stelle. Wollen wir den Logarithmus von 128 zur Basis 2 berechnen, so können wir das auf verschiedene Weisen machen:

log(x = 128, base = 2)   # ausführlich, alle Argumente angegben
[1] 7
log(128, 2)              # alle Argumente an der richtigen Stelle
[1] 7
log(base = 2, x = 128)   # Argumente richtig benannt, Reihenfolge egal
[1] 7
log(128, base = 2)       # erstes Argument an der richtigen Stelle, andere mit Namen
[1] 7

Bei einfachen Funktionen wird oft das positional matching verwendet. Werden die Funktionen komplizierter, haben also mehrere Argumente, die auch nicht alle angegeben werden wollen bzw. müssen, so verwenden wir in der Regel das named matching. Sollte es einen angegebenen Argumentenamen nicht geben, so gibt es eine Warnung bei der Ausführung.

2.2 Die Hilfe-Funktion help() bzw. ?

Die Hilfe-Funktion help() bzw. ? ist eine der wichtigsten Funktionen, die R zur Verfügung stellt. Sie kommt insbesondere bei umfangreicheren bzw. unbekannten Funktionen zum Einsatz.

?exp 

# ist das Gleiche wie

help(exp)

2.3 Benutzerdefinierte Funktionen

An vielen Stellen ist es sinnvoll bzw. notwendig Funktionen selbst zu schreiben oder existierende Funktionen anzupassen. Dadurch ersparen wir uns Arbeit, da längliche Routinen nicht durch Copy & Paste viel Text im Skript erzeugen, sondern durch Funktionen abgekürzt werden können.

2.3.1 Syntax einer Funktion.

Eine Funktion ist von der Form:

NAME_FUNKTION <- function(ARGUMENTE) {
  INHALT
  return(RÜCKGABE)
}

Dabei sind die kapitalisierten Wörter Platzhalter.

  • Mit der Funktion function() (oder verkürzt \()) können Funktionen erstellt werden.
  • Da man die Funktion im weiteren aufrufen möchte, benötigt diese einen Funktionsnamen
  • Die Argumente, die die neue Funktion haben soll, werden in die runden Klammern () geschrieben. Weißt man diesen Standardwerte zu, so werden diese über = angegeben.
  • Der Funktionskörper bzw. die Funktionsweise wird dahinter in geschweifte Klammern { } geschrieben.
  • Mit der Funktion return() innerhalb der geschweiften Klammern wird die Ausführung der Funkion unterbrochen (beendet) und ein Rückgabewert wird bestimmt und ausgegeben. Dabei kann der Rückgabewert nur genau ein R-Objekt (z.B. ein Vektor, eine Liste, ein Tibble, etc.) sein.

Beispiel

Was macht die folgende Funktion?

meine_funktion <- function(arg1, arg2=10) {
  Summe <- arg1 + arg2
  return(Summe)
}

Der Name der Funktion ist meine_funktion. Diese Funktion hat zwei Argumente arg1= und arg2=, wobei letzteres bereits einen vordefinierten Wert hat. Der Rückgabewert der Funktion ist die Summe der beiden Argumente.

meine_funktion(4, 5)
[1] 9
meine_funktion(4)
[1] 14
HinweisÜbungsaufgabe (★☆☆☆)

Erstellen Sie eine Funktion, die zwei Zahlen multipliziert. Testen Sie die Funktion mithilfe der prod()-Funktion.

HinweisÜbungsaufgabe (★★☆☆)

Definieren Sie eine Funktion, die eine Sequenz zufälliger Münzwürfe beliebiger Länge simuliert. Als Argumente sollten die Wahrscheinlichkeit für Kopf und die Anzahl der Würfe verwendet werden. Default-Wahrscheinlichkeit: 50%.

muenzwurf <- function(n, p_kopf = 0.5){
  rval <- sample(x = c("Kopf", "Zahl"), 
                 size = n,
                 prob = c(p_kopf, 1-p_kopf), 
                 replace = TRUE)
return(rval)
}


muenzwurf(n = 8)
[1] "Kopf" "Zahl" "Kopf" "Zahl" "Zahl" "Zahl" "Zahl" "Zahl"

2.3.2 Das ...-Argument

Schaut wir und die Hilfe von einigen Funktionen an, so steht in vielen Funktionen ... in der Liste der Argumente. Dies bedeutet, dass wir beim Aufruf der Funktion Argumente angeben können, die nicht explizit in der Liste der Argumente stehen, aber unterstützt und sinnvoll sind.

Am besten machen wir uns das an einem Beispiel klar.

Beispiel für ...-Argument

sum
function (..., na.rm = FALSE)  .Primitive("sum")

Wie wir sehen hat die Funktion sum() das ...-Argument (gelesen: dot dot dot) in der Liste der Argumente. Mit der Funktion sum() können numerische oder logische Vektoren addiert werden. Wichtig hierbei ist, dass die Anzahl der Argumente erst einmal unbestimmt ist, weswegen eine derartige Syntax sinnvoll ist:

sum(c(1,2,3))                  # ein Argument
[1] 6
sum(1,2,3)                     # drei Argumente
[1] 6
sum(c(1,2,3), c(1,2,3), 1,2,3) # Fünf Argumente 
[1] 18

Das ...-Argument ist sehr praktisch, wenn man eigene Funktionen schreibt und die Funktionalität der verwendeten Funktionen nicht einbüßen möchte. Wir schauen uns das wieder an einem Beispiel an.

Beispiel

Wir wollen eine Funktion mein_plot() definieren bei der wir die Funktion plot() verwenden und modifizieren, aber die Funktionalität von plot() nicht einschränken wollen. Als Standard verwenden wir für die Darstellung Rot (color="indianred2"), Sterne (pch=8) und vergrößerte Symbole (cex=2). Damit können wir zum Beispiel folgende neue Funktion definieren.

mein_plot <- function(...){
   plot(..., 
        pch = 8, 
        col = "indianred2",
        cex = 2)

}

Zum Testen der Funktion definieren wir zwei Vektoren xx und yy:

xx <- seq(0,10,0.5)
yy <- rnorm(length(xx)) |> sort()
plot(x = xx, y = yy) # Standard

mein_plot(x = xx, y = yy) # neue Funktion

TippBemerkung

Wir können der Funktion plot() alle Argumente übergeben, die in der Funktion par() zu finden sind.

HinweisÜbungsaufgabe (★★★☆)

Nutzen Sie die Funktion mean() (das arithmetische Mittel)

\overline{x} = \frac{1}{n} \sum_{i = 1}^{n} x_i um eine Funktion für das verallgemeinerte Hölder-Mittel

\overline{x}_p = \left(\frac{1}{n} \sum_{i = 1}^{n} {x_i}^p\right)^{1/p} zu schreiben. Nutzen Sie das ...-Argument um der neuen Funktion alle Argumente der Funktion mean() übergeben zu können.

Was steht innerhalb der Klammer?

Welche Argumente müssen der Funktion übergeben werden?

Hast Du es wirklich selbst versucht?!

Ganz ehrlich?!

hoelder <- function(x, p, ...){
  rval <- mean(x^p, ...)^(1/p)
  return(rval)
}

## Beispiele:

x <- c(1:10, NA)
hoelder(x, p = 1) 
[1] NA
# arithmetisches Mittel
hoelder(x, p = 1, na.rm = TRUE) 
[1] 5.5
# empirische Standardabweichung
hoelder(x-mean(x, na.rm = TRUE), p = 2, na.rm = TRUE) 
[1] 2.872281
  • p=1 entspricht offenbar dem gewöhlichen arithmetischen Mittel,
  • p=-1 entspricht dem geometrischen Mittel, das man bei relativen Änderungen wie bei Wachstumsprozessen (Zinsen, Inflation etc.) benötigt.
  • p=2 nutzt man z.B. bei der Berechnung der empirischen Standardabweichung.
  • Für p \to \infty bekommt man das Maximum der Werte x_i und
  • für p \to -\infty das Minimum.