Skip to Tutorial Content
Einstellungen für Barrierefreiheit

R und RStudio Installation

Logo

1. R Installation


RStudio Logo

2. RStudio Installation

Übungen

Aufgabe:

  1. Installiere R und RStudio auf deinem Rechner.

  2. Öffne Rstudio, um zu prüfen, ob die Installation erfolgreich war.

RStudio Einstieg

Kapitel

Console
Environment
Files
R Skripte

RStudio ist eine sogenannte integrated development environment (IDE), also eine Entwicklungsumgebung für die Programmiersprache R. Grundsätzlich sind auch andere IDEs möglich, wir werden in diesem Tutorial jedoch immer davon ausgehen, dass RStudio verwendet wird.

Nachdem RStudio geöffnet wird, sieht es so aus:

Die Console ist in einem Fenster geöffnet. Man kann dort die verwendete R Version “4.2.3” einsehen. Im rechten Drittel des Bildes ist das geöffnete Environment zu sehen. Direkt darunter ist ein weiteres Fenster, über das man zu Files, Plots, Packages, Help und Viewer gelangt.

Aktuell haben wir noch kein Dokument geöffnet. Wir sehen aktuell 3 separierte Bereiche bzw. Fenster.

Console

Die Console ist geöffnet.

In der Console können R Befehle direkt ausgeführt werden. Dies ist praktisch für kleine Taschenrechner-Befehle oder kleine Tests. Der Nachteil ist jedoch, dass die R Befehle nicht gespeichert werden können. Dafür wird ein R Skript benötigt.

Die Console ist geöffnet. Es werden beispielhafte Taschenrechner-Befehle ausgeführt, z. B. 5*6 = 30

Environment

Das Environment ist geöffnet. Im Environment steht Folgendes: Environment is empty. Über denselben Reiter kann man zu History, Connections und Tutorial gelangen.

Das Environment ist zu Beginn einer R Session leer. Wenn wir jedoch Variablen speichern oder Datensätze einladen, werden diese Objekte hier angezeigt.

Das Environment ist geöffnet und nicht mehr leer. Es werden gespeicherte Variablen und Datensätze angezeigt (z.B. data.frame und list).

Files

Das Fenster „Files“ ist geöffnet. Dort befinden sich zwei Dokumente (.Rhistory und project.Rproj).

Je nachdem, wo die working directory gesetzt ist, werden hier unterschiedliche Dokumente und Ordner angezeigt.

R Skripte

Wenn ein R Skript geöffnet wird, wird ein weiteres Fenster für das Skript angezeigt. In einem R Skript kann Code abgespeichert werden.

Übungen

  1. Öffne RStudio.

  2. Tippe in die Console eine einfache Rechenaufgaben und drücke “Enter”, um dir das Ergebnis anzeigen zu lassen.

  3. Tippe "Hallo Welt" (mit den Anhührunsgzeichen) in die Console und drücke auf “Enter”.

R Skript

Kapitel

Kommentare
Neues R Skript öffnen

In einem R Skript kann Code abgespeichert werden.

Ein R Skript, in dem sich ein Code befindet, ist geöffnet.

Kommentare

Grundsätzlich wird jeder Befehl und jedes Zeichen als R Code verstanden. Wenn man einen Kommentar schreiben möchte, muss man in jeder Zeile eine # davor setzen.

Ein R Skript, in dem sich ein Code befindet, ist geöffnet. Man sieht, dass ein Kommentar durch eine Raute am Zeilenanfang gekennzeichnet wird.

Code wird ausgeführt, indem der gewünschte Bereich markiert und dann auf den Run-Button geklickt wird. Es kann hier der gesamte Code markiert werden, aber auch einzelne Zeilen oder sogar nur einzelne Befehle.

Ein R Skript, in dem sich ein Code befindet, ist geöffnet. Der Code wurde blau markiert, dann wird auf den Run-Button geklickt, um den markierten Codeabschnitt auszuführen.

Die Tastenkombination für Run ist unter Windows Str + Enter und unter macOS Cmd + Enter.

Neues R Skript öffnen

Ein neues, leeres R Skript wird über diesen Button geöffnet:

Ein neues, leeres R Skript wird über die RStudio Oberfläche über ein grün-weißes Plus-Symbol geöffnet. Dieses befindet sich oben links.

Man erhält eine große Anzahl an möglichen Formaten, unter anderem auch ein R Skript.

Nachdem das Symbol mit dem grünen Kreis und dem weißen Plus gedrückt wurde, öffnen sich weitere Auswahlmöglichkeiten. Die oberste Leiste mit dem Titel „R Script - Create a new R script“ wird ausgewählt.

Das neu geöffnete R Skript sieht nun so aus und kann direkt mit dem Disketten-Symbol abgespeichert werden.

Ein neues, leeres R Skript ist geöffnet. Das zum Speichern geeignete blaue Disketten-Symbol befindet sich über der ersten Zeile.

Übungen

  1. Erstelle ein neues R-Skript und speichere es in einem Ordner ab.

  2. Schreibe einen Kommentar in das R-Skript.

  3. Schreibe eine einfache Rechenoperation in das R-Skript.

  4. Schreibe print("hallo Welt!")in das R-Skript.

  5. Führe das R Skript aus und schaue Dir den Output in der Console an.

RStudio vs otter

Die otter Tutorials sind alle interaktiv gestaltet. Damit wir dir Feedback geben können und du nicht immer zwischen RStudio und unserer Website wechseln musst, sind R-Bausteine eingebaut. Siehe dir die folgenden Bilder und Aufgaben an, um zu verstehen, wie in unseren Tutorials R eingebaut ist.

Zu sehen sind zwei Screenshots nebeneinander. Der linke Screenshot zeigt ein geöffnetes R-Skript. Der rechte Screenshot zeigt die Konsolen Ausgabe nach dem Ausführen des R-Skriptes in RStudio. Das R-Skript in R-Studio sowie der Konsolen-Output sind identisch mit den darunter stehenden Übungsaufgaben, die in Otter zu sehen sind. Daraus kann gefolgert werden, dass R-Studio-Umgebungen in Otter integriert sind und denselben Output ergeben.

Übungen

So sieht derselbe R Code in unserem Tutorial-Format aus:

Aufgabe: Klicke auf den Button “Code ausführen” und vergleiche die Ausgabe mit den obrigen Bildern.
5*5

# Dies ist ein Kommentar

print("Hallo Welt!")

Versuche Dich nun selbst!

Aufgabe: Berechne 84 * 15. Gebe dazu die Berechnung in den R Code Bereich ein und klicke auf “Code ausführen”

Datentypen

Kurze Zusammenfasssung

  • Logical: TRUE, FALSE
  • Integer: Ganze Zahlen (Platz speichernd)
  • Double: Kommazahlen
  • Character: Buchstaben

Logical

Werte: TRUE (entspricht 1) und FALSE (entspricht 0)

Kann aufsummiert werden:

TRUE + TRUE 
FALSE + FALSE
TRUE + FALSE 

Logische Operatoren können angewandt werden

FALSE & TRUE
FALSE | TRUE
5 < 10

Logische Operatoren

Symbol Bedeutung
< kleiner als
> größer als
== gleich
!= ungleich
| oder
& und
! Negierung

Mit logischen Operatoren können logische Prüfungen auf Objekte (Variablen, Vektoren, Datensätze, …) angewandt werden. Als Ergebnis wird immer der Datentyp logical ausgegeben.

buchstaben <- c("A", "B", "C", "D", "C")
zahlen <- c(18, 22, 16, 20)

# Welche Buchstaben sind C?
buchstaben == "C"

# Welche Zahl ist größer als 20?
zahlen > 20

Übungen

Vorbereitung:

namen <- c("Lisa Müller", "Peter Bauer", "Hannah Schmidt")
angemeldet <- c(TRUE, FALSE, TRUE)
alter <- c(18, 22, 16)

Aufgabe: Beantworte die gestellte Frage mit R Code.

# Wer von den Personen heißt NICHT Lisa Müller?
# namen ____ "Lisa Müller"
# !=
# Wer von den Personen heißt NICHT Lisa Müller?
namen != "Lisa Müller"
Aufgabe: Beantworte die gestellte Frage mit R Code.
# Wer von den Personen ist jünger als 18 Jahre?
# Wer von den Personen heißt NICHT Lisa Müller?
alter < 18

Integer

integer-Zahlen sind Ganzzahlen in R. Sie sind platzsparender als double-Zahlen, da Kommas ausgeschlossen sind. R geht zuerst immer davon aus, dass es sich um double-Zahlen handelt, somit müssen integer-Zahlen explizit definiert werden.

Hier gibt es zwei Möglichkeiten:

  • L muss direkt dahinter gesetzt werden, z.B. 2L
  • : ermöglicht schnell eine Folge an integer-Zahlen zu generieren, z. B. 1:3 erzeugt die Zahlen von 1 bis 3 in Einer-Schritten
1L
1:10
10:1

Mit der Funktion is.integer() können wir prüfen, ob es sich um integer-Zahlen handelt oder nicht.

is.integer(1)
is.integer(1L)

Double

double-Zahlen sind sogenannte Gleitkommazahlen. Diese Zahlentypen werden für normale Berechnungen verwendet

  • Kommazahlen
  • Sonderfälle
    • Inf Positive Unendlichkeit
    • -Inf Negative Unendlichkeit
    • NaN Not a Number (Fehlender Wert im Datensatz)
8/5
4.44 + 2.1

Mit der Funktion typeof() können wir abfragen, um welchen Datentyp es sich handelt.

typeof(5)

Übungen

Aufgabe: Erzeuge einen integer-Vektor von 5 bis 12 in Einer-Schritten
5:12
Aufgabe: Welcher Datentyp hat die Zahl 78? Nutze zur Beantwortung der Frage eine Funktion.
typeof(78)
Aufgabe: Was passiert, wenn man in R durch Null teilt? Probiere es aus!
1/0

Character

Text, Symbole oder auch Farben werden im Datentyp character gespeichert.

Text muss in "" gesetzt werden.

Dies ist ein Beispiel für Text.
"Hallo Welt"
Text wird häufig als Funktionsargument verwendet, weil hier auch alle Zeichen abgebildet werden können, z. B. um Symbole anzuzeigen. (Die Icons stammen von fontawesome.)
shiny::icon("rocket")
shiny::icon("star")

Oder auch für Hexcode, um Farben zu definieren.

scales::show_col(c("#044a85", "#e28743", "#1F98B44D", "#1F98BC"))

Übungen

Aufgabe: Gebe Dir den Text “Hallo liebe R-Freunde” aus.
"Hallo liebe R-Freunde"
Aufgabe: Gebe Dir ein Herz-Symbol aus. Ändere hierzu den Code und nutze den Text "heart".
shiny::icon("plus")
shiny::icon("heart")

Viel Nichts in R

In R gibt es viele Möglichkeiten, um auszudrücken, dass etwas nicht vorhanden ist. Alle Formen von “Nichts” haben eine leicht andere Bedeutung und werden in unterschiedlichen Fällen verwendet oder produziert.

Hier eine (nicht vollständige) Übersicht:

  • NaN: Not a Number (Länge ist 1). Wird verwendet bei invaliden Rechenoperationen.

  • NA: Not Available (Länge ist 1). Wird klassisch für fehlende Werte verwendet.

  • NULL: Repräsentiert das Null-Objekt in R (Länge ist Null). Wird z. B. in Funktionen verwendet für default Argumente.

  • logical(0): Ein logical-Wert der Länge Null.

  • integer(0): Eine integer-Zahl der Länge Null.

  • double(0): Eine double-Zahl der Länge Null.

All diese Werte stellen „nichts” oder „fehlend” dar.

Die Länge dieser Werte unterscheidet sich, so sind manche 0 und andere 1.

length(NaN)
length(NA)
length(NULL)
length(integer(0))
length(double(0))

Bei Berechnungen oder anderen Operationen kann es leicht passieren, dass sich fehlende Werte einschleichen.

Beispiele für die Erzeugung von NaN durch eine Rechenoperation:
0/0

NA tritt meistens auf, wenn ein Datensatz oder eine Variable einen fehlenden Wert enthält. Es ist üblich eine solche fehlende Information mit NA zu speichern.

alter <- c(21, 18, NA, 33, 67, NA)

Infektiöse fehlende Werte

Fehlende Werte wie NaN sind manchmal infektiös!

Bei Rechenoperationen führt z. B. ein NaN dazu, dass das Ergebnis auch ein fehlender Wert ist.

# Eine Variable wird absichtlich oder unabsichtlich zu NaN
variable <- NaN

# Weitere Berechnungen führen auch dazu, dass das Ergebnis zu einem fehlenden Wert wird
variable * 10

# Auch eine logischer Vergleich mit NaN führt hier zu einem fehlenden Wert!
variable == NaN

NaN kann nicht mit == geprüft werden! Es muss mit is.na() geprüft werden.

variable <- NaN
variable == NaN # -> erzeugt NA
is.na(variable) #- > gibt einen logischen Wert aus

Nur der | (oder) Operationen kann auch einen fehlenden Wert bearbeiten, ohne dass daraus ein fehlender Wert wird.

variable <- NaN
variable | TRUE

Übungen

Aufgabe: Prüfe, ob die Variable variable einen fehlenden Wert enthält. Korrigiere dazu den Fehler im Code.
variable <- 0/0
variable == NaN
variable <- 0/0
is.na(variable)

Hilfreiche Funktionen

Erstellen von “Platzhalter-Variablen” eines bestimmten Datentyps:

integer(5)
double(5)
character(5)
logical(5)

Prüfungen, welcher Datentyp vorliegt:

# Erzeugung einer Variable
number = 5

# Prüfung der Variable
is.integer(number)
is.double(number)
is.character(number)
is.logical(number)
is.numeric(number)
# Erzeugung einer Variable
number = 5

# Prüfung von Spezialfällen
is.na(number)
is.finite(number)
is.infinite(number)

Datentyp ändern:

# Erzeugung einer Variable
number = 0
# Änderung des Datentyps
as.numeric(number)
as.integer(number)
as.double(number)
as.character(number) # -> Zahl wird in einen Text verwandelt
as.logical(number) # -> 0 wird zu FALSE

Übungen

Datenstrukturen

Variablen

Variablen sind Container für Daten. Sie zeigen auf ein Objekt im Speicher. Sie müssen ausgeführt werden, um erstellt und genutzt werden zu können. Nach Erstellung taucht die Variable im Environment auf.

Eine Variable kann verschiedene Inhalte enthalten, z. B. eine Zahl, Buchstaben, Matrizen oder Listen.

Der Inhalt einer Variable kann auf die Console geschrieben werden, wenn der Variablenname ausgeführt wird.

name <- "Lara"
name

weiblich <- TRUE
weiblich

lieblingszahl <- 3
lieblingszahl

alter <- NULL
alter

In RStudio ist nach dem Ausführen dieses Codes im Environment Folgendes zu sehen:

Das Environment ist geöffnet. Die gespeicherten Daten (alter = NULL, lieblingszahl = 3, name = “Meike”, weiblich = “TRUE” ) sind zu sehen.

Mit Operatoren können Variablen Inhalte zugewiesen werden. In R gibt es hierfür zwei Zuweisungsoperatoren: <- und =. Wobei es als guter Stil gilt, einheitlich <- zu verwenden.

pfeil_beispiel <- "Pfeil"
pfeil_beispiel

gleich_beispiel = "Gleich"
gleich_beispiel

Der Inhalt von einer Variable kann jederzeit geändert werden. Neue Daten können mit dem Zuweisungsoperator zugewiesen werden. Dadurch werden die alten Daten überschrieben.

# Alte Daten
freunde <- 1:5
freunde

# Neue Daten Variante 1 (anderer Datentyp)
freunde <- c("Lisa", "Thorben", "Mara")
freunde
# Alte Daten
freunde <- c("Lisa", "Thorben", "Mara")
freunde

# Neue Daten Variante 2 (einzelne Daten ändern)
freunde[2] <- "XXXX"
freunde

# Neue Daten Variante 3 (einzelne Daten ändern)
freunde[c(FALSE, TRUE, TRUE)] <- ""
freunde

Daten können auch nachträglich gelöscht werden:

# Entferne den Inhalt an Position 2
freunde <- c("Lisa", "Thorben", "Mara")
freunde <- freunde[-2]
freunde
# Entferne den Inhalt "Thorben"
freunde <- c("Thorben", "Lisa", "Thorben", "Mara", "Thorben")
freunde <- freunde[!freunde == "Thorben"]
freunde

Übungen

Aufgabe: Erstelle ein Variable mit dem Inhalt: Baum, Blume, Haus, Pferd. Und gebe Dir den Inhalt der Variable auf der Console aus.
variable <- c("Baum", "Blume", "Haus", "Pferd")
variable

Atomare Vektoren

Atomare Vektoren können mehrere Informationen desselben Datentyps enthalten.

  • Werden mit c() erstellt (c = combine)
  • Skalare: Vektoren mit nur einer Position
  • „Klassische Vektoren”: Vektoren mit mehr als einer Position
  • Zugriff erfolgt mit Klammern [] und Nummer der Position oder einem Vektor mit TRUE und FALSE Werten.
Beispiel: Zugriff mit []
namen_freunde = c("Lisa", "Thorben", "Mara")
lieblingszahlen_freunde = c(1, 7, 8)
weiblich_freunde = c(TRUE, FALSE, TRUE)

# Zugriff erfolgt mit []
namen_freunde[2]
lieblingszahlen_freunde[2]
weiblich_freunde[c(2, 3)]

Beispiel: Zugriff mit TRUE und FALSE

namen_freunde = c("Lisa", "Thorben", "Mara")
namen_freunde[c(TRUE, TRUE, TRUE)]
namen_freunde[c(TRUE, FALSE, FALSE)]

Übungen

Aufgabe: Ändere den Inhalt der Variable: entferne die Einträge Hund.
blumen <- c("Tulpen", "Rosen", "Hund", "Sonnenblumen", "Hund")
blumen <- c("Tulpen", "Rosen", "Hund", "Sonnenblumen", "Hund")
blumen <- blumen[ !blumen == "Hund"]
blumen
Aufgabe: Ändere den Inhalt der Variable: ersetze die Einträge Hund durch NA.
blumen <- c("Tulpen", "Rosen", "Hund", "Sonnenblumen", "Hund")
blumen <- c("Tulpen", "Rosen", "Hund", "Sonnenblumen", "Hund")
blumen[ blumen == "Hund"] <- NA
blumen

Vektorisierte Berechnungen

Die Berechnungen in R erfolgen vektorisiert. Dies erlaubt effizienteres und leichteres Programmieren bei Rechenoperationen.

Beispiel: Multiplikation eines Vektors mit einem Skalar

# Jede Zahl im Vektor wird hier automatisch mit 5 multipliziert
c(1, 2, 3, 4) * 5

Beispiel: Addition zweier Vektoren

# Die Zahlen auf denselben Positionen werden mit einender addiert
zahlen_1 <- c(0, 0, 1, 1)
zahlen_2 <- c(1, 2, 3, 4)
zahlen_1 + zahlen_2

Beispiel: Logische Operatoren

# Alle Zahlen werden mit dem logischen Operator geprüft
zahlen <- c(0, 1, 2, 3)
zahlen < 2

Übungen

Aufgabe: Addiere auf jedes Element im Vektor die Zahl 3.
zahlen <- 1:100
zahlen <- 1:100
zahlen + 3
Aufgabe: Multipliziere jedes Element im Vektor mit der Zahl 5.
zahlen <- 1:100
zahlen <- 1:100
zahlen * 5
Aufgabe: Multipliziere die zwei Vektoren miteinander.
nummer_1 <- 1:100
nummer_2 <- 100:1
nummer_1 <- 1:100
nummer_2 <- 100:1

nummer_1 * nummer_2

Faktoren

Faktoren repräsentieren kategoriale Daten mit endlichen Ausprägungen, z. B. Tage, Monate im Jahr oder Geschlecht. Damit mit diesen Daten gut gerechnet werden kann in R, werden sie mit Faktoren abgebildet.

Dadurch können kategoriale Daten geordnet werden (hilfreich bei Tagen oder Monaten) oder auch in Zahlen kodierte Daten können inhaltlich sinnvoll abgebildet werden (hilfreich für statistische Auswertungen und Grafiken).

Beispiel: Geschlecht (Daten sind als Zahlen kodiert):

# Die Daten sind hier kodiert mit Zahlen
daten <- c(1,2,3,1,2,1,1,1,1)

# Erstellung eines Faktors
geschlecht <- factor(
  daten,
  # alle möglichen Kategorien (müssen nicht alle vorhanden sein in den Daten)
  levels = c(1, 2, 3, 4), 
  # Namen zugeordnet zu den levels - > für was steht die Zahl 1?
  labels = c("weiblich", "männlich", "divers", "unbekannt")
)

geschlecht

Beispiel: Tage (Daten sind als Text kodiert):

# Die Daten sind hier kodiert als Text
daten <- c("Sonntag", "Montag", "Freitag")

# Erstellung eines Faktors
tage <- factor(
  daten,
  # alle möglichen Kategorien (müssen nicht alle vorhanden sein in den Daten)
  levels = c("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")
)
# Daten ungeordnet
tage

Beispiel: Faktor vs character Vektor

daten <- c("Sonntag", "Montag", "Freitag")
# Daten werden nach dem Alphabet geordnet
sort(daten)

tage <- factor(
  daten,
  levels = c("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag")
)
# Daten werden nach der Reihenfolge der angegebenen levels geordnet
sort(tage)

Übungen

Aufgabe: Erstelle einen Faktor aus der Variable var_monate. Sortiere danach die Monate innerhalb dieser Variable.
# Nutze diese Variablen, um den Faktor zu erstellen
monate <- c("Januar", "Februar", "März", "April", "Mai", "Juni",
            "Juli", "August", "September", "Oktober", "November", "Dezember")
var_monate <- c("Juli", "Mai", "Januar", "November")
monate <- c("Januar", "Februar", "März", "April", "Mai", "Juni",
            "Juli", "August", "September", "Oktober", "November", "Dezember")
var_monate <- c("Juli", "Mai", "Januar", "November")

var_monate <- factor(var_monate, levels = monate)
sort(var_monate)

Matrizen

Sind Tabellen, die aus Vektoren gleicher Länge bestehen.

  • Können nur einen Datentyp enthalten, z.B. numeric

  • R Befehl: matrix()

  • Zugriff erfolgt mit [,], wobei die Positionen für [Zeile,Spalte] stehen.

Beispiel: Matrix Erstellung und Zugriff
matrix <- matrix(1:12, nrow=3, ncol=4)
matrix

matrix[1,2] # Zeile 1 und Spalte 2
matrix[1, ] # Gesamte Zeile 1
matrix[ ,2] # Gesamte Spalte

Übungen

Aufgabe: Erstelle eine Matrix aus der Variable farben. Wähle eine inhaltlich sinnvolle Aufteilung für die Spalten.
farben <- c("rot", "hellrot", "blau", "dunkelblau", "grün", "hellgrün")
farben <- c("rot", "hellrot", "blau", "dunkelblau", "grün", "hellgrün")
farben <- matrix(farben, ncol = 3)
farben
Aufgabe: Wähle die zweite Spalte aus der Matrix aus.
daten <- matrix(c("Lisa", "Thorben", "Mara", "TRUE", "FALSE", "TRUE", "2", "5", "8")
                , ncol = 3)
daten <- matrix(c("Lisa", "Thorben", "Mara", "TRUE", "FALSE", "TRUE", "2", "5", "8")
                , ncol = 3)
daten[, 2]
Aufgabe: Wähle aus der ersten Spalte die dritte Zeile aus.
daten <- matrix(c("Lisa", "Thorben", "Mara", "TRUE", "FALSE", "TRUE", "2", "5", "8")
                , ncol = 3)
daten <- matrix(c("Lisa", "Thorben", "Mara", "TRUE", "FALSE", "TRUE", "2", "5", "8")
                , ncol = 3)
daten[3, 1]

data frame

data.frame ist das Format für den klassischen Datensatz.

  • Besteht aus Spalten gleicher Länge
  • Spalten können verschiedene Datentypen haben.
  • Auf Spalte wird mit $ zugegriffen

Es wird gezeigt, dass mit $ auf Spalten zugegriffen werden kann.

Beispiel: data.frame Erstellung und Zugriff
namen = c("Lisa", "Thorben", "Mara")
lieblingszahlen = c(1, 7, 8)
weiblich = c(TRUE, FALSE, TRUE)

freunde <- data.frame(namen,
                      lieblingszahlen,
                      weiblich)

freunde[2, 3] # zweite Zeile, dritte Spalte im Datensatz
freunde$namen # Im Datensatz die Spalte namen 
freunde$lieblingszahlen[2] # Im Datensatz die Spalte lieblingszahlen, die zweite Position

freunde # gesamter Datensatz anzeigen lassen

Übungen

Aufgabe: Erstelle einen Datensatz tiere aus den Variablen und gebe den Datensatz aus.
tierart <- c("Hund", "Katze", "Maus", "Schlange", "Hund", "Hund", "Katze")
alter <- c(12, 2, 1, 4, 6, 2, 3)
gesund < c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE)
tierart <- c("Hund", "Katze", "Maus", "Schlange", "Hund", "Hund", "Katze")
alter <- c(12, 2, 1, 4, 6, 2, 3)
gesund_status <- c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE)

tiere <- data.frame(
  tierart = tierart,
  alter = alter,
  gesund_status = gesund_status
)
tiere
Aufgabe: Wähle die Spalte zahl aus (verwende dazu den Namen der Spalte).
data <- data.frame(
  buchstabe = c("A", "B", "C", "D", "E", "F", "G"),
  zahl = c(12, 2, 1, 4, 6, 2, 3),
  verwendet = c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE)
)
data <- data.frame(
  buchstabe = c("A", "B", "C", "D", "E", "F", "G"),
  zahl = c(12, 2, 1, 4, 6, 2, 3),
  verwendet = c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE)
)
data$zahl
Aufgabe: Wähle die Spalte buchstabe aus und ersetze den Buchstaben D mit einem X.
data <- data.frame(
  buchstabe = c("A", "B", "C", "D", "E", "F", "G"),
  zahl = c(12, 2, 1, 4, 6, 2, 3),
  verwendet = c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE)
)
data <- data.frame(
  buchstabe = c("A", "B", "C", "D", "E", "F", "G"),
  zahl = c(12, 2, 1, 4, 6, 2, 3),
  verwendet = c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE)
)

data$buchstabe[4] <- "X"

Listen

Listen ermöglichen das Speichern von allen möglichen Datentypen und Datenstrukturen im selben Objekt. Dadurch können sehr flexible und komplexe Strukturen erschaffen werden.

  • Jedes Element kann jeden Datentyp annehmen
  • Eine Liste kann also auch andere Listen enthalten!
  • Listen sind sehr mächtig! Sind aber auch schwerer zu bedienen als Matrizen oder data.frame
Beispiel: Liste Erstellung
variable <- 5

matrix <- matrix(1:12, nrow=3, ncol=4)

datensatz <- data.frame(namen = c("Lisa", "Thorben", "Mara"),
                      lieblingszahlen = c(1, 7, 8),
                      weiblich = c(TRUE, FALSE, TRUE))

liste <- list(matrix, datensatz, variable)

liste

Beispiel: Listen Zugriff

Bei Listen verwendet man im Allgemeinen [[]], um ein einzelnes Element auszuwählen, während [] eine Liste der ausgewählten Elemente zurückgibt. Je nachdem, um was für ein Objekt es sich in der Liste handelt und wie darauf zugegriffen werden soll, müssen somit einfache oder doppelte eckige Klammern verwendet werden.

liste[[1]] # erstes Element der Liste
liste[[2]][1,2] # im ersten Element (Datensatz) die erste Ziele und zweite Spalte
liste[[2]][1,] # im ersten Element (Datensatz) die erste Ziele

Übungen

Aufgabe: Erstelle eine Liste aus den drei Objekten und greife auf das zweite Objekt zu.
m <- matrix(1:12, nrow=3, ncol=4)
df <- data.frame(namen = c("Ben", "Claus", "Lisa"),
                 alter = c(51, 27, 38))
"Object 3"
m <- matrix(1:12, nrow=3, ncol=4)
df <- data.frame(namen = c("Ben", "Claus", "Lisa"),
                 alter = c(51, 27, 38))
liste <- list(m,
              df,
              "Object 3")
liste[[2]]

Funktionen

Funktionen erstellen

Funktionen sind elegante Möglichkeiten, um Code-Abschnitte zu bündeln, zu strukturieren und wiederzuverwenden. Eine Funktion tut irgendetwas mit Daten, Dokumenten, Argumenten etc. Sie können sehr klein, aber auch sehr groß und komplex sein.

double() oder length() sind z. B. Funktionen, die in Base-R vorkommen.

  • Eine Funktion ist in 3 Teile strukturiert:
    • Argumente
    • Körper der Funktion
    • Environment (Umgebung)

Beispiel: Erstellung einer Funktion

function_name <- function(argument) {
  # Körper der Funktion
  # hier passiert nun etwas mit den Argumenten
  return("Output") # Ausgabe des Outputs
}

function_name(argument = "test")

Es gilt als guter Stil return() zu nutzen.

Beispiel: Verwendung von return()
add_numbers <- function(number1, number2) {
  result = number1 + number2
  return(result)
}
add_numbers(5,80)

Es ist aber nicht zwingend erforderlich

Beispiel: ohne return()
add_numbers <- function(number1, number2) {
  number1 + number2
}
add_numbers(5,80)

Beispiel: Mehrere Argumente

namen = c("Lisa", "Thorben", "Mara", "Sophie", "Lara", "Tanja", "Lorenz", "Lena")

read_vector <- function(number, vector) {
  vector[number]
}

read_vector(2, namen)

Beispiel: Default Werte

Optionale Argumente werden mit argument = NULL angegeben
add_numbers <- function(number1 = 1, number2 = 1, argument3 = NULL) {
  number1 + number2
}
add_numbers(5,80)
add_numbers()

Übungen

Aufgabe: Schreibe eine Funktion, die zwei Zahlen addiert. Nutze dazu den bereits angegebenen Code.
rechner <- function() {
  
}
# Teste die Funktion
rechner(8, 5) # Diese Zeile soll nicht verändert werden
rechner <- function(zahl1, zahl2) {
  zahl1 + zahl2
}
rechner(8, 5)
Aufgabe: Schreibe eine Funktion, die zwei Vektoren multipliziert.
# Schreibe hier die Funktion

# Teste die Funktion
vektor_rechner(c(1,2,3), c(3,2,1)) # Diese Zeile soll nicht verändert werden
vektor_rechner <- function(vektor1, vektor2) {
  vektor1 * vektor2
}
vektor_rechner(c(1,2,3), c(3,2,1))

Aufgabe: Schreibe eine Funktion, die den Mittelwert über einen Vektor berechnet und folgende Ausgabe macht: "Mittwelwert = 5.67".

(Es ist 1 Tipp hinterlegt, danach wird die Lösung angezeigt.)
# Schreibe hier die Funktion

# Teste die Funktion
vektor_mittelwert(c(1,2,3, 8, 8, 12)) # Diese Zeile soll nicht verändert werden
# Lösung:
vektor_mittelwert <- function(vektor1) {
  mittelwert <- round(mean(vektor1), 2)
  paste("Mittwelwert =", mittelwert)
}
vektor_mittelwert(c(1,2,3, 8, 8, 12))
# Tipp: Verwende die Funktionen:
round()
mean()

Aufgabe: Schreibe die vorhandene Funktion so um, dass der Code taschen_rechner() die folgende Rechnung ausführt: 1 + 2.

(Es ist 1 Tipp hinterlegt, danach wird die Lösung angezeigt.)
taschen_rechner <- function(zahl1, zahl2, zeichen) {
  text = glue::glue("{zahl1}{zeichen}{zahl2}")
  eval(parse(text = text))
}
# Teste die Funktion
taschen_rechner(4, 5, "+")
taschen_rechner() # Diese Zeile soll nicht verändert werden
taschen_rechner <- function(zahl1 = 1, zahl2 = 2, zeichen = "+") {
  text = glue::glue("{zahl1}{zeichen}{zahl2}")
  eval(parse(text = text))
}
# Teste die Funktion
taschen_rechner(4, 5, "+")
taschen_rechner() # Diese Zeile soll nicht verändert werden
# Tipp: Definiere Default Argumente

Hilfe Seiten

Die Hilfe Seite öffnet sich mit einem ? vor dem Funktionsnamen, z.B. ?mean.

Aufgabe: Gebe ?mean ein und führe den Code aus.

?mean

Die Hilfe sollte immer verwendet werden, bevor man eine neue Funktion verwendet, um sich die Argumente und die Funktionsweise anzuschauen. Häufig werden am Ende auch Beispiele angegeben, die zeigen, wie die Funktion angewandt werden kann.

Die wichtigsten Inhalte in der Hilfe-Seite sind:

  • Description: Eine kurze Beschreibung, was die Funktion tut.

  • Usage: Hier ist die Funktion mit den Pflicht-Argumenten und Default-Werten abgebildet (farbig markiert im Screenshot).

  • Arguments: Eine Liste mit Erklärung der Funktions-Argumente

  • Value: Gibt an, was die Funktion ausgibt

Übersicht über Argumente

  • Pflicht-Argumente werden unter Usage angegeben und keine Default-Werte sind hinterlegt. Im Screenshot ist x ein Pflicht-Argument, welches angegeben werden muss.

  • Optionale-Argumente werden unter Usage angegeben und enden mit = NULL. Diese Argumente sind optional und es ist kein Default-Wert hinterlegt.

  • Default-Werte: alle Argumente, die unter Usage ein = mit Inhalt dahinter angezeigt haben, z.B. trim = 0.

Der Help-Reiter wurde ausgewählt in RStudio. Die Inhalte der mean() Funktion werden wiedergegeben.

Übungen

Aufgabe: Öffne hier die Hilfeseiten der Funktionen, um die folgenden Quiz-Fragen zu beantworten. Probiere auch gerne Code aus, um zu verstehen, wie die Funktionen funktionieren.

Reihenfolge von Argumenten

Die Hilfe-Seite einer Funktion zeigt unter Usage in welcher Reihenfolge die Argumente angegeben werden müssen.

Bei der mean Funktion muss diese Reihenfolge angegeben werden: x, trim, na.rm.

Diese Reihenfolge kann nur geändert werden, wenn die Argumente benannt werden, z. B. trim = 0.1, x = 1:20, na.rm = TRUE.

Wenn die Argumente nicht benannt werden, muss die Reihenfolge zwingend eingehalten werden!

Beispiel: Nicht benannte Argumente

data <- 1:20

# Reihenfolge wie in Hilfe angegeben, aber ohne Argumentname
mean(data, 0, FALSE)
Beispiel: Benannte Argumente
data <- 1:20

# andere Reihenfolge (mit Argumentname)
mean(na.rm = FALSE, trim = 0, x = data)

# andere Reihenfolge und Defaultwerte werden genutzt
mean(na.rm = FALSE, x = data)

Es gehen auch Mischformen, hier muss jedoch die Position der unbenannten Argumente korrekt sein!

Beispiel: Mischformen

data <- c(1:20, NA)

# das Argument "trim" wurde hier ausgelassen, "na.rm" muss deswegen benannt sein
mean(data, na.rm = TRUE)

Übungen

Aufgabe: Die Argumente werden im folgenden Code falsch übergeben. Korrigiere den Fehler.
median(TRUE, c(1:8))
median(c(1:8), TRUE)
Aufgabe: Die Argumente werden im folgenden Code falsch übergeben. Korrigiere den Fehler.
sample(1:10, NULL, TRUE, 4)
# Lösung 1 ----
sample(1:10, 4, TRUE, NULL)

# Lösung 2 ----
sample(1:10, 4, TRUE)

# Lösung 3 ----
sample(x = 1:10, size = 4, replace = TRUE)

Hilfreiche Funktionen

Zahlen:

x <- c(1:12,12,12,NA)

length(x)
mean(x, na.rm = TRUE)
sum(x, na.rm = TRUE)
sqrt(x)
is.na(x)
unique(x)
round(5.0487)

Daten simulieren:

# wiederhole einen Vektor
rep(c(1,2,3), 5)
rep(c(1,2,3), each = 5)
rep("lala", 3)

# ziehe zufällige Daten mit zurücklegen aus einem Vektor
sample(1:100, size = 10, replace = TRUE)

# ziehe zufällige Daten aus einer Normal-Verteilung
rnorm(n = 10, mean = 0, sd = 2)

# ziehe zufällige Daten aus einer Uniform-Verteilung
runif(n = 10, min = 0, max = 2)

Text:

variable = "Lisa"

print(variable)
paste("Hello", variable, "! How are you?")
paste0("Hello ", variable, "! How are you?")
glue::glue("Hello {variable}! How are you?")
cat("Hello", variable, "! How are you?")

Übungen

Aufgabe: Löse die Problemstellung mit einer Funktion.
vektor <- c(rep(c(1:5), 4), 12, 19)
# Gebe alle Zahlen aus, die nur einmal vorkommen im Vektor
vektor <- c(rep(c(1:5), 4), 12, 19)
# Gebe alle Zahlen aus, die nur einmal vorkommen im Vektor
unique(vektor)
Aufgabe: Löse die Problemstellung mit einer Funktion.
vektor <- 1:10
# Gebe jedes Element im Vektor 5 mal aus,
# wobei zuerst 5 1-er und dann fünf 2-er, etc ausgegeben werden.
vektor <- 1:10
# Gebe jedes Element im Vektor 5 mal aus,
# wobei zuerst 5 1-er und dann fünf 2-er, etc ausgegeben werden.
rep(vektor, each = 5)

R Pakete

Base-R bietet grundlegende Funktionen, z. B. mean(). R Pakete erweitern dieses Angebot. R Pakete sind damit Sammlungen an Funktionen.

Damit Pakete verwendet werden können, müssen sie zuerst installiert sein. Dies muss auf einem Gerät nur einmal gemacht werden.

Wir verwenden hier nun das sprtt Paket als Beispiel.

Beispiel: Installation

# Der Code ist auskommentiert, da es innerhalb von otter nicht möglich ist ein R Paket zu installieren

# install.packages(sprtt)

Nachdem das Paket installiert wurde, können die darin enthaltenen Funktionen verwendet werden mit dem Prefix: paketname::funktions_name().

Beispiel: Verwendung des Paketes nach der Installation

# Daten werden simuliert
data <- sprtt::draw_sample_normal(3, f = 0.4, max_n = 20)
# Eine sequentielle ANOVA (statistischer Test) wird gerechnet
sprtt::seq_anova(y ~ x, f = 0.4, data = data, verbose = FALSE)

Noch angenehmer ist jedoch die Nutzung, wenn das Paket geladen wird. Dadurch werden alle Funktionen in den aktuellen Namensraum geladen und Funktionen können ohne den Präfix genutzt werden.

Beispiel: Paket laden und nutzen

# Das Paket wird geladen
library(sprtt)

# Funktionen können nun auch ohne Prefix verwendet werden
data <- draw_sample_normal(3, f = 0.4, max_n = 20)
seq_anova(y ~ x, f = 0.4, data = data, verbose = FALSE)

Übersicht wichtiger R Pakete

Allgemein:

Statistische Auswertungen:

  • psych: Enthält viele Standardanalysen (für die Psychologie)
  • lavaan: Für Strukturgleichungsmodelle

Tidyverse:

  • bietet eine Sammlung von Alternativen zu Base-R Funktionen.
  • Dazu gehören auch dplyr und ggplot2.
  • Wird nicht weiter in diesem Tutorial behandelt.
  • https://www.tidyverse.org/

Übungen

  1. Öffne RStudio auf deinem Rechner und navigiere in den Reiter “Packages”. Siehe dir dort die installierten Pakete an.

  2. Installiere das Paket glue auf deinem Rechner.

  3. Führe den Code aus, um zu testen, ob alles funktioniert: glue::glue("Hallo Welt").

  4. Lade das Paket glue in einem R Skript oder über die Console.

  5. Führe den Code aus, um zu testen, ob alles funktioniert: glue("Hallo Welt! :-)").

Datenverarbeitung

Kapitel

Daten anschauen
Daten beschreiben
Fehlende Werte anzeigen
Fehlende Werte entfernen
Einzelne Daten auswählen
Daten ändern
Daten export
Daten import

Die Übungen zu diesem Kapitel befinden sich hier:

Hier ist der Einblick in einen klinischen Datensatz df (die Daten wurden simuliert).

Zeige den Code der Simulation

So wurde der Datensatz df simuliert:

set.seed(333) # fixiere alle Zufallsprozesse
N <- 100 # Anzahl der Personen im Datensatz
df <- data.frame(
  sex = factor(sample(c("weiblich", "männlich", "divers", NA), N, TRUE, prob = c(0.40, 0.40, 0.10, .1))),
  age = sample(16:60, N, TRUE),
  treatment_group = sample(c("treatment", "control group"), N, TRUE),
  health_rating_mental = sample(c(1:10, NA), N, TRUE),
  health_rating_body = sample(1:10, N, TRUE)
)
df # so können wir den Datensatz in der Console ausgeben lassen.
# Dies ist oft aber unpraktisch, wenn es große Datensätze sind.

Daten anschauen

Teile der Daten anzeigen:

head(df, n = 10) # zeigt die ersten 10 Zeilen im Datensatz
tail(df, n = 10) # zeigt die letzten 10 Zeilen im Datensatz

Daten beschreiben

Deskriptive Statistiken ausgeben:
summary(df)
psych::describe(df)

Fehlende Werte anzeigen

rowSums(is.na(df)) # Anzahl von fehlenden Werten pro Zeile (eine Zeile ist eine Person)
colSums(is.na(df)) # Anzahl der fehlenden Werte pro Spalte

Fehlende Werte entfernen

Verwendung von complete.cases():

complete.cases(df) # Prüft, ob alle Spalten ausgefüllt wurden pro Zeile
df[!complete.cases(df), ] # Zeigt die Daten, die fehlende Werte enthalten
df[complete.cases(df), ] # Zeigt die Daten, die keine fehlenden Werte enthalten

Verwendung von na.omit()

df <- na.omit(df) # Entfernt alle Zeilen mit fehlenden Werten
df

Einzelne Daten auswählen

Im Datensatz eine Spalte Filtern
# im Datensatz df alle Personen die jünger sind als 18 Jahre
df[df$age < 18, ] # Achtung: das Komma ist zwingend erforderlich!
Im Datensatz nach zwei verschiedenen Spalten filtern
# Im Datensatz df alle Personen die jünger sind als 18 Jahre
# und sich in der Treatment-Gruppe befinden
df[df$age < 18 & df$treatment_group == "treatment", ]
Im Datensatz innerhalb einer Spalte filtern
# Im Datensatz df in der Spalte sex,
# alle Personen die sich in der Treatment-Gruppe befinden.
df$sex[df$treatment_group == "treatment"]

Daten ändern

Nachdem man auf die richtigen Daten im Datensatz zeigt, können mit dem Zuweisungsoperator neue Daten zugewiesen werden. Damit werden die alten Daten überschrieben.

In einer Spalte im Datensatz bestimmte Werte ändern
# ersetze alle fehlenden Geschlechter durch "weiblich"
df$sex[is.na(df$sex)] <- "weiblich" 
df

Neue Spalten erstellen

# addiere alle Werte der health_ratings miteinander
# und erzeguge eine neue Spalte namens health_rating_sum
df$health_rating_sum <- df$health_rating_mental + df$health_rating_body

df$health_rating_sum

Daten Export

Jeder Datensatz (auch jede Variable) kann in verschiedene Dateiformate exportiert werden.

Wenn Dateien für andere zugänglich gemacht werden sollen, ist .csv zu empfehlen, da es ein allgemein gängiges Format ist und von verschiedenen anderen Programmen auch gut eingelesen werden kann.

R hat auch zwei R spezifische Formate, .rda bzw .RData und .rds. Diese Formate sind zu empfehlen, wenn nur innerhalb von R die Daten benötigt werden. Die R Formate sind deutlich effizienter und platzsparender als .csv.

R kann auch die besonderen Formate von anderen Programmen einlesen, oft existieren extra R Pakete dafür.

Eine Übersicht über die wichtigsten Infos:

Funktionen .csv .rda oder .RData .rds
Speichern write.csv() (international)
write.csv2() (deutsch & Excel)
save() saveRDS()
Laden read.csv() (international)
read.csv2() (deutsch & Excel)
load() readRDS()
Anzahl an gespeicherten Objekten eins mehrere eins
Verhalten beim Laden werden einem neuen Objekt zugewiesen werden im Environment wiederhergestellt werden einem neuen Objekt zugewiesen

.csv

# Komma als Seperator und . für Zahlen
write.csv(df, file = "data/df.csv") 
# Semikolon als Seperator und Kommas für Zahlen
write.csv2(df, file = "data/df.csv") 

.rda

# Speichert nur den Datensatz df
save(df, file = "data/df.rda") 
save(df, file = "data/df.RData") 

# Speichert den Datensatz df und die Variable N
save(df, N, file = "data/df.rda") 
save(df, N, file = "data/df.RData") 

.rds

saveRDS(df, file = "data/df.rds") # Speichert nur den Datensatz df

Die hier behandelten Formate sind besonders empfohlen, aber natürlich können auch andere Formate gespeichert werden.

Daten Import

.csv

# Komma als Seperator und . für Zahlen
df <- read.csv("data/df.csv")
# Semikolon als Seperator und Kommas für Zahlen
df <- read.csv2("data/df.csv")

.rda

load("data/df.rda") # Dies kann auch mehrere Objekte in das Environment laden

.rds

# Hier handelt es sich immer nur um ein einziges Objekt
df <- readRDS("data/df.rds")

Für weitere Datenformate bietet sich z.B. diese Quelle an: https://r4ds.hadley.nz/spreadsheets.html

R Projekte und Working Directory

Kapitel

Pfade im Projekt
R projekt erstellen
R projekt verwenden

In R befindet man sich immer in einem working directory (Arbeitsverzeichnis).

An diesem Ort werden Dateien abgespeichert, Datensätze geladen etc.

# gebe das aktuelle Arbeitsverzeichnis aus
getwd()

# ändere das aktuelle Arbeitsverzeichnis
setwd()

Dieses Pfadsystem kann einen schnell nerven! 😉 Zudem sind die Skripte nicht reproduzierbar für andere Personen, da sich die Pfade meist unterscheiden.

Eine bessere Lösung sind R Projekte!

R Projekte erlauben es, alle Pfade nur in Bezug auf das Projekt zu definieren. R weiß bereits automatisch, wo sich das Projekt auf dem aktuellen Rechner befindet. Damit erspart man sich selbst unnötige Arbeit mit setwd() und Co. Zudem kann man auch deutlich leichter mit anderen Personen am selben Projekt zusammenarbeiten.

Pfade im Projekt

Pfade werden nun immer innerhalb eines Projektes referenziert. Egal wo sich das Projekt befindet, die Pfade sind immer gleich.


Ein Pfad innerhalb eines Projektes:

R/script.R (Innerhalb des Projektes im Ordner R, die Datei script.R)


Ganzer Pfad (notwendig, wenn kein R Projekt genutzt wird):

D:/Laura/RKurse/r_programming_course/R/script.R (Dieser Pfad funktioniert nicht auf einem anderen PC)

R Projekt erstellen

Rechts oben in RStudio kann man ein neues Projekt erstellen.
Es wird rechts oben in RStudio auf „Project: (None)“ und anschließend in der obersten Leiste auf „New Project“ geklickt.

Hier wählt man aus, ob man einen neuen Ordner anlegen möchte, oder ein bereits existierendes Verzeichnis nutzen möchte.
Zu sehen sind die drei Auswahlmöglichkeit: New Directory, Existing Directory, Version Control.

Hier können Vorlagen für Projekte ausgewählt werden. In den meisten Fällen werdet ihr diese jedoch nicht benötigen.


Zu sehen sind Vorlagen für Projekte. Sofern man diese nicht benutzt, muss man einfach in der obersten Leiste auf „New Project“ klicken.

Hier könnt ihr nun den Namen vergeben und den Pfad auswählen.
Zu sehen ist ein Eingabefeld, in dem man dem zu erstellenden Projekt einen Namen vergeben und den Projektpfad anpassen kann.

Nachdem ein Projekt erstellt wurde, befindet sich die projektname.Rproj Datei in eurem Projektordner. Von nun an, muss diese Datei zuerst geöffnet werden, wenn man an dem Projekt arbeiten möchte.


Zu sehen ist das erstellte Projekt in dem Projektordner. Es ist nur die Datei test.Rproj zu sehen.

R Projekt verwenden

Zuerst muss immer die Projektdatei geöffnet werden!

Zu sehen ist das erstellte Projekt in dem Projektordner. Es ist nur die Datei test.Rproj zu sehen.

Danach können andere Skripte geöffnet werden. Das Projekt speichert, welche Skripte letztes Mal offen waren.

Verwendet eine klare und einheitliche Ordnerstruktur in euren Projekten. Empfohlen ist z. B. diese hier:

Auf dem Screenshot sind oben ein Ordner namens „data“, darunter ein Ordner namens „images“, darunter ein Ordner namens „R“ und darunter die neue Projekt-Datei (test.Rproj) abgebildet.

Im Ordner data werden alle Datensätze gespeichert. Im Ordner images werden alle Grafiken gespeichert. Im Ordner R werden alle R Skripte gespeichert.

Übungen

Aufgabe: Öffne RStudio auf deinem Rechner und gehe die folgenden Schritte durch:

  1. Erstelle ein R Projekt mit dem Namen otter in RStudio.

  2. Erstelle einen Unterordner und lege dort ein R Skript test.R ab.

  3. Schließe RStudio.

  4. Öffne das R Projekt und öffne das test.R Skript.

Code Flow

Warum ist Code Flow notwendig?

Beispiel: Partyplanung

Ihr wollt eine E-Mail automatisch an alle eure Freunde schicken. Ihr habt einen Datensatz mit allen Kontakten. Die E-Mail soll nur gesendet werden, wenn ihr befreundet seid.

Code soll nur ausgeführt werden, wenn eine bestimmte Bedingung erfüllt ist.

Lösung: if Statements

Ihr habt über 30 Freunde. Der Code soll sich mehrfach selbst ausführen, ohne ihn zu Copy-Pasten

Lösung: for oder while Loop

Übersicht

if()

  • Logik: if (Prüfung == TRUE) {Code wo etwas passiert}
  • Code wird nur ausgeführt, wenn eine Bedingung erfüllt ist
  • Damit können komplexe Wenn-Dann-Sonst-Bedingungen abgebildet werden
  • Der Code wird nur einmal ausgeführt (im Gegensatz zu den Loops)

for()

  • Logik: for (jedes Element in einem Vektor) {passiert etwas}, stoppe am Ende des Vektors
  • Werden sehr häufig angewandt
  • Können aber nicht immer verwendet werden

while()

  • Logik: while(Statement == TRUE) {wiederhole etwas}, stoppt nur, wenn das Statement == FALSE wird
  • Jede for Loop kann in eine while Loop umgewandelt werden!
  • Achtung: kann in eine Endlosschleife laufen, wenn das Statement nie unwahr wird!

if-else

If-else-Statements folgen der Wenn-Dann-Logik. Der Code ist nach folgendem Muster aufgebaut: if (Prüfung == TRUE) {Code wo etwas passiert}

name <- "Lara"
# Übersetzung wenn der Name gleich Lara ist, wird der Code ausgegeben: "Lara is here today."
if (name == "Lara") {"Lara is here today."}

name <- "XXX"
# Übersetzung wenn der Name ungleich Lara ist, wird der Code ausgegeben: "Lara is NOT here today."
if (name != "Lara") {"Lara is NOT here today."}

Eine komplexere Möglichkeit ist die Wenn-Dann-Sonst-Logik. Hier gibt es eine Restkategorie (Sonst). Wenn alle anderen if Statements davor nicht wahr sind, wird die else Kategorie ausgegeben.

name <- "Hans"
if (name == "Lara") {
  "Lara is here today."
} else{
  "Lara is NOT here today."
}

Es können auch mehrere If-Statements miteinander verbunden werden: Wenn-Dann-Wenn-Dann-Sonst-Logik Dazu werden else if Statements verwendet.

name <- "X"
if (name == "Lara") {
  "Lara is here today."
} else if (name == "X") {
  "We are closed."
} else{
  "Lara is NOT here today."
}

if-Statements können auch miteinander verschachtelt werden. Zuerst wird von oben nach unten und immer von der höchsten zur niedrigsten Ebene ausgewertet. Die Reihenfolge kann unten eingesehen werden mit # -> Zahl.

condition_1 <- FALSE
condition_1_1 <- FALSE
condition_2 <-TRUE
condition_2_1 <- FALSE

if (condition_1) {# -> 1
  if (condition_1_1) {
    "Code 1"
  } else{
    "Code 2"
  }
} else if (condition_2) { # -> 2
    if (condition_2_1) { # -> 3
    "Code 3"
  } else{ # -> 4
    "Code 4"
  }
} else{
  "Code 5"
}

Erklärung

  • # -> 1: condition_1 ist falsch und somit wird der nächste Fall geprüft. (condition_1_1 wird nicht geprüft, da der äußere Fall nicht wahr ist.)

  • # -> 2: condition_2 ist richtig und somit wird nun der Körper dieses Falls ausgewertet.

  • # -> 3: condition_2_1 ist falsch und somit wird der nächste Fall geprüft.

  • # -> 4: else hier ist das Ende erreicht der Prüfungen und der “Code 4” wird ausgegeben.

Übungen

Aufgabe: Schreibe ein if-else-Statement, dass den ersten Satz ausgibt, wenn die Variable tier ein Reptil enthält. Der zweite Satz soll ausgegeben werden, wenn es sich nicht um ein Reptil handelt.
tier <- c("Reptil")

print("Es handelt sich um ein Reptil.") # Satz 1
print("Es handelt sich nicht um ein Reptil.") # satz 2
# Lösung 1 ----
tier <- c("Reptil")
if (tier == "Reptil") {
  print("Es handelt sich um ein Reptil.")
} else {
  print("Es handelt sich nicht um ein Reptil.")
}

# Lösung 2 ----
tier <- c("Reptil")
if (tier == "Reptil") {
  print("Es handelt sich um ein Reptil.")
} else if (tier != "Reptil") {
  print("Es handelt sich nicht um ein Reptil.")
}
Aufgabe Was ist der Output diese Codes? (Führe den Code erst aus, wenn du eine Lösung hast.)
name <- "Meike"
vacation <- FALSE

if (name == "Meike") {
  if (vacation == TRUE) {
    "Meike is on vacation."
  } else{
    "Meike is here today."
  }
} else if (name == "X") {
  "We are closed."
} else{
  "Meike is NOT here today."
}

for-loop

Anmerkung: in einer for Loop muss print() genutzt werden, um auf die Console zu printen.

vector = 1:3
for (element in vector) {
  print(element + 10)
}
number = 3
for (i in 1:number) {
  print(i + 10)
}
friends = c("Lisa", "Thorben", "Mara", "Sophie")
for (person in friends) {
  print(person)
}

Was passiert, wenn wir eine Person zu unserer Freundesliste hinzufügen?

friends = c("Lisa", "Thorben", "Mara", "Sophie")

friends_status = logical(4) # Variable Initialisieren / Deklarieren

for (position in 1:4) {
  friends_status[position] <- TRUE
}
friends_status

Zeige die Lösung

Antwort: Wir müssten überall im Code die Zahl 4 ändern!

Bessere Alternative (weil flexibler): length()

friends_status = logical(length(friends)) # Variable Initialisieren / Deklarieren
for (position in 1:length(friends)) {
  friends_status[position] <- TRUE
}
friends_status

Übungen

Aufgabe: Schreibe eine For-Loop, die den Satz Ich mag ____. für alle Tiere ausgibt. Nutze dazu den Code, der bereits angegeben ist.
tiere <- c("Hunde", "Katzen", "Vögel") # diese Zeile nicht ändern

print(paste0("Ich mag ", ____, ".")) # ____ ist ein Platzhalter und muss ersetzt werden
# Lösung 1 ----
tiere <- c("Hunde", "Katzen", "Vögel")
for (i in 1:length(tiere)) {
  print(paste0("Ich mag ", tiere[i], "."))
}

# Lösung 2 ----
tiere <- c("Hunde", "Katzen", "Vögel")
for (i in tiere) {
  print(paste0("Ich mag ", i, "."))
}

while-loop

Negativ-Beispiel: Was ist das Problem mit diesem Code?

condition = TRUE
while (condition) {
  print("Hallo Welt!")
}

Zeige die Lösung

Es fehlt ein Abbruchkriterium in der While-Loop. Damit läuft sie unendlich lange.

Wenn das Abbruch-Kriterium vergessen wird, läuft die While-Loop in eine Endlosschleife. Wenn dies passiert, muss die Ausführung gestoppt werden.

Die Console ist geöffnet. “Hallo Welt” wird unendlich oft in der Console ausgegeben. Oben rechts befindet sich ein rotes Symbol, auf dem „Stop“ steht. Dieses muss geklickt werden, um die Ausführung zu stoppen.

Positiv-Beispiel: Abbruchkriterium ist vorhanden

counter = 1
stop_criteria = 3
while (counter <= stop_criteria) {
  print("Hallo Welt!")
  counter = counter + 1
}

Übungen

Aufgabe: Schreibe diese For-Loop in eine While-Loop um. Nutze dazu den Code, der bereits angegeben ist.
tiere <- c("Hunde", "Katzen", "Vögel")
results <- character(3)
for (i in 1:length(tiere)) {
  results[i] <- paste0("Ich mag ", tiere[i], ".")
}
results
tiere <- c("Hunde", "Katzen", "Vögel")
results <- character(3)
i = 1
while (i <= length(tiere)) {
    results[i] <- paste0("Ich mag ", tiere[i], ".")
  i = i + 1
}
results

Debugging (Fehlerbehebung)

Kapitel

Warnungen und Fehler
Tipps

Lasst euch nicht davon verunsichern, dass euer Code häufig nicht sofort funktioniert, sondern erst mal debugged werden muss!

Warnungen und Fehler

Warnungen und Fehler sind da, um euch zu helfen! Auch, wenn es sich nicht immer so anfühlt 😉

  • Sollen unerwartetes Verhalten verhindern.

  • Sollen erklären, warum etwas nicht geht, oder zumindest darauf hinweisen, dass etwas nicht geht.

  • Sollten auch in eigenen Funktionen genutzt werden!

  • Warnungen und Fehler werden mit If-Statements verbunden. Nur wenn ein bestimmter Fall vorhanden ist, werden sie dann ausgegeben.

  • Warnungen geben eine Meldung aus, aber das Programm läuft weiter. Sie werden erstellt mit warning().

  • Fehler geben eine Meldung aus und brechen das Programm ab! Sie werden erstellt mit stop().

Beispiel: eine Warnung selbst schreiben mit warning()

add_numbers <- function(number1 = 0, number2 = 0) {
  # Hier wird eine Warnung ausgegeben, wenn mit Unendlichkeit gerechnet wird.
  if (number1 == Inf | number2 == Inf) {warning("One Number is Infinity.")}
  if (number1 == -Inf | number2 == -Inf) {warning("One Number is - Infinity.")}
  number1 + number2
}
add_numbers(2, -Inf)

Beispiel: eine Fehlermeldung selbst schreiben mit stop()

# Hier soll eine Fehlermeldung ausgegeben werden, wenn versucht wird durch 0 zu teilen.
divide_numbers <- function(number1, number2) {
  if (number2 == 0) {stop("number2 is zero.")}
  number1 / number2
}
divide_numbers(8, 0)

Übungen

Aufgabe: Schreibe eine Warnung, die angezeigt wird, wenn die Variable zahl nicht numerisch ist. Nutze dazu den Code der bereits vorhanden ist.
zahl <- "5"

"Zahl ist nicht numerisch!"
zahl <- "5"
if (!is.numeric(zahl)){
  warning("Zahl ist nicht numerisch!")
}

Tipps

  • Fehlermeldungen lesen bzw. übersetzen lassen (häufig sagen diese relativ genau, was das Problem ist, manchmal sogar wie eine Lösung aussehen kann.)

  • Fehlermeldungen googeln (klingt banal, ist aber eine der wichtigsten Fähigkeiten beim Programmieren)

  • chatGPT oder andere KIs fragen, warum der Code nicht funktioniert

  • RStudio neu starten und Code Zeilen Stück für Stück einlesen (verhindert Reihenfolge-Fehler)

  • Coden -> Testen -> Coden -> Testen -> …. In kleinen Schritten arbeiten (testet euren Code in so kleinen Schritten wie möglich und nicht erst ganz am Ende)

  • Einzelne Zeilen ausführen, oder auch nur Ausschnitte von Zeilen markieren und Ausführen

  • Help Seite von Funktionen lesen

    • Welche Argumente gibt es? Was sind die Defaults?
    • Beispiele in der Doku ansehen
  • RStudio Debugger verwenden (https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE)

Environments

Kapitel

Funktionen
Loops

Variablen und Funktionen sind Environments (Umgebungen) zugeordnet. Diese Zuordnung entscheidet, wo eine Variable oder eine Funktion existiert

In Funktionen

Vorbereitung: Wir erzeugen hier eine Globale-Variable global_variable und eine Variable, die innerhalb des Körpers einer Funktion erzeugt wird function_variable.

global_variable = "global_variable"

# Definition der Funktion
test_function <- function() {
  function_variable = "function_variable"
  return(function_variable)
}
test_function() # Funktion wird ausgeführt

Auf welche Variablen kann nun zugegriffen werden?

Beispiel: Funktionsvariablen existieren nur innerhalb der Funktion und nicht außerhalb
function_variable # nur innerhalb der Funktion zugänglich -> Fehler
Beispiel: Globale Variablen existieren quasi immer
global_variable # immer zugänglich -> kein Fehler

Globale Variablen funktionieren sogar innerhalb der Umgebung einer Funktion, ohne als Argument übergeben worden zu sein! Dies sollte jedoch nicht so programmiert werden.

Negativ-Beispiel: Globale Variable in Funktionen
global_variable = "global_variable"

test_function <- function() {
  return(global_variable)
}
test_function()

Obwohl die global_variable nicht als Argument übergeben wurde, kann die Funktion auf die Variable zugreifen. Das funktioniert NUR, weil die Funktion im selben Skript wie die global_variable definiert wurde.

Achtung: Auch wenn es funktioniert, sollte man so etwas NIEMALS programmieren. Funktionen sollten immer nur auf ihre Argumente zugreifen.

Positiv-Beispiel: Globale Variable in Funktionen
global_variable = "global_variable"
test_function <- function(function_variable) {
  return(function_variable)
}
test_function(global_variable)

In Loops

Alle Variablen, die innerhalb von Loops verwendet werden, befinden sich in der globalen Umgebung (sofern die Loops sich in der globalen Umgebung befinden).

Damit kann auch außerhalb der Loop noch auf die Variablen zugegriffen werden und die Loops haben immer Zugriff auf globale Variablen.

Beispiel: Globale Variablen in for-Loops

for (counter in 1:77) {
  test = "for"
}
counter # enthält nun die Information der letzten for-loop-Iteration
test # enthält nun die Information der letzten for-loop-Iteration

Beispiel: Globale Variablen in while-Loops

j = 0
while (j <= 10) {
  j = j + 1
  test = "while"
}
j # enthält nun die Information der letzten while-loop-Iteration
test # enthält nun die Information der letzten while-loop-Iteration

Übergeordnete Übungen

Code Debugging

Die folgenden Aufgaben enthalten fehlerhaften Code. Behebe alle Fehler!

Aufgabe: Behebe den Fehler im Code (1 Fehler).
zahl <- c(1;33)
matrix <- matrix(zahl, ncol = 3)
matrix
zahl <- c(1:33)
matrix <- matrix(zahl, ncol = 3)
matrix
Aufgabe: Behebe den Fehler im Code (1 Fehler).
name <- NA
if (name == "X") {
  print("Heute ist leider kein Personal anwesend!")
}
name <- NA
if (is.na(name)) {
  print("Heute ist leider kein Personal anwesend!")
}
Aufgabe: Behebe die Fehler im Code (2 Fehler). Die Textausgabe soll in einer Zeile erfolgen
name <- "Lisa" # Diese Zeile ist korrekt
if (name == "Max") {
  print("Heute ist Max da!")
} else if {
  print(c("Heute ist Max leider nicht da!",
          "Es ist aber", name, "hier!"))
}
name <- "Lisa" # Diese Zeile ist korrekt
if (name == "Max") {
  print("Heute ist Max da!")
} else{
  print(paste("Heute ist Max leider nicht da!",
          "Es ist aber", name, "hier!"))
}
Aufgabe: Behebe den Fehler im Code (1 Fehler). Die Textausgabe soll Option 1 sein
content <- 55 # Diese Zeile ist korrekt
if (content < 55) {
  print("Option 1")
} else if (content > 55) {
  print("Option 2")
}
content <- 55 # Diese Zeile ist korrekt
if (content <= 55) {
  print("Option 1")
} else if (content > 55) {
  print("Option 2")
}
Aufgabe: Behebe den Fehler im Code (3 Fehler).
data <- data.frame(
  name = c("Peter", "Max", "Lizzy", "Mara", "Beatrice", "Klaus"),
  guthaben = c(-240, 33489, 453, 73563, -2553, 99763),
  anzahl_kredite = c(3, 0, 1, 4, 0, 1)
)
bank_status <- function(df, name) {
  guthaben <- df$guthaben[df$name = name]
  kredite <- df$anzahl_kredite[df$name = name]
  if (guthaben < 0) {
    if (kredite >= 1) {
      cat(name, "kann keinen weiteren Kredit erhalten.")
    } else{
      cat(name, "kann einen ersten Kredit erhalten.")
  } else{
    cat(name, "hat bereits", kredite, "Kredit(e) bei unserer Bank. Ein weiterer Kredit ist möglich.")
  }
  }
# Der Code ist ab hier ist korrekt!
bank_status(data, "Lizzy")
bank_status(data, "Beatrice")
bank_status(data, "Klaus")
data <- data.frame(
  name = c("Peter", "Max", "Lizzy", "Mara", "Beatrice", "Klaus"),
  guthaben = c(-240, 33489, -453, 73563, -2553, 99763),
  anzahl_kredite = c(3, 0, 1, 4, 0, 1)
)
bank_status <- function(df, name) {
  guthaben <- df$guthaben[df$name == name]
  kredite <- df$anzahl_kredite[df$name == name]
  if (guthaben < 0) {
    if (kredite >= 1) {
      cat(name, "kann keinen weiteren Kredit erhalten.\n")
    } else{
      cat(name, "kann einen ersten Kredit erhalten.\n")
    }
  } else{
    cat(name, "hat bereits", kredite, "Kredit(e) bei unserer Bank. Ein weiterer Kredit ist möglich.\n")
  }
}
bank_status(data, "Lizzy")
bank_status(data, "Beatrice")
bank_status(data, "Klaus")

Hinweis: Der korrekte Code soll diese Ausgabe haben:

## Lizzy kann keinen weiteren Kredit erhalten.
## Beatrice kann einen ersten Kredit erhalten.
## Klaus hat bereits 1 Kredit(e) bei unserer Bank. Ein weiterer Kredit ist möglich.

Code umschreiben (Refactoring)

Die folgenden Aufgaben enthalten Code, der umgeschrieben werden soll, ohne die Funktionalität zu ändern. Diese Fähigkeit hilft, Code flexibler zu schreiben.

Aufgabe: Schreibe den Code um, ohne die Funktionalität zu ändern. Erstelle den Datensatz direkt, ohne erst die Vektoren zu erstellen.
# Erstellt die Vektoren (dieser Schritt soll ausgelassen werden!)
namen <- c("Lisa", "Peter", "Klara", "Thorben")
alter <- c(22, 21, 34, 17)
status_student <- c(TRUE, FALSE, FALSE, TRUE)
# Erstellt den Datensatz
data <- data.frame(
  namen = namen,
  alter = alter,
  status_student
)
data
data <- data.frame(
namen = c("Lisa", "Peter", "Klara", "Thorben"),
alter = c(22, 21, 34, 17),
status_student = c(TRUE, FALSE, FALSE, TRUE)
)
data
Aufgabe: Schreibe den Code um, ohne die Funktionalität zu ändern.
content <- 55 
if (content < 55) {
  print("Option 1")
} else if (content > 55) {
  print("Option 2")
} else if (content == 55) { # verwende hier kein "else if"
  print("Option 3")
}
content <- 55 
if (content < 55) {
  print("Option 1")
} else if (content > 55) {
  print("Option 2")
} else{ # verwende hier kein "else if"
  print("Option 3")
}
Aufgabe: Schreibe den Code um, ohne die Funktionalität zu ändern. Schreibe die while-loop in eine for-loop um.
namen <- c("Lisa", "Peter", "Klara", "Thorben")
length_namen <- length(namen)
counter <- 1
results <- length(namen)
while (counter <= length_namen) {
  results[counter] <- paste("Hallo", namen[counter])
  counter <- counter + 1
}
results
namen <- c("Lisa", "Peter", "Klara", "Thorben")
results <- length(namen)
for (i in 1:length(namen)) {
  results[i] <- paste("Hallo", namen[i])
}
results

Übungen mit einem Datensatz

Zeige den Code der Simulation von data_health

So wurde der Datensatz data_health simuliert:

set.seed(3) # fixiere alle Zufallsprozesse
N <- 200 # Anzahl der Personen im Datensatz
data_health <- data.frame(
  sex = factor(sample(c("weiblich", "männlich", "divers"), N, TRUE, prob = c(0.40, 0.40, 0.20))),
  age = sample(16:60, N, TRUE),
  treatment_group = sample(c("treatment", "control group"), N, TRUE),
  health_rating_mental_1 = sample(c(1:10), N, TRUE),
  health_rating_mental_2 = sample(c(1:10), N, TRUE),
  health_rating_mental_3 = sample(c(1:10, NA), N, TRUE),
  health_rating_body_1 = sample(1:10, N, TRUE),
  health_rating_body_2 = sample(1:10, N, TRUE),
  health_rating_body_3 = sample(1:10, N, TRUE),
  stress_level = sample(1:7, N, TRUE)
)
data_health
Aufgabe: Schaue den Datensatz data_health an. Gebe dir dazu die letzten 7 Zeilen des Datensatzes aus.
tail(data_health, n = 7)
Aufgabe: Gibt es fehlende Werte im Datensatz data_health? Gebe dir fehlende Werte pro Spalte aus.
colSums(is.na(data_health))
Aufgabe: Gebe dir alle Zeilen aus, die fehlende Werte enthalten. Schaue dir die Daten an.
data_health[!complete.cases(data_health), ]
Aufgabe: Entferne alle Zeilen mit fehlenden Werten aus dem Datensatz (und speichere den neuen Datensatz als data ab).
# complete.cases() ----
data <- data_health[complete.cases(data_health), ]
data

# na.omit() ----
data <- na.omit(data_health)
data

Programmierübungen

Aufgabe: Schreibe eine Funktion, welche den Buchstaben F in die Console ausgibt mit unterschiedlichen Argumenten, um die Größe und das Aussehen zu beeinflussen. Die Consolenausgabe soll identisch sein mit dieser:

zeichne_f()
zeichne_f(groesse = 5, breite = 3, symbol = "%", trennungszeichen = "-")
#####
# 
# 
#####
# 
# 
# 
%-%-%-
% 
%-%-%-
% 
% 
# Erstelle hier die Funktion zeichne_f()


# Teste hiermit, ob deine Funktion funktioniert
zeichne_f()
zeichne_f(groesse = 5, breite = 3, symbol = "%", trennungszeichen = "-")
Um zu testen, ob dein Code funktioniert, vergleiche die Ausgabe mit der obigen Ausgabe.
# Beispiellösung ----
zeichne_f <- function(groesse = 7, breite = 5, symbol = "#", trennungszeichen = "") {
  
  fuss <- (groesse - 1) / 2
  kopf <- ceiling(fuss / 2) # ceiling() rundet auf
  
  cat(rep(symbol, breite), "\n", sep = trennungszeichen)
  for (i in 1:kopf) {
    cat(symbol, "\n")
  }
  cat(rep(symbol, breite), "\n", sep = trennungszeichen)
  for (i in 1:fuss) {
    cat(symbol, "\n")
  }
}
# Teste hiermit, ob deine Funktion funktioniert.
zeichne_f()
zeichne_f(groesse = 5, breite = 3, symbol = "%", trennungszeichen = "-")

R Chunk (freies Üben)

Arbeitsbereich 1 (kurz)

Arbeitsbereich 2 (mittel)

Arbeitsbereich 3 (lang)

R & RStudio Grundlagen