Die R Pro­gramming Language ist ein beliebte Statistik-Pro­gram­mier­spra­che, die vor allem in Wis­sen­schaft und Ma­the­ma­tik für Sta­tis­ti­cal Computing zum Einsatz kommt. R ist eine in­ter­es­san­te Sprache mit aus­ge­präg­ten Ei­gen­hei­ten. Hat man sich einmal daran gewöhnt, macht die Arbeit mit der Sprache durchaus Spaß.

Was zeichnet die „R Pro­gramming Language“ aus?

Bei R handelt es sich nicht um eine „General purpose“-Pro­gram­mier­spra­che wie Java oder Python. Vielmehr bedient die Sprache den spe­zi­el­len Ein­satz­be­reich des Sta­tis­ti­cal Com­pu­tings, zu Deutsch „sta­tis­ti­sches Rechnen“. Auf diesem Gebiet hält R seit Jahren trotz starker Kon­kur­renz einen Platz unter den 20 be­lieb­tes­ten Pro­gram­mier­spra­chen.

Was R besonders macht, ist nicht nur die Sprache an sich, sondern das Ge­samt­pa­ket. So findet die R-Pro­gram­mie­rung für ge­wöhn­lich in einer in­ter­ak­ti­ven Umgebung statt, komplett mit Read-Eval-Print Loop (REPL) und in­te­grier­ter Hilfe. Getragen wird die Open-Source-Sprache von einem weit ent­wi­ckel­ten Ökosystem; die Community unterhält das Paket-Re­po­si­to­ry „The Com­pre­hen­si­ve R Archive Network“ (CRAN). Auch Da­ten­sät­ze und wis­sen­schaft­li­che White­pa­per zu neuen Ansätzen und Paketen werden kon­ti­nu­ier­lich bei­gesteu­ert.

Zu­sam­men­ge­nom­men machen diese Ei­gen­schaf­ten R zur perfekten Pro­gram­mier­um­ge­bung für Statistik und Da­ten­wis­sen­schaf­ten. Gerade der in­ter­ak­ti­ve Charakter der Umgebung lädt zum Forschen ein und er­mög­licht ein spie­le­ri­sches Erlernen der Sprache und der zugrunde liegenden Ma­the­ma­tik.

R ist eine Statistik- und Daten-Pro­gram­mier­spra­che

R ist eine Statistik-Pro­gram­mier­spra­che und kennt Konzepte wie die Nor­mal­ver­tei­lung, sta­tis­ti­sche Tests, Modelle und Re­gres­si­on. Neben R existiert eine Reihe ver­gleich­ba­rer wis­sen­schaft­li­cher Sprachen – außer dem kom­mer­zi­el­len Produkt Matlab ist hier ins­be­son­de­re die jüngere Sprache Julia zu nennen. Als weiterer starker Kon­kur­rent der ver­gan­ge­nen Jahre gilt Python.

Im Gegensatz zu Python hat R native Un­ter­stüt­zung für sta­tis­ti­sche Pro­gram­mie­rung an Bord. Der her­aus­ra­gen­de Un­ter­schied liegt darin begründet, wie die Sprache auf Werten operiert. Daten liegen nor­ma­ler­wei­se in der Mehrzahl vor, und so rechnet man in R für ge­wöhn­lich mit mehreren Werten auf einmal. Während in fast allen anderen Sprachen der simpelste Wert eine einzelne Zahl ist, ist dies in R ein Spe­zi­al­fall.

Ver­an­schau­li­chen wir die Her­an­ge­hens­wei­se von R in Bezug auf Da­ten­ver­ar­bei­tung an einem simplen Beispiel. In jeder Pro­gram­mier­spra­che lassen sich ma­the­ma­ti­sche Ope­ra­tio­nen durch­füh­ren. Auch in R ist dies der Fall. Wir addieren zwei Zahlen:

# returns 15
10 + 5

So weit nichts Un­ge­wöhn­li­ches. Jedoch lässt sich in R dieselbe Additions-Operation auf eine Liste von Zahlen anwenden. Wir fassen zwei Zahlen zu einer Liste zusammen und addieren einen kon­stan­ten Wert:

# returns 15, 25
c(10, 20) + 5

Für ge­stan­de­ne Pro­gram­mie­re­rin­nen und Pro­gram­mie­rer ein über­ra­schen­des Ergebnis. Selbst eine moderne, dy­na­mi­sche Sprache wie Python erlaubt dies nicht:

# throws an error
[10, 20] + 5

In R lassen sich sogar zwei Listen addieren. Dabei werden nicht etwa die Lis­ten­ele­men­te zu einer Liste zu­sam­men­ge­fasst, sondern es wird für jedes Element die passende ma­the­ma­ti­sche Operation durch­ge­führt:

# returns 42, 69
c(40, 60) + c(2, 9)

In älteren Sprachen wie Java oder C++ benötigt man eine Schleife, um mehrere Elemente einer Liste zu ver­ar­bei­ten. Denn diese Sprachen trennen strikt zwischen einzelnen Werten, den Skalaren, und zu­sam­men­ge­setz­ten Da­ten­struk­tu­ren, den Vektoren. In R ist der Vektor die grund­le­gen­de Einheit; ein Skalar ist in der R-Pro­gram­mie­rung als ein­ele­men­ti­ger Vektor ein Spe­zi­al­fall.

An der Statistik ist besonders, dass die berühmte ma­the­ma­ti­sche Präzision auf­ge­weicht ist. Man rechnet mit Un­ge­wiss­hei­ten und der Realität ent­stam­men­den, im­per­fek­ten Daten. Dabei kann immer etwas schief gehen; glück­li­cher­wei­se ist R in gewissem Maße feh­ler­to­le­rant. Die Sprache kann mit fehlenden Werten umgehen, ohne dass diese ein laufendes Skript zum Absturz bringen.

Ver­an­schau­li­chen wir uns die Ro­bust­heit der Sprache an einem Beispiel. Nor­ma­ler­wei­se lässt sich in jeglicher Pro­gram­mier­spra­che ein Absturz pro­vo­zie­ren, indem man eine Zahl durch Null dividiert. R lässt dies jedoch kalt; als Ergebnis der Division durch Null wird der Wert Inf vermerkt, der sich in einem späteren Be­rei­ni­gungs­schritt einfach aus den Daten filtern lässt:

# list of divisors, containing zero
divisors = c(2, 4, 0, 10)
# returns `c(50, 25, Inf, 10)`
quotients = 100 / divisors
# filter out Inf; returns `c(50, 25, 10)`
cleaned_quotients = quotients[quotients != Inf]

R un­ter­stützt OOP und funk­tio­na­le Pro­gram­mie­rung

Die Pro­gram­mie­rung mit R gestaltet sich aus­ge­spro­chen flexibel; die Sprache lässt sich nicht klar in die Hier­ar­chie der Pro­gram­mier­pa­ra­dig­men einordnen. Getragen wird sie von einem OOP-System, die üblichen Klas­sen­de­fi­ni­tio­nen sucht man jedoch ver­geb­lich. Im täglichen Gebrauch kommen in erster Linie funk­tio­na­le und im­pe­ra­ti­ve Ansätze zum Einsatz. Gerade die funk­tio­na­len Features, die sich gut für die Da­ten­ver­ar­bei­tung eignen, sind stark aus­ge­prägt.

Ähnlich wie in Ja­va­Script glänzt das Ob­jekt­sys­tem durch seine Fle­xi­bi­li­tät. Mit Python ver­gleich­bar sind die ge­ne­ri­schen Funk­tio­nen, die sich auf Objekte un­ter­schied­li­chen Typs anwenden lassen. So gibt es in der R-Pro­gram­mie­rung die length()-Funktion, analog zu Pythons len().

Wie funk­tio­niert die R-Pro­gram­mie­rung?

In der R-Pro­gram­mie­rung dreht sich alles um Daten, denn darauf fußt die Statistik. Um eine Pro­blem­lö­sung in R zu ent­wi­ckeln, benötigt man einen Datensatz. Leider existiert dieser zum Zeitpunkt der Ent­wick­lung oft noch nicht. So beginnt man ein R-Pro­gramming-Projekt oft damit, Daten zu si­mu­lie­ren. Wir schreiben den Code, testen die Funk­tio­na­li­tät und tauschen die Testdaten später gegen echte Daten aus.

Wie wird R-Code aus­ge­führt?

Wie Ruby oder Python ist R eine dy­na­mi­sche, in­ter­pre­tier­te Skript­spra­che. Anders als in der Pro­gram­mier­spra­che C gibt es in R also keine Trennung von Quelltext und aus­führ­ba­rem Code. Die Ent­wick­lung findet meist in­ter­ak­tiv statt, d. h. man füttert den In­ter­pre­ter zei­len­wei­se mit Quellcode, der sofort aus­ge­führt wird. Variablen werden bei Bedarf au­to­ma­tisch erzeugt, Namen zur Laufzeit gebunden.

Der Effekt dieser in­ter­ak­ti­ven und dy­na­mi­schen Pro­gram­mie­rung ist ver­gleich­bar damit, sich innerhalb des laufenden Programms zu befinden. Bereits erzeugte Objekte lassen sich un­ter­su­chen und mo­di­fi­zie­ren, neue Ideen sofort testen. Der help-Befehl gibt Zugriff auf die Do­ku­men­ta­ti­on von Syntax und Funk­tio­nen:

# view help for `for` syntax
help('for')
# view help for `c()` function
help(c)

Aus dem In­ter­pre­ter heraus lassen sich Skript­da­tei­en dynamisch laden. Der source-Befehl funk­tio­niert wie das äqui­va­len­te Shell-Kommando. Beim Aufruf wird der Inhalt einer R-Quell­text­da­tei aus­ge­le­sen und in die laufende Session ein­ge­speist:

source('path/to/file.r')

Wie sieht die Syntax der R-Pro­gram­mier­spra­che aus?

Die Skript­spra­che nutzt die aus C und Java bekannten ge­schweif­ten Klammern, um die Körper von Funk­tio­nen und Kon­troll­an­wei­sun­gen ab­zu­gren­zen. Anders als in Python wirkt sich die Ein­rü­ckung von Code nicht auf dessen Funktion aus. Kom­men­ta­re beginnen wie in Ruby und Python mit einer Raute, am Ende einer Anweisung wird kein Semikolon benötigt.

Mit etwas Erfahrung erkennt man R-Code sofort, denn die Sprache bringt einige Ei­gen­hei­ten mit. Neben dem Gleich­heits­zei­chen als Zu­wei­sungs­ope­ra­tor, kommen in der R-Pro­gram­mie­rung zwei pfeil­ar­ti­ge Ope­ra­to­ren für Zu­wei­sun­gen zum Einsatz. So lässt sich die Richtung der Zuweisung umdrehen:

# equivalent assignments
age <- 42
'Jack' -> name
person = c(age, name)

Ein weiteres typisches Merkmal von R-Code ist eine Art Pseudo-Objekt-Notation nach dem Muster object.method():

# test if argument is a number
is.numeric(42)

Die Funktion is.numeric erscheint wie eine Methode numeric(), die einem Object namens is gehört. Jedoch ist dies nicht der Fall. In der R-Pro­gram­mie­rung ist der Punkt ein reguläres Zeichen; die Funktion könnte statt is.numeric auch is_numeric heißen.

Um die in der R-Pro­gram­mie­rung all­ge­gen­wär­ti­gen Vektoren zu erzeugen, kommt die Kon­ka­te­na­ti­ons-Funktion c() zum Einsatz:

people.ages <- c(42, 51, 69)

Wendet man die Funktion auf Vektoren an, werden diese zu einem zu­sam­men­hän­gen­den Vektor zu­sam­men­ge­fügt:

# yields `c(1, 2, 3, 4)`
c(c(1, 2), c(3, 4))

Anders als in den meisten Pro­gram­mier­spra­chen beginnt in R die In­di­zie­rung von Elementen eines Vektors bei 1. Das ist zunächst ge­wöh­nungs­be­dürf­tig, hilft jedoch, die ge­fürch­te­ten Off-by-one-Fehler zu vermeiden. Der höchste Index eines Vektors ent­spricht der Länge des Vektors:

# create a vector of names
people <- c('Jack', 'Jim', 'John')
# access the first name
people[1] == 'Jack'
# access the last name
people[length(people)] == 'John'

Ähnlich wie in Python gibt es auch in der R-Pro­gram­mie­rung das Konzept des Slicings. Mit einer Slice lässt sich ein Teil­be­reich eines Vektors in­di­zie­ren. Dem liegen Sequenzen zugrunde, die in R nativ un­ter­stützt werden. Wir erzeugen eine Sequenz von Zahlen und wählen einen Teil aus:

# create vector of numbers between 42 and 69
nums = seq(42, 69)
# equivalent assignment using sequence notation
nums = 42:69
# using a sequence, slice elements 3 through 7
sliced = nums[3:7]

Wie funk­tio­nie­ren Kon­troll­struk­tu­ren in der R-Pro­gram­mie­rung?

Die grund­le­gen­den Ope­ra­tio­nen in der R-Pro­gram­mie­rung sind für Vektoren definiert. So benötigt man oft keine Schleifen, sondern führt eine Operation direkt auf dem gesamten Vektor durch, wobei die einzelnen Elemente mo­di­fi­ziert werden. Wir qua­drie­ren die ersten zehn positiven Zahlen ohne Schleife:

nums <- seq(10)
squares <- nums ** 2
squares[3] == 9

Beim Einsatz der R For-Loop gilt zu beachten, dass diese nicht so funk­tio­niert wie in C, Java oder Ja­va­Script. Ohne den Umweg über eine Schlei­fen­va­ria­ble wird wie in Python direkt über den Elementen iteriert:

people = c('Jim', 'Jack', 'John')
for (person in people) {
    print(paste('Here comes', person, sep = ' '))
}

Selbst­ver­ständ­lich gibt es die If-else-Ver­zwei­gung in R als grund­le­gen­de Kon­troll­struk­tur. Jedoch lässt sich auch diese in vielen Fällen durch Filter-Funk­tio­nen oder die logische In­di­zie­rung von Vektoren ersetzen. Wir erzeugen einen Vektor mit Al­ters­an­ga­ben und filtern jeweils die über und unter 18-Jährigen in zwei Variablen, ohne eine Schleife oder Ver­zwei­gung zu benötigen:

# create 20 ages between 1 and 99
ages = as.integer(runif(20, 1, 99))
# filter adults
adults = ages[ages > 18]
# filter children
children = ages[ages < 18]
# make sure everyone is accounted for
length(adults) + length(children) == length(ages)

Der Voll­stän­dig­keit halber der äqui­va­len­te Ansatz mit Kon­troll­struk­tu­ren:

# create 20 ages between 1 and 99
ages = as.integer(runif(20, 1, 99))
# start with empty vectors
adults = c()
children = c()
# populate vectors
for (age in ages) {
    if (age > 18) {
        adults = c(adults, age)
    }
    else {
        children = c(children, age)
    }
}

Was wird für den Einstieg in die R-Pro­gram­mie­rung benötigt?

Um mit der R-Pro­gram­mie­rung los­zu­le­gen, benötigt man lediglich eine lokale R-In­stal­la­ti­on. Es stehen Installer für alle großen Be­triebs­sys­te­me zum Download bereit. Eine Standard-R-In­stal­la­ti­on umfasst einen GUI-In­ter­pre­ter mit REPL, in­te­grier­ter Hilfe und Editor. Für pro­duk­ti­ves Coden sollte man auf einen der eta­blier­ten Code-Editoren zu­rück­grei­fen. Mit R-Studio steht eine at­trak­ti­ve Al­ter­na­ti­ve zu R-Umgebung bereit.

Für welche Projekte eignet sich R?

Besonders häufig findet die R-Pro­gram­mie­rung Anwendung in Wis­sen­schaft und Forschung, etwa in der Bio­in­for­ma­tik und beim ma­schi­nel­len Lernen. Jedoch eignet sich die Sprache für alle Projekte, die sta­tis­ti­sche Mo­del­lie­run­gen oder ma­the­ma­ti­sche Modelle nutzen. Schwach ist R lediglich für reine Text­ver­ar­bei­tung; hier hat Python klar die Nase vorn.

Die üblichen Be­rech­nun­gen und Vi­sua­li­sie­run­gen in Ta­bel­len­kal­ku­la­tio­nen lassen sich durch R-Code ersetzen. Dabei pro­fi­tiert man von einer sauberen Trennung der Belange, denn Daten und Code werden nicht in Zellen vermischt. So lässt sich Code einmal schreiben und auf mehrere Da­ten­sät­ze anwenden. Ferner gibt es so keine Gefahr, die Formel einer Zelle bei manuellen Än­de­run­gen zu über­schrei­ben.

Für wis­sen­schaft­li­che Pu­bli­ka­tio­nen gilt R als Gold­stan­dard. Die Trennung von Code und Daten er­mög­licht erst die wis­sen­schaft­li­che Re­pro­du­zier­bar­keit. Das aus­ge­reif­te Ökosystem aus Tools und Paketen erlaubt die Er­stel­lung ef­fi­zi­en­ter Pu­bli­ka­ti­ons-Pipelines. Aus Code und Daten werden au­to­ma­ti­siert Aus­wer­tun­gen und Vi­sua­li­sie­run­gen erzeugt und in hoch­qua­li­ta­ti­ve LaTeX- oder RMarkdown-Dokumente ein­ge­bun­den.

Tipp

Die perfekte Basis, für Ihre Website: Jetzt günstigen Webspace kaufen bei IONOS!

Zum Hauptmenü