Einführung in R


Letzte Änderung am 03. Februar 2021


Einleitung

R ist eine kostenlose und quelloffene Statistiksoftware, die in Wissenschaft und Wirtschaft genutzt wird. Wir finden in R eine Fülle an Funktionen, die uns (statistische) Berechnungen und grafische Visualisierungen ermöglichen.

R ist die grundlegende Software, die unsere Berechnungen anstellt. RStudio ist eine zusätzliche Entwicklungsumgebung, die uns die Arbeit mit R vereinfacht.

Im Verlauf dieses Kapitels lernen wir, was Funktionen und Pakete sind und wie wir diese in R nutzen. Danach schauen wir uns an, wie wir Daten speichern, um mit ihnen arbeiten zu können. Am Ende des Kapitels finden wir wesentliche Kurzbefehle für Windows und Mac und weiterführende Hilfen.

exclamation Voraussetzung zur Bearbeitung des Kapitels ist, dass wir (zumindest) R installiert haben.

Weiterführend ist es sinnvoll, sich die Einführung in RStudio anzuschauen.

1. Funktionen & Pakete

Fangen wir damit an, was Funktionen und Pakete sind, warum wir diese nutzen und wie wir diese in R anwenden können.

exclamation Alles, was wir in einer Zeile hinter eine Raute (#) schreiben, wird nicht als Funktion, sondern als Kommentar interpretiert. Unseren Code zu kommentieren ist sehr nützlich, da es uns und Anderen die Nachvollziehbarkeit unseres Vorgehens erleichtert.

Funktionen

Funktionen sind (Unter)Programme, die eine gewisse Funktionalität haben, d.h. eine bestimmte Aufgabe ausführen.

Warum ist es sinnvoll, Funktionen zu nutzen?

Wenn wir beispielsweise den Mittelwert einer Zahlenreihe errechnen wollen, nutzen wir folgenden Code:

# Mittelwert der Zahlenreihe selbst berechnen
(4+3+6+2+3)/5
[1] 3.6

Dabei müssen wir die Zahlen aufsummieren und durch deren Anzahl teilen. Wenn wir weiter mit der Zahlenreihe arbeiten wollen, müssen wir sie außerdem wieder eingeben.

Viel einfacher können wir die Aufgabe ausführen indem wir vorgefertigte Funktionen nutzen.

# Zahlenreihe (Vektor) erstellen
nums <- c(4, 3, 6, 2, 3)
nums
[1] 4 3 6 2 3
# Mittelwert errechnen lassen
mean(x = nums)
[1] 3.6

Wir können Funktionen variierenden Input übergeben. Dieser steht immer in Klammern direkt hinter der Funktion. Beispielsweise könnten wir auch den Mittelwert einer anderen Zahlenreihe als nums berechnen.

Den Input übergeben wir an einen Parameter. Das ist eine (formale) Variable einer Funktion (z.B. mean(x)), die in der Funktionsdefinition festgelegt ist. Der tatsächliche Input nennt sich Argument (z.B. mean(x = nums)). Die Parameter einer Funktion werden mit Kommata getrennt. Schematisch sieht eine Funktion somit folgendermaßen aus: function(parameter_1 = argument_1, parameter_2 = argument_2, …)

Werfen wir einmal einen Blick in die Funktionsdefinition von mean():

Manche Parameter besitzen voreingestellte Argumente (z.B. na.rm=FALSE); diese bezeichnet man als Defaults. Funktionen mit (min. einem) Parameter ohne Default (z.B. mean()) werden ohne Spezifikation dieser nicht ausgeführt. Beispielsweise müssen wir dem Parameter x einen Vektor, von dem wir den Mittelwert berechnen wollen, übergeben.

Parameter ermöglichen uns aber nicht nur, eine Aufgabe mit verschiedenen Daten durchzuführen, sondern auch weitere Optionen zu wählen (z.B. na.rm: Ausschluss von fehlenden Werten; trim: trimmen der Enden der Verteilung der Zahlenreihe vor Berechnung des Mittelwerts).

Wenn unsere Zahlenreihe beispielsweise fehlende Werte (in R: NA) besitzt, müssen wir den Default von mean(..., na.rm=FALSE) ändern, sodass fehlende Werte aus der Berechnung entfernt werden.

# fehlenden Wert hinzufügen
nums <- c(nums, NA)
nums
[1]  4  3  6  2  3 NA
# Mittelwert errechnen lassen
mean(nums) # funktioniert nicht, weil unklar was mit NA passieren soll
[1] NA
mean(nums, na.rm=TRUE) # funktioniert, weil NA aus Berechnung entfernt
[1] 3.6
Wann können wir Parameternamen weglassen (wie bei mean(nums))?

Wir müssen x=nums nicht ausschreiben, weil x der erste Parameter in der Funktionsdefinition ist, und unser Argument num automatisch dem Parameter x zugeordnet wird.

Das funktioniert mit jedem Argument solange wir die Reihenfolge der Parameter in der Funktionsdefinition beachten.

mean(nums, TRUE) 
# funktioniert nicht (wir würden eine Fehlermeldung erhalten), ...
# ... weil trim (und nicht na.rm) an zweiter Stelle steht ...
# ... und trim numerischen Input (eine Zahl zwischen 0 und 0.5) ...
# ... und na.rm logischen Input (TRUE oder FALSE) verlangt
mean(nums, 0, TRUE) 
[1] 3.6

So erleichtern uns Funktionen unsere Arbeit. Zusammengefasst hat die Nutzung von Funktionen folgende Vorteile:

Auf freecodecamp.org finden wir eine kurze Einführung zu R: R Programming Language explained. Es lohnt sich, vertiefend den Part zu Funktionen anzuschauen (~ 10min), um ein besseres Verständnis für die Arbeit mit R zu bekommen.

Pakete

Funktionen (und Dateien) werden in sogenannten Paketen gespeichert. Dabei sind in einem Paket (häufig) Funktionen, die für einen begrenzten Aufgabenbereich genutzt werden.

Es gibt Standardpakete, die man automatisch mit dem Download von R erhält und deren Funktionen und Dateien man einfach nutzen kann. Diese sind base (basale Funktionen wie z.B. c() und mean(), die wir gerade genutzt haben), datasets (Beispieldatensätze), graphics (Grafiken erstellen), grDevices (Farben und Schriften), methods (Methoden und Klassen erstellen bzw. Informationen erhalten), stats (statistische Methoden) und utils (z.B. Informationen zu Add-On Paketen erhalten und diese herunterladen).

Zum Beispiel können wir mit der Funktion data() auf die in datasets enthaltenen Datensatze zugreifen.

data(women) 

Die Größe des Datensatzes sehen wir mit dim().

dim(women)
[1] 15  2

Der Datensatz women enthält 15 Fälle (Zeilen) und zwei Variablen (Spalten).

Die Namen der Variablen erfahren wir mit names().

names(women)
[1] "height" "weight"

Mit den Funktionen aus den Standardpaketen können wir schon vieles machen. Weil R open-source ist, kann jeder eigene Pakete schreiben und Anderen zugänglich machen. Wir können auf diese Add-on Pakete, die andere R-NutzerInnen erstellt haben, über CRAN (Comprehensive R Archive Network) zugreifen. Natürlich können wir selbstgeschriebene Funktionen, die wir häufig nutzen, auch in eigenen Paketen speichern, um sie unkompliziert wieder nutzen zu können oder sie der R-Community zur Verfügung zu stellen.

Add-on Pakete müssen wir einmalig herunterladen und jedes Mal, wenn wir sie (in einer R-Session) nutzen wollen, laden.

Ein bei PsychologInnen beliebtes Paket ist psych. Dieses enthält Funktionen, die häufig in der Persönlichkeitspsychologie und Psychometrie genutzt werden.

Wir können ein Add-on Paket mit folgendem Befehl herunterladen:

install.packages("psych") # auf Anführungszeichen achten!

Die im Paket enthaltene Funktion describe() gibt uns beispielsweise eine kompakte Übersicht relevanter deskriptiv-statistischer Kennwerte von Daten aus.

Wenn wir enthaltene Funktionen nutzen wollen, müssen wir das Paket zuerst laden.

library(psych) # keine Anführungszeichen notwendig
describe(women)
       vars  n   mean    sd median trimmed   mad min max range skew
height    1 15  65.00  4.47     65   65.00  5.93  58  72    14 0.00
weight    2 15 136.73 15.50    135  136.31 17.79 115 164    49 0.23
       kurtosis   se
height    -1.44 1.15
weight    -1.34 4.00

Mit describe erhalten wir folgende Informationen zu jeder Variable im Data Frame bzw. Matrix: Namen, Spaltennummer (vars), Anzahl (gültiger) Fälle (n), Mittelwert (mean), Standarabweichung (sd), Median (median), getrimmter Mittelwert (trimmed), Median Absolute Deviation (mad), Minimum (min), Maximum (max), Schiefe (skew), Exzess (kurtosis) und Standardfehler des Mittelwerts (se).

Wenn wir R bzw. RStudio schließen und erneut öffnen, müssen wir zusätzliche Pakete vor der Nutzung erneut laden.

Für mehr Informationen zu Paketen, u.a. wie wir diese aktualisieren können, schaut euch unser dazugehöriges Kapitel an.

2. Daten

Um zu verstehen, wie R arbeitet, benötigen wir ein Verständnis dafür, wie Daten in R repräsentiert werden. Dazu schauen wir uns drei wichtige Konzepte an: Datentypen, Datenstrukturen und Objekte.

Bevor wir uns die einzelnen Konzepte im Detail anschauen, sehen wir nachfolgend eine Veranschaulichung des Zusammenhangs dieser, um bereits eine grobe Vorstellung zu haben, was uns in den folgenden Abschnitten erwartet.

exclamation Die Gliederung nach “Datentyp” und “Datenstruktur” sind getreu des Manuals von R. Man stößt in anderen Quellen teils auf abweichende Benennungen.

Datentypen

Der Datentyp gibt die Art der Daten an, d.h. welche konkreten Werte(bereiche) die Daten annehmen können und welche Operationen darauf anwendbar sind.

Wir beschäftigen uns in R zumeist mit den folgenden Datentypen: character, logical, integer und double. Die letzten beiden werden (häufig) als numeric zusammengefasst.

Nachfolgend finden wir eine Übersicht dieser Datentypen.

Art der Daten Werte Operationen Datentyp in R
Zeichen(ketten) z.B. “Ball” oder ‘@’ gleich oder ungleich character
Wahrheitswerte TRUE, FALSE (einige) Logische Operatoren logical _
Ganze Zahlen z.B. 2 Arithmetische und Logische Operatoren integer numeric
Kommazahlen z.B. 3.4 double

exclamation Kommazahlen werden mit . und nicht mit , dargestellt, weil Kommata genutzt werden, um Argumente einer Funktion voneinander zu trennen.

Logische Operatoren in R

Ein logischer Operator ist ein Operator, dessen Ergebnis ein Wahrheitswert (logical; TRUE oder FALSE) ist.

Operator Vergleich Beispiel
< kleiner 1 < 1
FALSE
<= kleiner gleich 1 <= 1
TRUE
> größer 2 > 1
TRUE
>= größer gleich 1 >= 3
FALSE
== (genau) gleich TRUE == FALSE
FALSE
!= ungleich TRUE != FALSE
TRUE
! nicht (Negation von Bedingungen) !TRUE
FALSE
| oder || oder 5 > 3 | 5 == 4
TRUE
& oder && und 5 > 3 & 9 < 8
FALSE

Arithmetische Operatoren in R

Über (die meisten) arithmetischen Operatoren sind wir wohl schon zu Grundschulzeiten gestoßen. Das sind Operatoren, die wir zum Rechnen mit Zahlen (numeric) benötigen.

Operator Rechenoperation Beispiel
.+ Addition 1 + 1
2
.- Subtraktion 4 - 3
1
.* Multiplikation 2 * 3
6
/ Division 5 / 3
1.666667
^ oder ** Exponenzieren 8^2
64
%% ganzzahliger Rest bei der Division (Modulo) 5 %% 3
2
%/% ganzzahliger Quotient 5 %/% 3
1

Messniveaus und Datentypen

Recap: Messniveaus

Das Messniveau (oder auch Skalenniveau) ist eine wichtige Eigenschaft von Merkmalen (Variablen) von Untersuchungseinheiten. Es beschreibt, welche Informationen in unseren Messwerten abgebildet werden und damit auch welche mathematischen Transformationen mit den Messwerten sinnvoll sind (z.B. das Berechnen von Mittelwerten). Somit begrenzt das Messniveau auch die zulässigen Datenauswertungsverfahren unserer Variablen.

Die Kodierung von nominalskalierten Merkmalen ist insofern willkürlich, als dass lediglich auf Gleichheit versus Ungleichheit geachtet werden muss (z.B. 1, 4, 9 oder A, Y, M).

Die Kodierung von ordinalskalierten Merkmalen geschieht der Größe nach, d.h. dass die Rangfolge der Kodierungen einzelner Gruppen relevant ist (z.B. 1 < 4 < 9 oder A < M < Y). Man kann aber auch eine eigene Sortierung festlegen, die nicht der “natürlichen” Rangfolge (Zahlen: aufsteigend; Buchstaben: alphabetisch) entspricht (z.B. Y < A < M). Ein Realschulabschluss ist beispielsweise besser als ein Hauptschulabschluss. Wir können aber nicht festlegen, wie viel besser er ist.

Bei der Kodierung von intervallskalierten Merkmalen sind sowohl die Rangfolge als auch die Abstände zwischen den Ausprägungen relevant (z.B. 1, 4, 7; jeweils mit gleichem Abstand zueinander; oder 1.4, 1.5, 2.3; jeweils mit verschiedenen Abständen zueinander). Ein Beispiel dafür ist die Temperatur in Grad Celsius oder Grad Fahrenheit.

Bei der Kodierung von verhältnisskalierten Merkmalen ist zusätzlich noch ein Nullpunkt vorhanden. Dieser erlaubt es, dass Quotienten zwischen Werten gebildet werden können. Ein beliebtes Beispiel ist die Kelvin Skala. Bei dieser ist bei 0°K keine Bewegungsenergie mehr vorhanden und 20°K sind halb so viel wie 40°K.

Zu guter Letzt gibt es noch absolutskalierte Merkmale, welche sowohl einen eindeutigen Nullpunkt als auch eine eindeutige Einheit der Skala (z.B. Anzahl der Kinder) vorweisen kann. Die Kodierung entspricht der natürlichen Einheit.

Nachfolgend finden wir eine Tabelle der möglichen Unterscheidungen der jeweiligen Messniveaus.

(Un-) Gleichheit Rangordnung Abstände Verhältnisse natürliche Einheit
Nominal X
Ordinal X X
Intervall X X X
Verhältnis X X X X
Absolut X X X X X

Bildquelle: https://de.wikipedia.org/wiki/Datei:Skalenniveau.png

Die verschiedenen Messniveaus können mit unterschiedlichen Datentypen repräsentiert werden. Hauptsächlich nutzt man dafür character und numeric. Nachfolgend finden wir eine Übersicht der möglichen Kodierungen der Messniveaus.

_
Art der Skala:
Nominal- Ordinal- Intervall- Verhältnis- Absolut-
Datentyp: character X X\(^2\)
numeric X\(^1\) X\(^2\) X X X
\(^1\) Faktorisieren (unordered factor) notwendig wenn keine Indikatorvariable(n) genutzt \(^2\) Faktorisieren (ordered factor) notwendig
Können Merkmale auch mit logical kodiert werden?

Wir könnten auch logische Werte nutzen, um Merkmale zu kodieren, allerdings kann es sich dabei nur um dichotome nominalskalierte Merkmale handeln (d.h. diese können nur zwei diskrete Ausprägungen besitzen).

Logische Werte und Operatoren kommen hauptsächlich in der Indexierung von Vektoren (diese lernen wir im nächsten Abschnitt kennen) …

x <- c(7,4,3,6,1) # Vektor x erstellen
x
[1] 7 4 3 6 1
# Welche Elemente in Vektor x sind größer als 5? 
x > 5 # Output: logischer Vektor (mit T/F zu jedem Element) ...
[1]  TRUE FALSE FALSE  TRUE FALSE
x[x > 5] # ... den wir auf x anwenden können, um die Elemente zu erhalten.
[1] 7 6

… und der konditionalen Programmierung vor.

for (i in 1:length(x)) { # Für jedes Element in x, begonnen bei 1 ...
  if (x[i] > 5) {         # ... wenn i-tes Element in x größer als 5 ...
    x[i] = x[i] * 2         # ... multipliziere Element mit 2
  }
}
x
[1] 14  4  3 12  1

Damit werden wir uns erst später beschäftigen. Anwendung findet die konditionale Programmierung z.B. wenn wir subsetten, d.h. Elemente, auf die eine Kondition (z.B. größer als 5) zutrifft, einer Datenstruktur (z.B. Vektor, Matrix, Dataframe) entnehmen wollen.

Datenstrukturen

Die Datenstruktur bestimmt die Organisation und Speicherung von Daten(typen), und folglich auch, welche Funktionen wir anwenden können.

Datenstrukturen können nach Dimensionalität und enthaltenen Datentypen klassifiziert werden. Nachfolgend befindet sich eine Übersicht der in R enthaltenen Datenstrukturen.

_
Beinhaltet unterschiedliche Datentypen?
nein (homogen) ja (heterogen)
Anzahl der Dimensionen 1 Vektor Liste
2 Matrix Data Frame
n Array

Vektor

Vektoren sind die elementare Datenstruktur, aus der sich alle anderen Datenstrukturen zusammensetzen. Sie besitzen nur eine Dimension. Mit c() können wir Vektoren erstellen.

Generell können sie unterschiedlichen Typs sein …

vek_1 <- c("A", 'B')  # egal ob " oder ' 
vek_2 <- c(F, T, T)  # Abkürzung von FALSE und TRUE

… aber ein Vektor kann nur einen Datentyp beinhalten.

vek_3 <- c(1, "3")  # alles wird zu character

Zahlen können wir auf unterschiedliche Weisen speichern.

vek_4 <- c(1, 2, 3) # ganze Zahlen
vek_5 <- c(1.3, 4.5) # Kommazahlen
vek_6 <- c(1L, 4L) # ganze Zahlen

Mit str() können wir uns den Datentyp, die Länge der Dimension (Anzahl der Elemente) und die ersten 10 Elemente ausgeben lassen.

str(vek_1)
 chr [1:2] "A" "B"
# chr --> Datentyp character
# [1:2] --> enthält zwei Elemente
# "A" "B" --> ersten zwei (von max. 10) Elementen
str(vek_2)
 logi [1:3] FALSE TRUE TRUE
str(vek_3)
 chr [1:2] "1" "3"
str(vek_4)
 num [1:3] 1 2 3
str(vek_5)
 num [1:2] 1.3 4.5
str(vek_6)
 int [1:2] 1 4
Warum sind die numerischen Vektoren nur vom Typ numeric oder integer?

Bei Betrachtung der numerischen Vektoren fällt auf, dass vek_4 und vek_5 als numeric und vek_6 als integer gespeichert wurden.

Aber warum wurden vek_4 und vek_5 als numeric gespeichert, obwohl wir integer (ganze Zahlen) bzw. double (Kommazahlen) erwartet hätten?

Das liegt daran, dass R alle Zahlen (d.h. ganze, reelle und komplexe Zahlen) als numeric zusammenfasst (wie bereits in der Einführung zu Datentypen erwähnt), solange wir diese nicht explizit (als integer) definieren.

Genau genommen lautete der exakte Datentyp von ganzen und reellen Zahlen, die als numeric zusammengefasst sind, double. Mit typeof() sehen wir diesen.

typeof(vek_4)
[1] "double"
typeof(vek_5)
[1] "double"

Warum double (und nicht integer)?

Wenn wir arithmetische Operatoren (v.a. Division) anwenden, dann werden unsere ganzen Zahlen zu Kommazahlen. Daher werden ganze und gebrochene Zahlen in numeric “präventiv” als double gespeichert.

Und warum ist vek_6 vom Typ integer?

Hier haben wir mit dem L hinter den (ganzen) Zahlen (c(1L, 4L)) explizit festgelegt, dass wir diese als integer speichern wollen.

Wenn wir integer-Zahlenfolgen erstellen wollen, können wir das auch mit Anfang:Ende machen.

vek_7 <- 2:5
vek_8 <- c(6:9, 1:4)
str(vek_7)
 int [1:4] 2 3 4 5
str(vek_8)
 int [1:8] 6 7 8 9 1 2 3 4

Generell reicht für uns aber die Unterscheidung zwischen numeric und den anderen, nicht-numerischen Datentypen. Ob integer oder double ist zumeist nicht von Relevanz.

Wenn wir Zahlenfolgen (numeric) erstellen wollen, können wir seq() nutzen.

# seq(from,to,by)
vek_9 <- seq(1,10,2)
vek_10 <- seq(1,10,0.5)
str(vek_9)
 num [1:5] 1 3 5 7 9
str(vek_10)
 num [1:19] 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 ...

Wenn wir wollen, dass sich Elemente wiederholen, können wir die Funktion rep() nutzen.

# rep(x, times)
vek_11 <- rep("A", 10)
vek_12 <- c(rep(1, 3), rep(2:3, 3))
str(vek_11)
 chr [1:10] "A" "A" "A" "A" "A" "A" "A" "A" "A" "A"
str(vek_12)
 num [1:9] 1 1 1 2 3 2 3 2 3
Wie genau funktioniert rep()?

Dem Parameter x übergeben wir die Zeichen(folge), die wir wiederholen wollen; times übergeben wir die Anzahl der Wiederholungen der Zeichenfolge bzw. each die Anzahl der Wiederholungen der einzelnen Zeichen.

Die Zahl 1 wird 10 mal (times) wiederholt:

rep(1, 10) # das gleiche wie: rep(x=1, times=10)
 [1] 1 1 1 1 1 1 1 1 1 1

Die Zahlenfolge 0, 1 bzw. die Zeichenfolge "A", "B wird 10 mal (times) wiederholt:

rep(0:1, 10)
 [1] 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
rep(c("A", "B"), 10)
 [1] "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B" "A" "B"
[17] "A" "B" "A" "B"

Wenn wir erst 10 mal die 0 bzw. "A" und anschließend 10 mal die 1 bzw. "B" haben wollen, nutzen wir den Parameter each.

rep(0:1, each=10) # das gleiche wie c(rep(0, 10), rep(1, 10))
 [1] 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
rep(c("A", "B"), each=10)
 [1] "A" "A" "A" "A" "A" "A" "A" "A" "A" "A" "B" "B" "B" "B" "B" "B"
[17] "B" "B" "B" "B"

Durch Indexierung via [] können wir uns einzelne Elemente ausgeben lassen.

vek_1[2] # zweites Element
[1] "B"
vek_5[1] # erstes Element
[1] 1.3

Spezialfall Faktor

Ein Faktor ist ein spezieller Vektor, der genutzt wird, um diskrete Klassifikationen zu kodieren.

Mit der Funktion factor() können wir Vektoren in ungeordnete und geordnete Faktoren umwandeln.

Unsortierte Faktoren können nominalskalierte Merkmale kodieren.

# Vektor erstellen
x <- c(1,3,2,3,2)
y <- c("f", "B", "c", "b", "c")

nominal_x <- factor(x)
nominal_y <- factor(y)
str(nominal_x)
 Factor w/ 3 levels "1","2","3": 1 3 2 3 2
str(nominal_y)
 Factor w/ 4 levels "b","B","c","f": 4 2 3 1 3

Die Zahlen hinter den Ausprägungen zeigen die interne Kodierung. Bei numerischen Vektoren wie nominal_x entsprechen diese auch den möglichen Ausprägungen.

Sortierte Faktoren können ordinalskalierte Merkmale kodieren. Um Faktoren zu sortieren, müssen wir dem Parameter ordered das Argument TRUE übergeben.

ordinal_x <- factor(x, ordered=TRUE)
ordinal_y <- factor(y, ordered=TRUE)
str(ordinal_x)
 Ord.factor w/ 3 levels "1"<"2"<"3": 1 3 2 3 2
str(ordinal_y)
 Ord.factor w/ 4 levels "b"<"B"<"c"<"f": 4 2 3 1 3

Wie wir sehen wurde automatisch eine Sortierung festgelegt. Zahlen werden standardmäßig aufsteigend; Zeichen alphabetisch sortiert (wobei Kleinbuchstaben vor Großbuchstaben auftauchen). Bei den unsortierten Faktoren gab es diese Sortierung auch bereits, allerdings wird diese nur zum Darstellen der Ausprägungen genutzt (bei nominal_ sind die Ausprägungen mit , getrennt; bei ordinal_ mit <).

Mit dem Parameter levels können wir auch eigene Sortierungen festlegen. Das übergebene Argument muss selbst ein Vektor mit den möglichen Ausprägungen sein.

ordinal_x.2 <- factor(x, ordered=TRUE, levels=c(3,2,1))
ordinal_y.2 <- factor(y, ordered=TRUE, levels=c("B", "f", "b", "c"))
str(ordinal_x.2)
 Ord.factor w/ 3 levels "3"<"2"<"1": 3 1 2 1 2
str(ordinal_y.2)
 Ord.factor w/ 4 levels "B"<"f"<"b"<"c": 2 1 4 3 4

Jetzt sehen wir auch, dass sich (mit einer anderen als der natürlichen Sortierung) auch die internen Kodierungen geändert haben.

Matrix

Matrizen sind zweidimensionale Vektoren, die nur einen Datentyp beinhalten können. In mathematischen Kontexten werden Matrizen uns häufiger begegnen.

Wir erstellen sie mit matrix(data, nrow, ncol).

mat_1 <- matrix(data=c(1,2,3,4), # Daten-Vektor
                nrow=2, # Anzahl Zeilen
                ncol=2, # Anzahl Spalten
                # eine Angabe (Zeilen oder Spalten) reicht auch
                byrow=TRUE) # reihenweise Eintragen der Daten
mat_1
     [,1] [,2]
[1,]    1    2
[2,]    3    4
str(mat_1) # [Länge Zeilen, Länge Spalten]
 num [1:2, 1:2] 1 3 2 4

Wenn wir einzelne Elemente indexieren wollen, müssen wir zwei Indizes angeben, weil Matrizen zweidimensional sind.

# [Zeile, Spalte]
mat_1[1,2] # Zeile 1, Spalte 2
[1] 2
mat_1[2,1] # Zeile 2, Spalte 1
[1] 3

Wir können auch nur einen Index angeben, um uns die komplette Zeile bzw. Spalte ausgeben zu lassen. Dabei müssen wir aber daran denken, das Komma zu setzen!

mat_1[1,] # komplette erste Zeile
[1] 1 2
mat_1[,2] # komplette zweite Spalte
[1] 2 4

Zusätzlich können wir die Spalten und Zeilen von Matrizen benennen.

colnames(mat_1) <- c("A", "B") # Spalten benennen
rownames(mat_1) <- c("Vpn_1", "Vpn_2")
mat_1
      A B
Vpn_1 1 2
Vpn_2 3 4

Liste

Listen bestehen aus geordneten Sammlungen von Objekten (Komponenten) unterschiedlichen Datentyps. Diese Objekte können wiederum selbst Vektoren, Matrizen oder Dataframes sein. Listen haben nur eine Dimension.

Mit list() können wir eigene Listen erstellen.

list_kurs <- list(kurs="Programmieren",
                  teilnehmer=3,
                  namen.teilnehmer=c("Tina", "Paul", "Lena"),
                  vorerfahrung=c(T, F, F))
list_kurs
$kurs
[1] "Programmieren"

$teilnehmer
[1] 3

$namen.teilnehmer
[1] "Tina" "Paul" "Lena"

$vorerfahrung
[1]  TRUE FALSE FALSE
str(list_kurs) # "List of ..." gibt die Länge der (einen) Dimension der Liste an
List of 4
 $ kurs            : chr "Programmieren"
 $ teilnehmer      : num 3
 $ namen.teilnehmer: chr [1:3] "Tina" "Paul" "Lena"
 $ vorerfahrung    : logi [1:3] TRUE FALSE FALSE

Wir können Komponenten bzw. ihre Elemente auf verschiedene Arten indexieren.

list_kurs[3] # Name und Elemente der dritten Komponente
$namen.teilnehmer
[1] "Tina" "Paul" "Lena"
list_kurs[[3]] # nur Elemente der dritten Komponente
[1] "Tina" "Paul" "Lena"
list_kurs[[3]][2] # zweites Element der dritten Komponente
[1] "Paul"

Wir können alle Elemente einer Komponente ebenso mit ihren Namen extrahieren.

list_kurs$vorerfahrung
[1]  TRUE FALSE FALSE

Listen werden uns häufiger als Output statistischer Funktionen begegnen.

Data Frame

In der Psychologie arbeiten wir zumeist mit Data Frames. Diese haben, wie Matrizen, zwei Dimensionen, aber sie können auch unterschiedliche Datentypen beinhalten.

Um Data Frames zu erstellen, spezifizieren wir zuerst Vektoren (unterschiedlichen Typs) und führen diese dann mit data.frame() zusammen.

# Vektoren erstellen: 
eins <- c(1, 3, 2, 1) 
zwei <- c("A", "A", "B", "B")

# in Data Frame zusammenführen
df_1 <- data.frame(eins, zwei)
df_1
  eins zwei
1    1    A
2    3    A
3    2    B
4    1    B
str(df_1) # obs. = Länge Zeilen, variables = Länge Spalten
'data.frame':   4 obs. of  2 variables:
 $ eins: num  1 3 2 1
 $ zwei: chr  "A" "A" "B" "B"

Die Benennung der Vektoren wird als Spaltenbenennung übernommen. Per Default werden Daten vom Typ character (z.B. zwei) als Faktoren gespeichert (stringsAsFactors = default.stringsAsFactors(), was wiederum TRUE ist).

Mit colnames() bzw. rownames() können wir wieder Spalten- bzw. Zeilennamen ändern bzw. hinzufügen.

colnames(df_1) <- c("AV", "UV")
rownames(df_1) <- c("Fall_1", "Fall_2", "Fall_3", "Fall_4")
# mit data.frame(..., row.names) könnten wir auch initial Zeilennamen übergeben
df_1
       AV UV
Fall_1  1  A
Fall_2  3  A
Fall_3  2  B
Fall_4  1  B

Wir können mit Indexieren wieder einzelne Elemente oder Spalten bzw. Zeilen extrahieren. Spalten bzw. Zeilen können wir hier auch mit ihren Namen ansprechen.

df_1[3,2] # dritte Zeile, zweite Spalte
[1] "B"
df_1["Fall_3", "UV"] # dritte Zeile, zweite Spalte
[1] "B"
df_1[1,] # erste Zeile
       AV UV
Fall_1  1  A
df_1["Fall_1",] # erste Zeile
       AV UV
Fall_1  1  A

Spalten können wir uns auch mit dem $-Operator ausgeben lassen mit der Form df_name$spalten_name.

df_1$AV
[1] 1 3 2 1

Einige Funktionen verlangen Data Frames als Input. Wir können z.B. Matrizen mittels as.data.frame() in Data Frames umwandeln.

Objekte

“Everything that exists in R is an object”
- John Chambers (Entwicklungsteam von R)

R arbeitet mit sogenannten Objekten. Alle Entitäten, mit denen wir in R operieren, sind Objekte. So sind alle Datenstrukturen, die wir gerade kennengelernt haben, Objekte sobald wir ihnen einen Namen zugewiesen haben.

Um ein Objekt zu erstellen, nutzen wir den Zuweisungspfeil <-.

obj <- c(1, 2, 3)

Wir können uns Objekte anschauen, indem wir ihren Namen ausführen oder indem wir View() nutzen. Zweiteres öffnet das Objekt im Data Viewer (in RStudio).

obj
[1] 1 2 3

Alle Objekte, die derzeit in R vorhanden sind, bekommen wir mit ls() angezeigt.

Wenn wir Objekte löschen wollen, nutzen wir rm(). Mit rm(objekt_1, objekt_2>, …) löschen wir einzelne Objekte; mit rm(list = ls()) löschen wir alle.

Zur Benennung von Objekten ist folgendes zu wissen:

3. Weitere Hilfen

Kurzbefehle

Nachfolgend finden wir einige Kurzbefehle für die beiden Betriebssysteme Windows und Mac, die unseren Workflow verbessern.

exclamation Mit dem letzten Kurzbefehl können wir schneller Dateipfade kopieren, was uns das Einlesen von Daten in R erleichtert. Dieser Kurzbefehl ist, im Gegensatz zu den anderen, nicht zur Nutzung in R geeignet; er funktioniert nur im Explorer (Windows) bzw. Finder (Mac).

Windows Mac
Code der aktuellen Linie bzw. markierten Code ausführen Strg + enter cmd + enter
Code bis zur aktuellen Linie ausführen alt + Strg + B alt + cmd + B
Skript speichern Strg + S cmd + S
Dateipfad kopieren shift + Rechtsklick auf Datei
dann Als Pfad kopieren
alt + cmd + C

Eine Übersicht weiterer Kurzbefehle für R finden wir in der Leiste ganz oben unter Help > Keyboard Shortcuts Help (nicht zu verwechseln mit dem Bereich Help, der uns Zugang zur Dokumentation verschafft).

Andere Lernplattformen und Übungen

Wie bereits im Abschnitt Funktionen erwähnt, können wir auf freecodecamp.org eine weiterführende Vertiefung zu Funktionen im gleichnamigen Abschnitt bekommen. Das dauert nur ca. 10min und ist gut investierte Zeit, wenn man wenig Erfahrung mit dem Programmieren hat.

Wenn ihr einen amüsanten Einstieg in R haben wollte, schaut euch YaRrr! The Pirate’s Guide to R (auf englisch) an. Nach einer charismatischen Einführung befinden sich mehrere Abschnitte, teils mit Abschlussübung z.B. zu Skalaren und Vektoren, Vektor-Funktionen, Indexierung, Plotten, uvm..

www.r-exercises.com bietet eine Fülle an Übungen (mit Lösungen) zu verschiedenen Themenbereichen, wie z.B. Vektoren und Data Frames. Mit Ausnahme der mit Protected gekennzeichneten Seiten können wir alle nutzen. Rechts unter Filter by Topic können wir die Themen filtern.

Wenn ihr den Umgang mit R direkt in R lernen wollt, dann schaut euch das Paket swirl an. Es gibt mehrere Kurse mit mehreren kleinen Einheiten zu absolvieren.


Um eine möglichst exakte Replikation der Funktionen zu gewährleisten gibt es im folgenden relevante Angaben zum System (R-Version, Betriebssystem, geladene Pakete mit Angaben zur Version), mit welchem diese Seite erstellt wurde.

R version 4.0.3 (2020-10-10)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.1 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

locale:
 [1] LC_CTYPE=de_DE.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=de_DE.UTF-8        LC_COLLATE=de_DE.UTF-8    
 [5] LC_MONETARY=de_DE.UTF-8    LC_MESSAGES=de_DE.UTF-8   
 [7] LC_PAPER=de_DE.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=de_DE.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
[1] psych_2.0.12     distill_1.2      kableExtra_1.3.1
[4] knitr_1.31      

loaded via a namespace (and not attached):
 [1] rstudioapi_0.13   xml2_1.3.2        magrittr_2.0.1   
 [4] mnormt_2.0.2      downlit_0.2.1     rvest_0.3.6      
 [7] munsell_0.5.0     lattice_0.20-41   colorspace_2.0-0 
[10] viridisLite_0.3.0 R6_2.5.0          rlang_0.4.10     
[13] fansi_0.4.2       highr_0.8         stringr_1.4.0    
[16] httr_1.4.2        tools_4.0.3       grid_4.0.3       
[19] parallel_4.0.3    webshot_0.5.2     nlme_3.1-149     
[22] tmvnsim_1.0-2     xfun_0.20         selectr_0.4-2    
[25] htmltools_0.5.1.1 yaml_2.2.1        digest_0.6.27    
[28] lifecycle_0.2.0   vctrs_0.3.6       glue_1.4.2       
[31] evaluate_0.14     rmarkdown_2.6     stringi_1.5.3    
[34] compiler_4.0.3    scales_1.1.1     

Für Informationen zur Interpretation dieses Outputs schaut auch den Abschnitt Replizierbarkeit von Analysen des Kapitels zu Paketen an.

jump-to-top

feedback-r-lernplattform