›  Demo-R1: R-Tutorial: Teil 2

Der zweite Teil der R-Tutorial-Reihe bietet einen Einstieg in Kontrollstrukturen (bedingte Verzweigungen und Schleifen) und die Verwendung und Erstellung von Funktionen in der Programmiersprache R.

Nachdem in Teil 1 der R-Tutorial-Reihe eine erste Einführung in das Basiswissen der Programmiersprache R bzgl. der Syntax, Variablen, Matrizen, regelmäßigen Folgen und dem Umgang mit Datensätzen erfolgt ist, bietet dieser Teil eine Vertiefung in Richtung Ablaufsteuerung und dem Einsatz von eigenen und in Paketen vordefinierten Funktionen.

info-icon Motivation

R ist eine freie Programmiersprache für statistische Berechnungen und Grafiken. Sie wurde 1992 von den Statistikern Ross Ihaka und Robert Gentleman an der Universität Auckland für Anwender mit statistischen Aufgaben neu entwickelt und ist auf UNIX-Plattformen, Windows and MacOS lauffähig. Die R-Umgebung wird ausdrücklich ebenfalls als R bezeichnet und ist Teil des GNU-Projekts.

Warum R?

R gilt als eine Standardsprache für statistische Problemstellungen sowohl in der Wirtschaft als auch in der Wissenschaft. Da der Quellcode öffentlich ist, bietet R die Möglichkeit, schnell neue Pakete zu entwickeln und zur Verfügung zu stellen.

Die kostenlosen und online verfügbaren Pakete erweitern das Anwendungsfeld von R auf viele Fachbereiche. Die interne Dokumentationen und auch die Foren, die sich mit der Anwendung von R befassen, bieten dem Benutzer die Möglichkeit die Funktionalität von R leicht zu erfassen und anzuwenden.

Warum RStudio?

RStudio ist eine kostenlose und integrierte Entwicklungsumgebung für die Progammiersprache R, durch RStudio wird die Benutzerfreundlichkeit von R erhöht. Der Aufbau der Entwicklungsumgebung ist einfach und sehr übersichtlich.

R vs. MATLAB und Python

R wird, wie MATLAB und Python, insbesondere für die Entwicklung von Anwendungen im Bereich des Maschinellen Lernens verwendet, um z.B. im Rahmen der Vorausschauenden Wartung Prognosen oder Clusteranalysen zu erstellen. Die drei Sprachen bieten zum Teil ähnliche Funktionalität (Bibliotheken für statistische Probleme, ausgefeilte Grafik- und Visualisierungsmodule), wobei jede ihre Stärken und Schwächen hat. Während R auf statistische Programmierung spezialisiert ist, ist MATLAB allgemeiner auf mathematische Problemstellungen ausgelegt. Python hingegen ist eine Programmiersprache, die um statistische Programmbibliotheken erweitert wurde. Die Gemeinsamkeiten und Unterschiede in der Syntax und Verwendung werden hervorgehoben, um Wechslern den Einstieg in R zu erleichtern.

info-icon Übersicht

Das Tutorial ist in vier Abschnitte gegliedert, die die R-Syntax an einfachen Beispielen erklären und aufeinander aufbauen:

  1. Gruppen von Anweisungen

  2. Bedingte Verzweigung: if-Anweisung

  3. Schleifen: for, while, repeat-Anweisung

  4. Funktionen

Gruppen von Anweisungen

Die Definition von Gruppen von Anweisungen über mehrere Zeilen wird häufig bei Kontrollstrukturen und Funktionen angewandt, da dies zur Übersichtlichkeit des Quellcodes dient.

Um Gruppen von Anweisungen (zusammengehörige Anweisungen bzw. Codeblöcke) zu definieren, werden geschweifte Klammern verwendet. Die Anweisungen in einer geschweiften Klammer werden wie ein einziges Kommando ausgeführt. Die Anweisungen können durch ein Semikolon getrennt hintereinander in einer Zeile stehen oder untereinander in mehreren Zeilen. Dabei liefert eine Gruppe bei Aufruf nur ein Objekt als Ergebnis wieder, dies ändert sich bei Funktionen.

Beispiel: Gruppen von Anweisungen in einer Zeile
Im folgenden Beispiel wird die Gruppe V definiert, die zwei Zuordnungen und zwei Ausdrücke, also vier Anweisungen enthält. Bei Aufruf der Gruppe V wird nur die letzte Anweisung ausgegeben, aber die beiden Zuordnungen sind weiterhin aufrufbar.

Der Quellcode enthält in

Zeile 1: die Gruppe V wird über geschweifte Klammern definiert und enthält vier Anweisungen.
Zeile 2: die Gruppe V wird aufgerufen.
Zeile 3: die Anweisungen x und y, die innerhalb der Gruppe V aufgerufen wurden, werden ausgegeben.

R-Skript Output
 V={x=3;y=4; x+y; x*y;}
 V
 x;y; 

Beispiel: Gruppen von Anweisungen über mehrere Zeilen
Im folgenden Beispiel wird die Gruppe W definiert, die zwei Zuordnungen und einen Ausdruck, also drei Anweisungen, enthält. Bei Aufruf der Gruppe W wird nur die letzte Anweisung ausgegeben, aber die beiden Zuordnungen sind weiterhin aufrufbar.

R-Skript Output
 W={ 
   x=1 
   y=3 
   x-y 
 } 
 W 

Hinweis: In Python erfolgt die Definition von Codeblöcken über Einrückungen und Leerzeichen, wie auch in MATLAB.

Bedingte Verzweigungen

Eine bedingte Verzweigung ist eine Kontrollstruktur, die festlegt, welche von zwei (oder mehr) Gruppen von Anweisungen, abhängig von einer (oder mehreren) Bedingungen, ausgeführt wird. Bedingte Verzweigungen werden in R wie in fast allen Programmiersprachen mit der if-else-Anweisung beschrieben. Das Schlüsselwort "else if" in R ist genau wie: "Wenn die vorherigen Bedingungen nicht zutreffen, versucht es mit dieser Bedingung" und das Schlüsselwort "else" fängt alles ab, was von den vorhergehenden Bedingungen nicht erfasst wird.

Beispiel: if-Anweisung
Abhängig davon, ob der Wert der Variablen x kleiner, gleich oder größer als 10 ist, werden unterschiedliche Strings in der Console ausgegeben.

Der Quellcode enthält in

Zeile 1: die Variable x bekommt den Wert 8 zugewiesen.
Zeile 3: Prüfe, ob der Wert von x kleiner als 10 ist, dann führe Anweisungen in Zeile 4 und 5 aus.
Zeile 6: Prüfe, ob der Wert von x gleich 10 ist, dann führe Zeile 7 aus.
Zeile 8: Falls die Bedingungen in Zeile 3 und 6 nicht erfüllt sind, dann führe Anweisungen in Zeile 9-12 aus.

R-Skript Output
 x = 8 
  
if(x<10) { 
   cat("Der Wert von x ist kleiner als 10,  
        Wert:); x;  
} else if(x==10) {                                        
  cat("Der Wert von x ist gleich 10.")  
} else { 
   cat("Keine der vorherigen Bedingungen 
        ist erfüllt.")
   cat("Der Wert von x ist größer als 10, 
        Wert:); x; 
 } 

Nun wird der Wert von x auf 12 gesetzt und damit bei Anwendung der obigen if-Anweisung eine andere Gruppe von Anweisungen ausgeführt.

R-Skript Output
 x = 12 
  
if(x<10) { 
   cat("Der Wert von x ist kleiner als 10,  
        Wert:); x;  
} else if(x==10) {                                        
  cat("Der Wert von x ist gleich 10.")  
} else { 
   cat("Keine der vorherigen Bedingungen 
        ist erfüllt.")
   cat("Der Wert von x ist größer als 10, 
        Wert:); x; 
 } 

Hinweis: In Python lautet Syntax der Abfragen: if, elif, else und in MATLAB if, elseif, else, end. Dabei kommen die Einrückungen zur Definition der Codeblöcke bei den einzelnen Bedingungen zum Einsatz.

Schleifen

Schleifen ermöglichen es, Anweisungen wiederholt auszuführen, und zwar so lange, wie eine Ausführungsbedingung erfüllt ist. R verfügt über drei Schleifenbefehle: "for"-Schleife, "while"-Schleife und "repeat"-Schleife.

for-Schleife

Eine for-Schleife ist eine Zählschleife, die für eine Zählvariable eine Start- und Endbedingung festlegt. Die Anweisungen werden für eine vorgegebene Anzahl an Schleifen-Durchläufen wiederholt. Die Angabe der Anzahl wird über die Zählvariable umgesetzt, die automatisch nach jedem Schleifendurchlauf um 1 (bzw. eine andere Schrittweite) erhöht wird.

Syntax: for(Zählvariable in Wert){Anweisungen im Schleifenrumpf}.

Beispiel: for-Schleife
Die Schleife wird 10 mal durchlaufen und dabei wird der Wert der Variablen x jeweils um 1 erhöht. Die Zählvariable i der Schleife startet bei 1 und endet bei 10.

Der Quellcode enthält in

Zeile 1: die Variable x bekommt den Wert 3 zugewiesen.
Zeile 2: for-Schleife mit Schleifenrumpf/Gruppen von Anweisungen in geschweiften Klammern, Erhöhung von x um den Wert 1 und Ausagbe von x mit der print()-Anweisung.

R-Skript Output
 x=3 
 for(i in 1:10){x=x+1; print(x);} 

Hinweis: In Python wird mit der for-Schleife über die Elemente einer Sequenz (Liste, Tupel, Menge etc.) iteriert, eine einfache for-Schleife wie in anderen Programmiersprachen gibt es nicht. Die Syntax der for-Schleife erfordert zwingend den Mitgliedsoperator "in". for-Schleifen wie in R müssen in Python mit Hilfe der range()-Funktion umgeschrieben werden.
In MATLAB wird mit der Syntax "for i=1:k:n ... end" eine Zählvariable definiert, die beim Index 1 startet und den Index je Schleifendurchlauf um k erhöht, bis der Indexwert n erreicht ist.

while-Schleife

Eine while-Schleife ermöglicht es, Anweisungen wiederholt auszuführen, und zwar so lange, wie eine Ausführungsbedingung erfüllt ist. Dabei wird die Variable, die in der Bedingung abgefragt wird, nicht automatisch heraufgesetzt, sie muss also im Schleifenrumpf explizit inkrementiert werden. Wenn keine Erhöhung der Variablen stattfindet, dann erfolgt eine Endlosausführung der Schleife.

Syntax: while(Bedingung){Anweisungen im Schleifenrumpf}.

Hinweis: In Python wird ebenfalls durch "while i ≤ Wert:" ein while-Schleife definiert, die Anweisungen des Schleifenrumpfes erfolgen als eingerückte Anweisungen. In MATLAB definiert "while i ≤ Wert ... end" eine while-Schleife, hier, wie auch in Python und R, muss der Wert der Variablen i inkrementiert werden, damit keine Endlosschleife entsteht.

Beispiel: while-Schleife: Inkrementierung als letzte Anweisung
Die Schleife wird so lange ausgeführt, wie die Variable i kleiner als 10 ist. Dabei wird der Wert der Variablen i als letzte Anweisung im Schleifenrumpf um 1 erhöht. Die Zählvariable i der Schleife startet bei 0. Die print()-Anweisung gibt die Werte von i, hier 0 bis 9, aus.

R-Skript Output
  i=0 
  while(i<10){print(i); i=i+1; } 

Beispiel: while-Schleife: Inkrementierung als erste Anweisung
Die Schleife wird so lange ausgeführt, wie die Variable i kleiner als 10 ist. Dabei wird der Wert der Variablen i als erste Anweisung im Schleifenrumpf um 1 erhöht. Die Zählvariable i der Schleife startet bei 0. Die print()-Anweisung gibt die Werte von i, hier 1 bis 10, aus.

R-Skript Output
  i=0 
  while(i<10){i=i+1; print(i);} 

Die Stelle der Inkrementierung spielt also eine entscheidende Rolle für die Ausgabe.

repeat-Schleife mit break-Anweisung

Bei einer repeat-Schleife wird der Schleifenrumpf solange ausgeführt, bis eine Abbruchbedingung erfüllt ist. Diese Abbruchbedingung wird erst am Ende des Schleifenrumpfes überprüft (if-Anweisung mit break-Anweisung), also in umgekehrter Reihenfolge als bei den vorherigen Schleifen. Die Schleife wird bei Erfüllung der Bedingung mit dem Schlüsselwort "break" abgebrochen. Dabei wird die Variable, die in der Bedingung abgefragt wird, nicht automatisch heraufgesetzt, sie muss also im Schleifenrumpf heraufgesetzt werden, um eine Endlosschleife zu vermeiden. Die Stelle der Erhöhung der Variablen spielt wieder eine entscheidende Rolle für die Ausgabe.
Hinweis: In Python wird ebenfalls mit dem Schlüsselwort "break" eine Schleife abgebrochen.

Beispiel: repeat-Schleife: Inkrementierung als erste Anweisung
Die Schleife wird so lange ausgeführt, wie die Variable i kleiner oder gleich 10 ist. Dabei wird der Wert der Variablen i als erste Anweisung im Schleifenrumpf um 1 erhöht. Die Zählvariable i der Schleife startet bei 0. Die print()-Anweisung gibt die Werte von i, hier 1 bis 11, aus. Die Abbruchbedingung wird mit einer if-Anweisung geprüft und bei Erfüllung der Bedingung (i>10) wird die Schleife mit dem Schlüsselwort "break" abgebrochen.

R-Skript Output
  i=0 
  repeat{ 
  i=i+1; print(i);  
  if(i>10) break 
  }   

Funktionen

Eine Funktion ist eine Gruppe von Anweisungen, die nur ausgeführt wird, wenn sie aufgerufen wird. Funktionen werden einmal definiert und können dann beliebig oft aufgerufen werden, dabei können die Funktionen im eigentlichen Code stehen oder in einer separaten R-Datei. Man kann Daten oder sogenannte Parameter, an eine Funktion übergeben. Eine Funktion kann auch Daten/Parameter zurückgeben. Damit eine Funktion Werte zurückgeben kann, benutzt man das Schlüsselwort "return".

Funktionen kommen auf zweierlei Arten zum Einsatz: zum einen verwendet man vordefinierte Funktionen der R-Pakete, um gewisse Aufgaben durchzuführen. Zum anderen entwickelt man eigene Funktionen für Teilaufgaben und strukturiert damit größere Programme.

Hinweis: Bei Funktionen kommt die Syntax für Gruppen von Anweisungen, also geschweifte Klammern, zum Einsatz. In Python werden zur Definition einer Funktion Einrückungen eingesetzt. Und in MATLAB wird eine Funktion, wie schon bei den Kontrollstrukturen, mit dem Schlüsselwort "end" als Zeichen für den Abschluss der Funktion umrahmt.

Definition einer Funktion

Funktionen werden definiert, indem man dem Funktionsnamen das Schlüsselwort "function" zuweist, und danach in runde Klammern gesetzt eine Parameterliste angibt. In den folgenden geschweiften Klammern stehen die Anweisungen, die zum Anweisungsblock der Funktion gehören.

Syntax: funktionsName=function(Übergabeparameter){Anweisungen}.

In R erfolgt die Festlegung der Rückgabewerte mit dem Schlüsselwort "return" und dem dann folgenden Rückgabeobjekt, z.B. einer Variablen, einer Liste usw. Alle Anweisungen nach der return-Zeile werden ignoriert, d.h. return kennzeichnet somit das Ende der Anweisungen im Funktionskörper. Wird kein "return" gefunden, nimmt R die letzte Anweisungszeile im Funktionskörper als Rückgabewert.
Bevor die Funktion aufgerufen werden kann, muss dies ein die aktuelle R-Session geladen werden, d.h. mit RUN ausgeführt werden. Die Funktion erscheint dann im Environment-Tab. Bei Angabe des Funktionsnamens (Achtung: kein Aufruf der Funktion) in der Konsole wird die gesamte Funktionsdefinition dort angezeigt.

Beispiel: Funktion ohne Parameter

  #ohne Übergabeparameter: 
  my_func = function(){ 
    print("Meine eigene Ausgabe Funktion."); 
  } 
  # Funktions-Aufruf:                
  my_func()	
   # Ausgabe: [1] "Meine eigene Ausgabe Funktion."

Beispiel: Funktion mit Übergabeparameter

  #mit Übergabeparameter: 
  my_func = function(text){ 
    print(text); 
  } 
  # Funktions-Aufruf:                
  my_func("Übergebener Wert")	
  # Ausgabe: [1] "Übergebener Wert"

Beispiel: Funktion mit default-Übergabeparameter

  #mit default-Übergabeparameter: 
  my_func = function(text= "kein Text übergeben""){ 
    print(text); 
  }        
  # Funktions-Aufrufe:           
  my_func()	
   # Ausgabe: [1] "kein Text übergeben"
  my_func("Übergebener Wert")	
   # Ausgabe: [1] "Übergebener Wert"
  my_func(text = "Übergebener Wert")	
   # Ausgabe: [1] "Übergebener Wert"

Beispiel: Funktion mit Übergabe- und Rückgabeparameter

  myfunc2 = function(x,y){ 
  z <- x+y;      
  A=diag(x);      
  return(z);              
  }
  myfunc2(2,3) #Ausgabe: [1] 5

Wenn das Schlüsselwort "return" weggelassen wird, dann nimmt R die letzte Anweisung als Rückgabewert.

  myfunc2 = function(x,y){ 
  z <- x+y;      
  A=diag(x);      
  z;        
  A;       
  }
  myfunc2(2,3) 
  #Ausgabe:      
  #[,1] [,2]
  #[1,]    1    0
  #[2,]    0    1

Beispiel: Funktion mit mehreren Rückgabeparametern (einer Liste)

Dem Schlüsselwort "return" kann nur ein Objekt übergeben werden, bei mehr Objekten kommt es zu einer Fehlermeldung beim Funktionsaufruf. Ein Element der Rückgabeliste kann gezielt über das $-Zeichen und Nennung des Elementnames aufgerufen werden.

 myfunc3 = function(x,y){ 
 z <- x+y;      
 A=diag(x);
 out=list(summe=z, matrix=A)     
 #Liste mit den Elementen "summe" und "matrix"
 return(out)  
 #Liste zurückgeben
 }           
 
 myfunc3(2,3)
 #Ausgabe: 
 #$`summe`
 #[1] 5
 #
 #$matrix
 #[,1] [,2]
 #[1,]    1    0
 #[2,]    0    1
  
 # Speichern der Rückgabe in einer Variablen out1:
 out1=myfunc3(2,3)
  
 # Aufruf einzelner Rückgabe-Elemente:
 B=out1$matrix
 B 
  #Ausgabe:      
  #[,1] [,2]
  #[1,]    1    0
  #[2,]    0    1    

Beispiel: Funktion mit einem Datensatz als Rückgabeparameter und default-Übergabeparametern

Dem Schlüsselwort "return" wird ein Datensatz als Rückgabeobjekt übergeben, dessen Elemente mit dem $-Zeichen aufrufbar sind.

 # mit Datensatz als Rückgabewert  
 myfunc4 <- function(x = 1, y = 0){ 
 z <- x+y;        
 y=x*y 
 out=data.frame(Summe=z,Produkt=y) 
 return(out)      
 } 
            
 myfunc4(5,3) 
 #Ausgabe: 
 #  Summe Produkt 
 #1     8      15 
 out2=myfunc4(5,3) 
 out2$Summe # Ausgabe: [1] 8 

Funktionen in separaten R-Dateien

Um den Quellcode übersichtlich zu halten, ist es sinnvoll, Funktionen in eigenen R-Dateien zu speichern und diese dann im Haupt-Quellcode mit der source()-Anweisung zu laden. Die geladenen Funktionen erscheinen dann im Environment-Tab und sind in der aktuellen R-Sitzung anwendbar.

Beispiel: Lade die Datei mit der Funktion "myfunc4"

In der R-Datei "myfunc4.r" befindet sich der Teil der Funktionsdefinition des obigen Codes (Zeile 1 bis 7). Mit

 source("myfunc_4.r") 

wird dieser Quellcode (Funktionsdefinition) in die aktuelle R-Session geladen und ist nun aufrufbar. Dazu muss entweder die R-Datei im gleichen Ordner wie die Datei, die die "source()"-Anweisung enthält, liegen oder es muss der Pfad zu dem passenden Ordner angegeben werden.

Hinweis: In Python erfolgt die Definiton einer Funktion, indem man nach dem Schlüsselwort "def" den Name der Funktion angibt, und danach ebenfalls in runden Klammern die Parameterliste (komma-getrennt) angibt. In den nachfolgende Zeilen stehen die Anweisungen, diese müssen eingerückt sein. Die Festlegung der Rückgabewerte erfolgt ebenfalls mit dem Schlüsselwort "return" und dem dann folgenden Rückgabeobjekt. In MATLAB lautet die Syntax: function [Rückgabeliste] = funktionsName(Übergabeparameter) ... end. Dabei werden die Rückgabewerte bereits in der ersten Zeile der Definiton durch die Nennung in den eckigen Klammern festgelegt.

Autoren, Tools und Quellen

Autoren:
 M. Sc. Anke Welz
 Prof. Dr. Eva Maria Kiss
Tools:
R, RStudio
Quellen und weiterführende Links
R-Tutorial Teil 1: Variablen, Vektoren, Matrizen, regelmäßigen Folgen
R-Dokumentation im Comprehensive R Archive Network (CRAN)