18  Eigene Funktionen programmieren

In R lassen sich auch eigene Funktionen integrieren. Die wohl “einfachste” Methode hierbei ist, die Funktionen in der R-Sprache selber zu schreiben. Es besteht aber auch die Möglichkeit, neue Funktionen in Programmiersprachen wie z.B. C++ zu programmieren.

Zum Erstellen einer eigenen Funktion steht der Befehl function() zur Verfügung. Dieser ist wie folgt aufzurufen:

function(Parameter1, Parameter2, ...) {
        FUNKTIONSWEISE
        }

In den Klammern direkt nach function können Parameter benannt werden, welche dann beim Funktionsaufruf der Funktion zur Verfügung stehen. Innerhalb der geschweiften Klammern wird die eigentliche Funktionsweise geschrieben.

Um eine neue Funktion in R aufrufen zu können, wird die Funktionsweise einem neuen Objekt (z.b. myfunc) zugeordnet.

myfunc <- function(x,y){ # Neue Funktion mit den Parametern x und y
          z <- x+y       # Die Summe von x und y wird in z gespeichert
          return(z)      # z wird zurückgemeldet
          }

Der obigen Dummy-Funktion werden im Funktionsaufruf die Parameter x und y übergeben. Innerhalb der Funktion wird die Summe aus x und y gebildet, und per return() an die R-Konsole zurückgemeldet. Jetzt können wir diese Funktion aufrufen:

myfunc(4,6)
## [1] 10

Es besteht ferner die Möglichkeit, Standardwerte für die Parameter zu setzen, welche verwendet werden, falls der Funktionsaufruf ohne Parameter erfolgt.

myfunc <- function(x=3,y=7){ # Neue Funktion mit Standardwerten für die Parameter x und y
          z <- x+y           # Die Summe von x und y wird in z gespeichert
          return(z)          # z wird zurückgemeldet
          }

Rufen wird die Funktion ohne Parameter auf, so werden die Standardwerte genutzt.

# Funktionsaufruf OHNE Parameter
myfunc()
## [1] 10

Rufen wir die Funktion mit Parametern auf, werden diese verwendet.

myfunc(12,4)
## [1] 16

18.1 Beispiele

Alle Funktionen (und Datensätze) dieses Lehrbuches sind auch im Zusatzpaket jgsbook enthalten (siehe Abschnitt 15.1).

18.1.1 z-Transformation

Mit dieser Funktion wird die z-Transformation für gegebene Werte errechnet. Die Funktion folgt der Formel

\(z_{i} = \frac{x_{i}-\mu}{\sigma}\)

Als Standardparameter werden die Werte der Standardnormalverteilung gesetzt.

ztrans <- function(x, mu=0, sd=1){
  z = (x-mu)/sd
  return(z)
}
# x ist 120, aus einer normalverteilten Reihe mit
# Mittelwert 118 und Standardabweichung 20
ztrans(120,mu=118,sd=20)
## [1] 0.1

18.1.2 Sensitivität

Die folgende Funktion errechnet Sensitivität, Spezifität sowie positiv- und negativ-prädiktive Werte für gegebene Werte.

sens.spec <- function(rp, rn, fp, fn){
    x <- data.frame(
             sens=round(rp/(rp+fn)*100, 2),
             spec=round(rn/(rn+fp)*100, 2),
             ppw =round(rp/(rp+fp)*100, 2),
             npw =round(rn/(rn+fn)*100, 2)
             )
   return(x)
 }

Die zu übergebenden Parameter sind

  • rp = Anzahl richtig positive
  • rn = Anzahl richtig negative
  • fp = Anzahl falsch positive
  • fn = Anzahl falsch negative
sens.spec(40, 17, 85, 4)
##    sens  spec ppw   npw
## 1 90.91 16.67  32 80.95

18.1.3 Kenngrößen

Die folgende Funktion gibt die gebräuchlichsten Kenngrößen einer Wertereihe zurück:

kenngroessen <- function(werte){
  bla <- data.frame(0)
  bla$modus=paste(as.character(statip::mfv(werte)), collapse="|")
  bla$mean=mean(werte, na.rm=T)
  bla$median=median(werte, na.rm=T)
  bla$p25=quantile(werte,0.25,type=6)
  bla$p75=quantile(werte,0.75,type=6)
  bla$iqr=IQR(werte,type=6)
  bla$sd=sd(werte, na.rm=T)
  bla$var=var(werte, na.rm=T)
  bla$VK= (sd(werte, na.rm=T)/mean(werte,na.rm=T))
  return(bla[-1])
}
# erzeuge zufällige Werte
x <- ceiling(rnorm(100, 10,5))

# Kenngrößen anzeigen
kenngroessen(x)
##   modus  mean median p25 p75 iqr       sd      var       VK
## 1     9 10.84     11   9  14   5 5.304315 28.13576 0.489328

18.1.4 Häufigkeitstabellen

Die folgende Funktion gibt eine vollständige Häufigkeitstabelle mit absoluten und relativen Häufigkeiten sowie kummulierten Werten zurück.

freqTable <- function(werte){
  x <- table(werte)
  tabelle <- data.frame(x)
  tabelle$freqcum <- cumsum(x)
  tabelle$relfreq <- round(x/length(werte)*100,2)
  tabelle$relcum  <- cumsum(round(x/length(werte)*100,2))
  colnames(tabelle) <- c("Wert", "Häufig", "Hkum", "Relativ", "Rkum")
  tabelle$Wert <- as.numeric(as.vector(tabelle$Wert))
  return(tabelle)
}
x <- ceiling(rnorm(13, 10,2))
freqTable(x)
##   Wert Häufig Hkum Relativ  Rkum
## 1    7      1    1    7.69  7.69
## 2    8      2    3   15.38 23.07
## 3    9      5    8   38.46 61.53
## 4   10      2   10   15.38 76.91
## 5   11      2   12   15.38 92.29
## 6   12      1   13    7.69 99.98

18.2 Bedingungen

Innerhalb der Funktion können Variablenbedingungen mit dem if()-Befehl abgefragt werden. Der Aufruf erfolgt etwa so:

if(VARIABLENBEDINGUNG) {FUNKTIONSWEISE}

Innerhalb der Klammern des if()-Befehls werden die Variablenbedingungen gesetzt. Falls diese Bedingungen erfüllt sind, wird der Code innerhalb der geschweiften Klammern ausgeführt. Folgende Bedingungen können abgefragt werden

Zeichen Bedingung
== gleich
!= ungleich
< kleiner
<= kleiner-gleich
> größer
>= größer-gleich
& UND
| ODER

Innerhalb von Funktionen kann man dies wie folgt anwenden

myfunc <- function(x=3,y=7){ 
          z <- x+y                      # Die Summe von x und y wird in z gespeichert
          if(z>20) {                    # Abfrage, ob die Summer größer als 20 ist
             z <- "wow, bist du gross"  # wenn ja, dann schreibe einen Text in das Objekt z
             }
          return(z)                     # z wird zurückgemeldet
          }

Mehrere Bedingungen können verknüpft werden, z.B. so:

myfunc <- function(x=3,y=7){ 
          if(x<0 & y<0) {         # Abfrage, ob x und y negativ sind
             x <- x*(-1)          # wenn ja, dann mache beide positiv
             y <- y*(-1)
             }
          z <- x+y                # Die Summe von x und y wird in z gespeichert
          if(z==0 | z>50)  {      # Abfrage, ob z gleich 0 oder größer 50 ist
            z <- "Summe ist 0 oder größer 50" # wenn ja, schreibe einen Text...
            }
          return(z)               # z wird zurückgemeldet
          }

18.2.1 Beispiel Zusatzpakete

Die folgende Funktion installiert die vorgegebenen Pakete, sofern sie noch nicht installiert sind. Dies ist hilfreich, wenn z.B. auf eine höhere R-Version geupdatet wurde, und alle Zusatzpakete neu installiert werden müssen.

install.my.packages <- function(){
  # Liste meiner favorisierten Pakete
  my_packages <- c("blogdown", "bookdown",
                 "car",
                 "foreign",
                 "gghighlight", "ggplot2",
                 "haven",
                 "likert",
                 "prettyR", "psych",
                 "reshape", "reshape2",
                 "samplingbook", "scales", "statip",
                 "tidyverse",
                 "VGAM",
                 "xtable"
)

#--------------
# Überprüfe, ob die Pakete bereits installiert sind
not_installed <- my_packages[!(my_packages %in% installed.packages()[ , "Package"])]
# installiere solche, die noch nicht installiert sind
if(length(not_installed)) install.packages(not_installed, dependencies = TRUE)
return(paste(length(not_installed), "Pakete wurden installiert (plus dependencies)."))
}

Die Funktion kann dann wie folgt aufgerufen werden:

install.my.packages()

Bei mir ist alles up-to-date, so dass kein Paket installiert werden muss.

Mit einer leichten Änderung können weitere Pakete an den Parameter p übergeben werden:

install.my.packages <- function(p=""){
  # Liste meiner favorisierten Pakete
  my_packages <- c("blogdown", "bookdown",
                 "car",
                 "foreign",
                 "gghighlight", "ggplot2",
                 "haven",
                 "likert",
                 "prettyR", "psych",
                 "reshape", "reshape2",
                 "samplingbook", "scales", "statip",
                 "tidyverse",
                 "VGAM",
                 "xtable"
)

# Falls Pakete über den Parameter "p" übergeben wurden,
# füge sie der Liste hinzu
if(p!=""){
  my_packages <- c(p, my_packages)
    }
#--------------
# Überprüfe, ob die Pakete bereits installiert sind
not_installed <- my_packages[!(my_packages %in% installed.packages()[ , "Package"])]
# installiere solche, die noch nicht installiert sind
if(length(not_installed)) install.packages(not_installed, dependencies = TRUE)
return(paste(length(not_installed), "Pakete wurden installiert (plus dependencies)."))
}

Der Funktion kann so ein Vektor weiterer Pakete übergeben werden, die zusätzlich zur vorgegebenen Liste installiert werden, falls sie noch nicht installiert sind:

install.my.packages(c("ggpubr", "qqplotr"))
[1] "2 Pakete wurden installiert (plus dependencies)."

18.3 Funktionen in Dateien speichern

Eigene Funktionen sind Objekte wie alle anderen Variablen im Workspace. Wenn sie nicht abgespeichert werden, stehen Sie u.U. nach einem Neustart (oder wenn der Workspace überschrieben oder geleert wird) nicht mehr zur Verfügung.

Es bietet sich an, die eigenen Funktionen in einer .R-Datei zu speichern. Mit dem source()-Befehl kann die Datei dann in neuen Projekten eingelesen werden, und die Funktionen stehen zur Verfügung.

source("/Pfad/zu/MeineFunktionen.R")