x <- 5
y <- 2
z <- 12 Programmierung
Programmieren ist wie Küssen: Man kann darüber reden, man kann es beschreiben, aber man weiß erst was es bedeutet, wenn man es getan hat.
Andrée Beaulieu-Green, Professorin an der Université du Québec à Montréal
2.1 Objekte, Zuweisungen und Environments
Grundsätzlich lassen sich Objekte neuen Variablen mit Hilfe eines Pfeils <- zuweisen. Wollen wir zum Beispiel der Variable x den Wert 5 zuweisen, y den Wert 2 und z den Wert 1, so schreiben wir
Wenn wir dann im Folgenden den Wert von x ansehen möchten, geben wir einfach x ein und erhalten das Resultat zurück:
x[1] 5
Wir können mit x und y nun auch Berechnungen anstellen, so ergibt sich \(x^y = 5^2\) mit
x^y[1] 25
Zuweisungen auf ein schon bestehendes Objekt, überschreibt dieses:
a <- 1
a <- 2
a[1] 2
Mit einer Zuweisung wird ein Objekt also erstellt und ist in der Arbeitsumgebung (Environment) von nun an verfügbar. In RStudio können wir diese Objekte auch in dem entsprechenden oberen rechten Fensterabschnitt im Reiter “Environment” sehen (siehe Abbildung 2.1).
Zuweisungen können grundsätzlich auch mit einem = erfolgen, d.h. x = 5 würde ebenfalls der Variable x den Wert 5 zuweisen. Sie werden diese Schreibweise immer wieder in fremdem R-Code finden. Allerdings wird von dieser Schreibweise abgeraten, da das Gleichheitszeichen auch für die Definition von Parametern in Funktionen verwendet wird (siehe Kapitel 2.7) und damit zu Fehlern führen kann.
Möchte man ein Objekt wieder aus der Umgebung entfernen, geschieht dies über die Funktion rm, in unserem Fall also
rm(x)Möchte man mehrere Objekte in der Umgebung löschen, listet man diese in der Funktion rm einfach auf (z. B. rm(x,y)).
Möchte man sich alle Objekte in der aktuellen Environment anzeigen lassen, so geht dies mit der “List Objects” Funktion
ls()[1] "a" "y" "z"
Alle verfügbaren Objekte werden mit Ihrem Namen (also in Anführungszeichen) aufgelistet. Zu diesem Zeitpunkt sind also nur noch a, y und z in der Umgebung verfügbar, da wir zuvor x entfernt haben. Möchten wir alle Objekte der Umgebung löschen, können wir dies mit dem Befehl
rm(list = ls())erledigen.
Startet man eine neue Analyse oder ein neues Programm, empfiehlt es sich in der Regel mit dem Befehl rm(list = ls()) zu beginnen, um sicherzustellen, dass die Arbeitsumgebung von allen nicht benötigten Objekten befreit ist. Man räumt vor einer neuen Aufgabe sozusagen seinen Schreibtisch auf.
Andernfalls kann es schnell passieren, dass ein zuvor zugewiesenes Objekt x unbeabsichtigt und fälschlicherweise weiterverwendet wird.
Um sicherzustellen, dass der für diese Variablen zugewiesene Speicher auch tatsächlich freigemacht wird, kann über die Funktion gc() eine sogenannte “Garbage Collection” folgen.
Einzelne oder mehrere Objekte aus einer Umgebung, ja sogar die gesamte Umgebung lassen sich in einer Datei abspeichern und später wieder laden. Hierfür gibt es die Befehle save (bzw. save.image) und load. Hierzu gibt man die Objekte an, welche abgespeichert werden sollen (durch Komma getrennt) und anschließend mit dem Argument file einen Pfad und Dateinamen, in dem die Objekte abgelegt werden. Beispielsweise speichern wir mit
save(y,z, file = "C:/Daten/datenxy.RData")die Objekte y und zin der Datei “datenxy.RData” im Ordner “C:/Daten” ab. Typischerweise verwendet man für R Objekte die Dateiendung “.RData” oder “.rds”. Die gesamte Arbeitsumgebung lässt sich mit dem Befehl save.image unter einem beliebigen Pfad abspeichern.
Mit dem Befehl
load(file = "C:/Daten/datenxy.RData")können wir zu einem späteren Zeitpunkt alle Objekte aus der Datei “datenxy.RData” wieder in unsere Umgebung laden.
Mit dem load Befehl lassen sich nur R Objekte laden. Datensätze in Formaten wie Excel, als Textdatei oder gar in Datenbanken lassen sich hiermit nicht einlesen. Mehr zum Import von Daten finden Sie in Kapitel 3.1.
Bei längeren Analysen und größeren Datensätzen ergibt es durchaus Sinn, Zwischenschritte und Objekte abzuspeichern, damit man die längeren Berechnungen nicht bei jeder Iteration wiederholen muss.
Beim Start legt R automatisch ein Arbeitsverzeichnis (engl. working directory) fest. Dies ist ein Pfad, in dem standardmäßig (wenn kein Pfad angegeben ist) Dateien abgespeichert werden oder beim Laden nach ihnen gesucht wird. Dieser Pfad kann mit dem Befehl getwd() angezeigt und mit der Funktion setwd festgelegt werden. Auf dem RStudio Server der FH Münster sollte Ihr Working Directory Ihrem Heimverzeichnis in der FH Umgebung entsprechen und im Pfad /home/<Nutzerkennung>/working zu finden sein.1
Es ist ratsam, das Working Directory bewusst in einen Ordner zu verlegen, in dem man für ein bestimmtes Projekt arbeiten möchte. Bei RStudio Projekten ist das Working Directory gleich dem Projektordner (mehr zu Projekten finden Sie in Kapitel 2.9).
In einer R Session arbeitet man immer mit mehreren Environments. Neben der eigenen Arbeitsumgebung hat zum Beispiel jedes geladene Paket eine eigene Umgebung. Was dies für Konsequenzen hat und wie man geschickt mit Umgebungen arbeiten kann, können Sie bei Wickham (2014) nachlesen (siehe http://adv-r.had.co.nz/Environments.html).
2.2 Datentypen und Datenstrukturen
2.2.1 Atomische Datentypen
Wie in jeder Programmiersprache werden auch in R Daten in verschiedenen Typen abgespeichert. Ähnlich wie die Skalenniveaus aus der Statistik unterscheiden diese Typen die Daten nach Informationsgehalt (z. B. metrisch und nominal skalierte Daten). Außerdem wird über die Datentypen geregelt, wie R die Daten intern im Arbeitsspeicher ablegt.
Die von R verwendeten Datentypen sind
numeric: Dezimalzahleninteger: ganzzahlige Zahlencomplex: komplexe Zahlenlogical: logische Werte (d.h. wahr oder falsch, bzw. in RTRUEoderFALSE)character: Textzeichen
Um festzustellen, welcher Typ einem Objekt in R zugewiesen wurde, verwenden wir die Funktion mode
x <- 5
mode(x)[1] "numeric"
y <- TRUE
mode(y)[1] "logical"
Man kann auch die einzelnen Typen abfragen, indem man vor die Typenbezeichnung ein is.setzt:
is.numeric(x)[1] TRUE
is.character(x)[1] FALSE
R gibt in diesem Fall ein TRUE oder FALSE zurück, je nachdem ob das Objekt den jeweiligen Datentyp besitzt. Mit einem as. gefolgt von der Typenbezeichnung lässt sich der Datentyp eines Objekts konvertieren:
x2 <- as.integer(x)
is.integer(x2)[1] TRUE
x3 <- as.character(x)
mode(x3)[1] "character"
x3[1] "5"
Neben diesen Datentypen gibt es außerdem einige besondere Typen:
NaN: “Not a Number”, kommt zum Beispiel durch Teilen durch 0 zustandeNA: “Not Available”, also fehlender WertNULL: leeres ObjektInf,-Inf: Unendlich (positiv und negativ)
2.2.2 Datenstrukturen
Wenn wir mit Daten arbeiten, nutzen wir typischerweise Strukturen, um einzelne Zahlen zu größeren Objekten zusammenzufassen. Einfachste Beispiele hierfür sind Vektoren und Matrizen. Neben diesen gibt es weitere Datenstrukturen in R, mit denen man arbeiten kann. Sie unterscheiden sich im Wesentlich dadurch, wie viele Dimensionen sie umfassen
vector: Vektor – eindimensionale Kombination von atomischen Datenpunkten gleichen Typsmatrix: Matrix – zweidimensionale Kombination von atomischen Datenpunkten gleichen Typsarray: Array – mehrdimensionale Kombination von atomischen Datenpunkten gleichen Typslist: Liste – eindimensionale Kombination von atomischen Datenpunkten unterschiedlichen Typsdata.frame: Data Frame – zweidimensionale Kombination von atomischen Datenpunkten unterschiedlichen Typs
Vektoren
Einen Vektor können wir erstellen, indem wir mehrere atomare Objekte (oder andere Vektoren) mit Hilfe der “Combine”-Funktion verknüpfen:
x <- c(1,2,3)
x[1] 1 2 3
Für ganzzahlige Zahlenfolgen können wir die Kurzschreibweise m:n verwenden:
x <- -5:5
x [1] -5 -4 -3 -2 -1 0 1 2 3 4 5
Um auf einzelne Elemente aus einem Vektor zuzugreifen, geben wir in eckigen Klammern die Stellen im Vektor an, die zurückgegeben werden sollen. Diese Stellen nennt man auch Index.
x[1][1] -5
x[4:5][1] -2 -1
Ein vorangesetztes Minus-Zeichen ergibt, dass alle Elemente des Vektors ausgegeben werden außer diejenigen mit negativem Index
x[-1] [1] -4 -3 -2 -1 0 1 2 3 4 5
x[-c(1,6)][1] -4 -3 -2 -1 1 2 3 4 5
Über die Indizierung lassen sich auch einzelne Werte überschreiben
x[1] <- 10000
x [1] 10000 -4 -3 -2 -1 0 1 2 3 4 5
Statt eines Index’ kann die Referenzierung auch mit Hilfe von logischen Werten erfolgen. Dazu ist ein logischer Vektor der gleichen Länge zu verwenden – die Rückgabe entspricht dann allen Einträgen, für die der logische Vektor gleich TRUE ist.
x <- 1:5
y <- c(TRUE, FALSE, TRUE, FALSE, TRUE)
x[y][1] 1 3 5
Matrizen und Arrays
Matrizen sind Datenstrukturen mit zwei Dimensionen (Zeilen und Spalten), Arrays können beliebig viele Dimensionen haben, was deren Darstellung in der zwei-dimensionalen Konsole schwieriger macht.
Matrizen oder Arrays können direkt aus Vektoren erstellt werden:
x <- 1:12
m1 <- matrix(x, nrow = 3, byrow = TRUE)
m1 [,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
m2 <- matrix(x, nrow = 4, byrow = FALSE)
m2 [,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
a <- array(x, dim = c(2,2,3))
a, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 3
[,1] [,2]
[1,] 9 11
[2,] 10 12
Auf die einzelnen Elemente aus einer Matrix oder einem Array kann man auch wieder über die eckigen Klammern zugreifen, wobei die Dimensionen durch ein Komma getrennt werden. Bei einer Matrix entsprechen die Zeilen der ersten Dimension und die Spalten der zweiten Dimension. Das heißt, möchten wir von Matrix m1 das Element in der zweiten Zeile und dritten Spalte auswählen, erfolgt dies mit
m1[2,3][1] 7
Auch hier könnte man wie bei Vektoren logische Werte für die Referenzierung verwenden.
Um ganze Zeilen oder Spalten auszuwählen, wird die jeweils andere Dimension leer gelassen. Es können auch mehrere Zeilen oder Spalten gleichzeitig gewählt werden. So ergibt sich zum Beispiel für m1 für die Auswahl der zweiten und vierten Spalte
m1[,c(2,4)] [,1] [,2]
[1,] 2 4
[2,] 6 8
[3,] 10 12
Negative Indizes funktionieren genau wie bei Vektoren und helfen dabei, auf alle Elemente bis auf ausgewählte zuzugreifen.
a[1,2,-2][1] 3 11
Matrizen (und Vektoren) transponiert man mit der Funktion t
t(m1) [,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
Die gewöhnliche Addition oder Multiplikation (auch Potenzieren) von Skalaren mit Vektoren oder Matrizen erfolgt elementweise
3+x [1] 4 5 6 7 8 9 10 11 12 13 14 15
x^2 [1] 1 4 9 16 25 36 49 64 81 100 121 144
2*m1 [,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 10 12 14 16
[3,] 18 20 22 24
Das Skalarprodukt kann per %*% verwendet werden:
v1 <- 1:3
v2 <- 1:4
t(v1) %*% m1 %*% v2 [,1]
[1,] 500
Vektoren, Matrizen und Arrays enthalten immer nur einen Datentyp. Dieser wird immer gewählt als der Datentyp, in den sich alle einzelnen Elemente höchstens umwandeln lassen (je höher das Skalenniveau, umso besser). Eine Zahl kann beispielsweise leicht in einen Text bzw. Character umgewandelt werden, andersherum funktioniert das aber nicht.
x <- c(1,2,3,"R")
x[1] "1" "2" "3" "R"
mode(x)[1] "character"
as.numeric(x)Warning: NAs introduced by coercion
[1] 1 2 3 NA
Listen
Listen sind eindimensionale Datenstrukturen, welche jedoch in den einzelnen Elementen Daten unterschiedlichen Typs enthalten können. So kann eine Liste zum Beispiel im ersten Element eine Zahl enthalten und im zweiten einen Character. Das ist bei Vektoren wie oben gesehen nicht möglich.
x <- list(1,2,3,"R")
x[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] "R"
Listen können auch als Elemente nicht-atomare (sogar beliebige) Datenstrukturen enthalten, zum Beispiel Vektoren, Matrizen oder Arrays (ja sogar andere Listen!). Außerdem können einzelne Elemente mit einem Namen versehen werden.
l <- list(Vektor = 1:10,
Matrix = matrix(1:12, nrow = 3),
Array = array(1:12, dim = c(2,2,3)),
Character = c("a","b","c"))
l$Vektor
[1] 1 2 3 4 5 6 7 8 9 10
$Matrix
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
$Array
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 3
[,1] [,2]
[1,] 9 11
[2,] 10 12
$Character
[1] "a" "b" "c"
RStudio hilft dabei, durch sinnvolle Einrückungen den Code lesbarer zu machen. Im obigen Beispiel hilft der Zeilenumbruch nach jedem definierten Listenelement dabei, dass der Code nicht in einer sehr langen Zeile resultiert. Die Einrückungen nach dem Zeilenumbruch macht RStudio automatisch, und zwar so, dass der Code logisch strukturiert und gut lesbar ist.
Auf einzelne Listenelemente kann man auf verschiedene Arten zugreifen – entweder über einen Index in doppelten eckigen Klammern, über die Referenzierung mit logischen Werten oder über den Namen des Listenelements nach einem Dollarzeichen:
x[[1]][1] 1
x$VektorNULL
Objekte und Environment
- Erstellen Sie eine Matrix mit 4 Zeilen und 5 Spalten, welche spaltenweise die ersten 20 Quadratzahlen enthält. Berechnen Sie anschließend die Summe der dritten Spalte.
- Legen Sie ein Arbeitsverzeichnis unter
/home/xx123456/Vorlesungen/Data Science/Übungenan, wobeixx123456Ihrer FH Kennung entspricht. - Speichern Sie die in Aufgabe 1 angelegte Matrix als
.RDataDatei in Ihrem Arbeitsverzeichnis ab. - Leeren Sie Ihren Workspace.
- Laden Sie die in Aufgabe 3 abgespeicherte Matrix wieder.
Data Frames
Der Data Frame ist die Datenstruktur, die in R wahrscheinlich am häufigsten zur Anwendung kommt. Ein Data Frame entspricht dem, wie wir uns eine typische Datentabelle vorstellen. Ähnlich wie eine Matrix hat ein Data Frame zwei Dimensionen (Zeilen und Spalten). Die Spalten entsprechen dabei den Variablen, die Zeilen den Beobachtungen des Datensatzes. Entsprechend kann im Unterschied zu einer Matrix jede Spalte eines Data Frames einen unterschiedlichen Datentyp haben (z. B. numerisch als numeric, kategoriell als factor), was uns wiederum an Listen erinnert. Spalten und Zeilen von Data Frames bekommen Namen.
Im Grunde sind Data Frame nichts anderes als Listen, die etwas anders darstellt werden und einige Einschränkungen haben (z. B. jedes Listenelement = Spalte ist ein Vektor und gleich lang) – mehr dazu siehe http://adv-r.had.co.nz/Data-structures.html#data-frames.
Data Frames lassen sich neu definieren, aus Matrizen erstellen, oder auch aus externen Datenquellen einlesen (mehr zu letzterem in Kapitel 3.1).
as.data.frame(m1) V1 V2 V3 V4
1 1 2 3 4
2 5 6 7 8
3 9 10 11 12
Wenn nicht anders angegeben, lauten die Namen der Zeilen 1,2,3,… und die Namen der Spalten V1, V2, V3, … – es können aber auch Namen bei der Definition angegeben werden
df <- data.frame(Name = c("Mueller", "Meyer", "Schneider", "Meyer", "Meier"),
Alter = c(45,23,62,32,22),
Premiumkunde = c(TRUE, FALSE, FALSE, TRUE, TRUE))
df Name Alter Premiumkunde
1 Mueller 45 TRUE
2 Meyer 23 FALSE
3 Schneider 62 FALSE
4 Meyer 32 TRUE
5 Meier 22 TRUE
Ähnlich wie bei Listen, kann auch bei Data Frames der Zugriff auf einzelne Elemente über die Namen oder Indizes erfolgen:
df$Alter[1] 45 23 62 32 22
df[3,] Name Alter Premiumkunde
3 Schneider 62 FALSE
df[1,2][1] 45
R enthält viele Datensätze (als Data Frames), mit denen man üben und Algorithmen testen kann. Es gibt dafür ein spezielles Paket, welches in der Basis-Installation von R bereits enthalten ist: datasets (für eine Übersicht: help(package = "datasets")). Diese Datensätze lassen sich ganz einfach mit ihrem Namen aufrufen, z. B. der Datensatz iris ist bereits in der Umgebung verfügbar und kann direkt verwendet werden.2
In jedes Paket können eigene Datensätze integriert werden, so dass es eine Vielzahl an Beispieldatensätzen auch in anderen Paketen zu finden gibt.
2.2.3 Kategorielle Variablen
In der Statistik arbeitet man häufig mit ordinal oder nominal skalierten Daten. Hierfür bietet R einen speziellen Datentyp: factor.
Ein factor wird in R intern als Merkmal mit ganzzahligen Ausprägungen gespeichert. Jeder dieser Ausprägungen kann ein “Label” vergeben werden. Faktoren lassen sich zum Beispiel aus character-Vektoren erstellen:
automarke_chr <- c("Opel", "BMW", "Mercedes", "Mercedes", "Opel", "BMW")
automarke_factor <- factor(automarke_chr)
automarke_chr[1] "Opel" "BMW" "Mercedes" "Mercedes" "Opel" "BMW"
automarke_factor[1] Opel BMW Mercedes Mercedes Opel BMW
Levels: BMW Mercedes Opel
Bei der Ausgabe eines Faktors werden die Beobachtungen angezeigt und auch eine Übersicht über die enthaltenen Faktorlevels (Kategorien) gegeben. Auf diese kann man auch über die Funktion levels zugreifen und die Bezeichnungen gegebenenfalls überschreiben:
levels(automarke_factor)[1] "BMW" "Mercedes" "Opel"
levels(automarke_factor)[2] <- "Mercedes Benz"
automarke_factor[1] Opel BMW Mercedes Benz Mercedes Benz Opel
[6] BMW
Levels: BMW Mercedes Benz Opel
Für einen Faktor mit definierten Faktorlevels können keine Beobachtungen mit anderen Faktorlevels eingetragen werden
automarke_factor[1] <- "BMW"
automarke_factor[1] BMW BMW Mercedes Benz Mercedes Benz Opel
[6] BMW
Levels: BMW Mercedes Benz Opel
automarke_factor[1] <- "Audi"Warning in `[<-.factor`(`*tmp*`, 1, value = "Audi"): invalid factor level, NA
generated
automarke_factor[1] <NA> BMW Mercedes Benz Mercedes Benz Opel
[6] BMW
Levels: BMW Mercedes Benz Opel
Dazu muss zunächst ein zusätzliches Faktorlevel definiert werden
levels(automarke_factor) <- c(levels(automarke_factor), "Audi")
automarke_factor[1] <NA> BMW Mercedes Benz Mercedes Benz Opel
[6] BMW
Levels: BMW Mercedes Benz Opel Audi
automarke_factor[1] <- "Audi"
automarke_factor[1] Audi BMW Mercedes Benz Mercedes Benz Opel
[6] BMW
Levels: BMW Mercedes Benz Opel Audi
Intern werden die Faktorstufen als Integer abgespeichert (in der Reihenfolge der Faktorlevels beginnend mit 1, also hier: BMW = 1, Mercedes Benz = 2, Opel = 3 und Audi = 4). Wenn man einen Faktor in einen numeric umwandelt, entsprechen die Elemente diesen Werten.
as.numeric(automarke_factor)[1] 4 1 2 2 3 1
Bei der Definition oder dem Einlesen von Data Frames ermittelt R automatisch den optimalen Datentyp. character Variablen werden deshalb standardmäßig in factor umgewandelt. Dies lässt sich über die Option stringsAsFactors steuern, sehen Sie sich dazu die Hilfe der Funktion data.frame an!
Neben den hier vorgestellten Datentypen gibt es noch viele weitere, die jeweils für spezielle Aufgaben gedacht sind. So gibt es beispielsweise Datentypen für Datum, Zeitreihen, Geokoordinaten etc., welche an dieser Stelle nicht im Detail vorgestellt werden.
Ermitteln der Struktur eines Objektes
Strukturen von Objekten können sehr komplex und verschachtelt sein (z. B. Listen mit vielen verschiedenen Datentypen). Die Funktion str fasst die Struktur zusammen und macht sie so transparent. Sie gibt die interne Struktur eines R Objekts zurück. Für jedes grundlegende Strukturelement gibt sie eine Zeile mit den wesentlichen Informationen zurück. Für die Liste l ist dies der Typ, die Größe und einige Werte der Listenelemente.
str(l)List of 4
$ Vektor : int [1:10] 1 2 3 4 5 6 7 8 9 10
$ Matrix : int [1:3, 1:4] 1 2 3 4 5 6 7 8 9 10 ...
$ Array : int [1:2, 1:2, 1:3] 1 2 3 4 5 6 7 8 9 10 ...
$ Character: chr [1:3] "a" "b" "c"
Für den Data Frame df wird die Anzahl Beobachtungen und Variablen angegeben, sowie eine kurze Übersicht über jede einzelne Variable.
str(df)'data.frame': 5 obs. of 3 variables:
$ Name : chr "Mueller" "Meyer" "Schneider" "Meyer" ...
$ Alter : num 45 23 62 32 22
$ Premiumkunde: logi TRUE FALSE FALSE TRUE TRUE
Datenstrukturen
- Betrachten Sie den Data Frame
iris. Welchen Datentyp hat die VariableSpecies? - Betrachten Sie den im Paket
datasetsenthaltenen Datensatzmtcars. Welche der Spalten sind strenggenommen nicht metrisch? Ändern Sie entsprechend den Datentyp dieser Spalten!
2.3 Funktionen
Funktionen beinhalten einfache oder auch komplexe Rechenanweisungen. R enthält viele Standardfunktionen und weitere Funktionen in Paketen und kann durch eigene Funktionen erweitert werden (siehe Kapitel 2.7).
2.3.1 Aufruf von Funktionen
In der Regel hat eine Funktion einen Namen und kann durch diesen aufgerufen werden. Die Funktion, welche den Mittelwert berechnet, heißt mean. Um den Mittelwert zu berechnen, verwenden wir also mean(...), wobei wir für ... die Argumente der Funktion angeben. Welches die obligatorischen und optionalen Argumente bzw. Parameter sind, ist über die Hilfe zu erfahren (vgl. Kapitel 1.6).
Jede Funktion lässt sich auf unterschiedliche Arten mit ihren Argumenten aufrufen:
- Mit den Namen der Argumente: jedem Argument wird sein Name mit einem
=vorangestellt, z. B.
t.test(x = df$Alter, mu = 30, alternative = "two.sided")- Mit abgekürzten Namen, die R in der Regel erkennt, wenn sie eindeutig sind, z. B.
t.test(x = df$Alter, m = 30, alt = "two.sided")- Mit der Reihenfolge der Argumente: die Argumente können ohne Namen angegeben werden, wenn Sie exakt der Reihenfolge aus der Definition in der Hilfe folgen, z. B.
t.test(df$Alter, NULL, "two.sided", 30)Der Nachvollziehbarkeit zu Liebe und um Fehler zu vermeiden ist es sehr ratsam, stets der Option 1 bei Funktionsaufrufen zu folgen. Bei sehr einfachen Funktionen wie etwa sum kann der Name des Arguments weggelassen werden, wenn es sich nur um ein Argument handelt (z. B. sum(1:10)).
Nicht alle Funktionsaufrufe folgen dem Schema funktionsname(argument1, argument2), wie wir schon bei den arithmetischen Operationen wie + und - gesehen haben. Neben diesen gibt es noch weitere interessante elementare Funktion.
2.3.2 Elementare Funktionen
Mathematische Funktionen
Die Grundrechenarten +, -, *, /, ^ (Potenz), %% (\(x \pmod y\)), %/% (ganzzahlige Division) haben wir größtenteils schon kennengelernt. Diese sind für Skalare aber auch Vektoren, Matrizen etc. anwendbar.
Daneben existieren viele mathematischen Funktionen wie sum, prod, sqrt, sin, cos, log, exp und statistische Funktionen wie mean, var, sd, cov, cor, etc.
Logische Funktionen
Für Vergleiche nutzt man <, >, <= (kleiner gleich), >= (größer gleich), == (gleich), != (ungleich). Diese Vergleiche ergeben immer logische Werte. Hier sind einige Beispiele:
x <- 1:3
y <- c(1,2,5)
x < y[1] FALSE FALSE TRUE
x <= y[1] TRUE TRUE TRUE
x == y[1] TRUE TRUE FALSE
x != y[1] FALSE FALSE TRUE
Die apply Familie
Eine sehr nützliche Funktion ist apply und seine “Freunde”. Mit Hilfe von apply lassen sich Funktionen elementweise auf komplexe Datenstrukturen anwenden.
Die Funktion apply selbst erfordert dazu drei Argumente:
X: einematrix, einarrayoder auch eindata.frameMARGIN: ein Index(vektor) der angibt, über welche Dimensionen die Funktion angewendet werden sollFUN: die Funktion, welche elementweise angewendet werden soll
Wir können zum Beispiel über die Zeilen der Matrix m1 aufsummieren
apply(m1,1,sum)[1] 10 26 42
oder auch über die Spalten
apply(m1,2,sum)[1] 15 18 21 24
oder über die erste und zweite Dimension des Arrays a
apply(a,c(1,2),sum) [,1] [,2]
[1,] 15 21
[2,] 18 24
Für Listen existiert die lapply Funktion (“l” wie list), mit der eine Berechnung für jedes Element der Liste durchgeführt wird
lapply(l,is.numeric)$Vektor
[1] TRUE
$Matrix
[1] TRUE
$Array
[1] TRUE
$Character
[1] FALSE
Die Funktion sapply ist ebenfalls für Listen anzuwenden, sie versucht noch zusätzlich, das Ergebnis zu vereinfachen (“s” wie simplify). Wenn beispielsweise das Ergebnis der Berechnung für jedes Listenelement ein einzelner Wert ist, macht sapply daraus einen Vektor:
sapply(l,is.numeric) Vektor Matrix Array Character
TRUE TRUE TRUE FALSE
Die Funktion tapply ist nützlich, wenn man eine Aggregation von bestimmten Elementen eines Vektors durchführen möchte. Wir summieren nun alle Einträge der zweiten Spalte von m1 auf, für die die Werte der ersten Spalte \(>2\) sind.
tapply(m1[,2], list(m1[,1]>2), sum)FALSE TRUE
2 16
Für Data Frames bietet by eine ähnliche Funktionalität
by(df$Alter, df$Premiumkunde, mean)df$Premiumkunde: FALSE
[1] 42.5
------------------------------------------------------------
df$Premiumkunde: TRUE
[1] 33
Funktionen
- Finden Sie heraus, ob die Funktion
vardie empirische Varianz, also \[\frac{1}{n}\sum_{i=1}^n{\left(x_i - \bar{x}\right)^2}\] oder die korrigierte Stichprobenvarianz, also \[\frac{1}{n-1}\sum_{i=1}^n{\left(x_i - \bar{x}\right)^2}\] berechnet. - Erläutern Sie das Argument
useder Korrelationsfunktioncor. - Was machen die Funktionen
rep,sequndpaste?
2.4 Pipe-Operator in Base R
Seit R 4.1 gibt es in Base R den Pipe-Operator |>. Mit der Pipe wird das Ergebnis links als erstes Argument an die Funktion rechts weitergegeben.
x <- 1:10
x |> mean()[1] 5.5
Der große Vorteil: mehrere Verarbeitungsschritte lassen sich als klarer Ablauf von links nach rechts schreiben. Das entspricht oft genau dem gedanklichen Vorgehen bei einer Analyse.
Typische Vorteile sind:
- Bessere Lesbarkeit: statt stark verschachtelter Funktionsaufrufe stehen die einzelnen Schritte untereinander.
- Nachvollziehbare Reihenfolge: die Reihenfolge der Transformationen ist direkt sichtbar.
- Einfachere Fehlersuche: einzelne Schritte können leichter isoliert und getestet werden.
Damit kann man Verarbeitungsschritte übersichtlich hintereinander schreiben:
x <- c(1, 2, 3, 4, 100)
x |>
sqrt() |>
round(2)[1] 1.00 1.41 1.73 2.00 10.00
Ohne Pipe wäre dieselbe Berechnung stärker verschachtelt:
round(sqrt(x), 2)[1] 1.00 1.41 1.73 2.00 10.00
Der Unterschied wird bei längeren Ketten noch deutlicher:
x <- c(1, 2, 3, 4, 100)
x |>
log() |>
mean() |>
round(3)[1] 1.557
round(mean(log(x)), 3)[1] 1.557
Wichtig ist dabei: mit |> wird standardmäßig immer in das erste Argument der nächsten Funktion gepiped.
2.5 Logische Operatoren
Für logische Werte existieren einige nützliche Rechenoperationen (siehe Tabelle 2.1).
| Operator | Beschreibung |
|---|---|
! x |
nicht x also das Gegenteil von x: wenn x TRUE, dann ergibt sich FALSE |
x & y |
x und y: wenn beide TRUE, dann TRUE, sonst `FALSE |
x && y |
x und y: überprüft nur das erste Element von x und y |
x | y |
x oder y: wenn eines der beiden TRUE, dann TRUE, sonst `FALSE |
x || y |
x oder y: wenn eines der ersten Elemente der beiden TRUE, dann TRUE, sonst `FALSE |
xor(x,y) |
xor: elementweises exklusives “oder”, d.h. nur eines der beiden Elemente darf TRUE sein |
Ein Beispiel:
x <- c(TRUE, TRUE, FALSE, FALSE)
y <- c(TRUE, FALSE, TRUE, FALSE)
!x[1] FALSE FALSE TRUE TRUE
x & y[1] TRUE FALSE FALSE FALSE
x | y[1] TRUE TRUE TRUE FALSE
xor(x,y)[1] FALSE TRUE TRUE FALSE
Außerdem sind für logische Werte die Funktionen any, all, which und %in% sehr nützlich:
x <- 5:1
x[1] 5 4 3 2 1
x > 3[1] TRUE TRUE FALSE FALSE FALSE
any(x < 2)[1] TRUE
which(x < 2)[1] 5
which.max(x)[1] 1
all(x != 0)[1] TRUE
5:7 %in% x[1] TRUE FALSE FALSE
x %in% 5:7[1] TRUE FALSE FALSE FALSE FALSE
Die wichtigsten Funktionen in R sind dem Base R Cheat Sheet oder der R Reference Card zu finden.
Logische Operatoren
- Schauen Sie sich die Hilfe Seiten zu den Funktionen
any,all,whichund%in%an und beschreiben Sie deren Funktionalität. - Mit welchen Befehlen können Sie die Funktion
which.maxnachbilden?
2.6 Kontrollstrukturen
R ist eine vollwertige Programmiersprache und beherrscht deshalb auch Kontrollstrukturen, welche den Programmablauf steuern. Diese werden verwendet, um Anweisungen nur unter bestimmten Voraussetzungen durchzuführen (Bedingte Anweisungen) oder Anweisungen wiederholt auszuführen bzw. solange, bis eine bestimmte Bedingung erfüllt ist (Schleifen). Sie werden sehen, dass gerade diese Elemente von R einen sehr großen Vorteil gegenüber Statistiksoftware mit einer Steuerung per Benutzeroberfläche bieten.
2.6.1 Bedingte Anweisungen
Möchten wir eine Berechnung nur ausführen, wenn eine gewisse Voraussetzung erfüllt ist, so können wir dies mit einem if Statement realisieren, dessen grundlegende Struktur wie folgt aussieht:
if (<Bedingung>){
<Konsequenz>
} Das Stichwort if wird gefolgt von einer Bedingung in runden Klammern, die einen eindeutigen logischen Wert ergeben muss. Ist dieser TRUE, wird der Code in den folgenden geschweiften Klammern ausgeführt. Falls die Bedingung nicht zutrifft, also gleich FALSE ist, werden die Anweisungen in den geschweiften Klammern übersprungen und der nachfolgende Code ausgeführt.
Es kann auch konkret angegeben werden, welcher Code in dem Fall ausgeführt werden soll, falls die Bedingung nicht erfüllt ist. Dieser Code folgt nach einem else und wird nur für den Fall durchgeführt, wenn die Bedingung FALSE ist.
if (<Bedingung>){
<Konsequenz>
} else {
<Alternative>
}Ein konkretes Beispiel:
x <- 5
if(x>5){
y <- 1
} else {
y <- 2
}
y[1] 2
Möchte man noch weitere Fallunterscheidungen mit mehreren Alternativen abbilden, geht dies über eine Verschachtelung mehrerer if und else Statements der Form
if (<Bedingung>){
<Konsequenz>
} else if (<Bedingung2>) {
<Konsequenz2>
} else {
<Alternative>
}Eine einfachere Variante für Vektoren ist die Funktion ifelse. Die Bedingung wird elementweise im Vektor geprüft und dann entweder für den Fall TRUE die Konsequenz ausgegeben und für FALSE die Alternative
ifelse(<Bedingung>, <Konsequenz>, <Alternative>)Im Beispiel mit unserem Data Frame
df$Premiumkunde <- ifelse(df$Name == "Meyer" & df$Alter >30, TRUE, FALSE)
df Name Alter Premiumkunde
1 Mueller 45 FALSE
2 Meyer 23 FALSE
3 Schneider 62 FALSE
4 Meyer 32 TRUE
5 Meier 22 FALSE
2.6.2 Schleifen
Mit Hilfe von Schleifen können wir sich wiederholende Aufgaben automatisieren.
for Schleife
Die gängigste Schleife in R wiederholt sich solange, wie wir dies durch einen Indexvektor vorgeben. Ihre allgemeine Form ist wie folgt:
for (<Zähler> in <Index>){
<Ausdruck>
}Der Indexvektor wird dabei von Anfang bis Ende durchlaufen. Möchten wir beispielsweise eine Berechnung für jede Zeile in einem Datensatz durchführen, können wir eine for Schleife über alle Zeilen des Datensatzes laufen lassen.
df$Geburtsjahr <- NULL
for (i in 1:nrow(df)){
df$Geburtsjahr[i] <- 2018-df$Alter[i]
}
df Name Alter Premiumkunde Geburtsjahr
1 Mueller 45 FALSE 1973
2 Meyer 23 FALSE 1995
3 Schneider 62 FALSE 1956
4 Meyer 32 TRUE 1986
5 Meier 22 FALSE 1996
while Schleife
Mit einer while Schleife wird eine Anweisung solange ausgeführt wie eine vorgegebene Bedingung noch erfüllt (also gleich TRUE ist). Allgemein hat solche eine Schleife die Form
while (<Bedingung>){
<Ausdruck>
}i <- 0
while (i < 10){
i <- i+1
result <- 2^i
}
result[1] 1024
repeat Schleife
Die repeat Schleife wiederholt eine Anweisung solange, bis ein Abbruchkriterium erfüllt ist. Dafür wird die Funktion break verwendet:
repeat {
<Ausdruck>
if (<Bedingung>){
break
}
}Ein Beispiel
a <- 1
repeat {
a <- a*2
if (a>100){
break
}
}
a[1] 128
Es kann schnell passieren, dass man unendliche Schleifen erstellt. Das passiert, wenn das Abbruchkriterium nie eintritt. In diesem Fall muss dann eventuell die R Session beendet werden, um der Schleife ein Ende zu setzen.
Kontrollstrukturen
- Die Reihendarstellung des natürlichen Logarithmus ist gegeben durch \[ \begin{split} \ln(1+x) & = -\sum_{i=0}^{\infty}{\frac{(-x)^{i+1}}{i+1}} \\ & = x - \frac{x^2}{2} + \frac{x^3}{3} - \frac{x^4}{4} + \dots \end{split}\] für \(-1<x\leq 1\). Nutzen Sie eine Schleife, um die ersten 1.000 Summanden der Reihe für \(x = 1\) zu berechnen und aufzusummieren. Vergleichen Sie das Ergebnis mit der in R implementierten Berechnung des natürlichen Logarithmus!
- Schreiben Sie eine Schleife, welche den natürlichen Logarithmus von 2 mit Hilfe der Reihendarstellung (siehe Aufgabe 1) bis auf 4 Nachkommastellen genau berechnet und führen Sie die Berechnung aus.
2.7 Eigene Funktionen
Berechnungen mit mehreren Schritten, die man häufiger verwenden möchte, kann man in eigenen Funktionen implementieren. Diese stehen dann wie die Standardfunktionen in R zur Verfügung.
Funktionen werden wie Objekte über eine Zuweisung definiert. Nach dem Schlüsselwort function werden dann die Argumente festgelegt und anschließend in geschweiften Klammern die Berechnungsschritte bzw. der Algorithmus angegeben. Mit einem return wird am Ende festgelegt, welche Outputs die Funktion zurückgibt. Allgemein folgt die Funktionsdefinition also der Form:
funktionsname <- function(<Argumente>){
<Funktionsbefehle>
return(<Ergebnisse>)
}Ein Beispiel: müssen wir häufiger Temperaturen von Celsius (\(T_{^\circ C}\)) in Kelvin (\(T_{^\circ C}\)) und Fahrenheit (\(T_{^\circ F}\))) umrechnen, wäre es sehr umständlich, jedes Mal die entsprechenden Rechenschritte zu tippen. Für die Umrechnung der Einheiten gilt: \[ T_{^\circ F} = \frac{9}{5} T_{^\circ C} + 32\] und \[ T_{^\circ K} = T_{^\circ C} + 273.15 \]
Wir können dies nun in einer Funktion abbilden. Diese nimmt als einziges Argument die Temperatur in Celsius entgegen (temp_C) und gibt die Temperatur in Kelvin (temp_K) und Fahrenheit (temp_F) zurück:
celsius_to_kelvin_fahrenheit <- function(temp_C) {
temp_F <- temp_C * 9/5 + 32
temp_K <- temp_C + 273.15
return(list(temp_F = temp_F, temp_K = temp_K))
}
# Gefrierpunkt von Wasser
celsius_to_kelvin_fahrenheit(0)$temp_F
[1] 32
$temp_K
[1] 273.15
Mit einer Funktion lassen sich beliebig viele Rechenschritte abbilden. Es hat sich aber als gute Praxis erwiesen, große Berechnungen in viele kleinere Funktionen aufzuteilen, die die verschiedenen Teilaufgaben übernehmen. Soll eine Funktion mehr als ein Objekt zurückgeben, so werden diese Objekte typischerweise in einer Liste gesammelt.
Das Ergebnis der Funktion kann dann einem Objekt zugewiesen werden und auf die einzelnen Elemente per $ zugegriffen werden. So sind die meisten Funktionen in R aufgebaut.
# Siedepunkt von Wasser
boiling_point <- celsius_to_kelvin_fahrenheit(100)
boiling_point$temp_F[1] 212
boiling_point$temp_K[1] 373.15
Um Funktionen zu steuern, z. B. Warnungen auszugeben, wenn Argumente nicht korrekt angegeben wurden oder sogar die Funktion mit einem Fehler abzubrechen, wenn eine Berechnung gar nicht möglich ist, gibt es spezielle Funktionen wie warning oder stop.
Um während der Berechnungen ein Update zum Status zu geben, kann mit der Funktion cat Text auf der Konsole ausgegeben werden oder in eine Log-Datei geschrieben werden.
Jede Funktion ist in R ebenfalls als Objekt abgelegt. Das bedeutet, dass man sich genau wie bei Objekten, den Inhalt des Objekts – in diesem Fall den Code – ansehen kann, indem man den Funktionsnamen (ohne Klammern) einfach in der Konsole ausführt.
Um Beispielsweise den Code zu sehen, der der Funktion celsius_to_kelvin_fahrenheit zugrunde liegt, kann man einfach in der Konsole ausführen:
celsius_to_kelvin_fahrenheitfunction (temp_C)
{
temp_F <- temp_C * 9/5 + 32
temp_K <- temp_C + 273.15
return(list(temp_F = temp_F, temp_K = temp_K))
}
<bytecode: 0x5595890f6ae0>
Dies gilt auch für die Standard-Funktionen in R, z. B. factor
factorfunction (x = character(), levels, labels = levels, exclude = NA,
ordered = is.ordered(x), nmax = NA)
{
if (is.null(x))
x <- character()
nx <- names(x)
matchAsChar <- is.object(x) || !(is.character(x) || is.integer(x) ||
is.logical(x))
if (missing(levels)) {
y <- unique(x, nmax = nmax)
ind <- order(y)
if (matchAsChar)
y <- as.character(y)
levels <- unique(y[ind])
}
force(ordered)
if (matchAsChar)
x <- as.character(x)
levels <- levels[is.na(match(levels, exclude))]
f <- match(x, levels)
if (!is.null(nx))
names(f) <- nx
if (missing(labels)) {
levels(f) <- as.character(levels)
}
else {
nlab <- length(labels)
if (nlab == length(levels)) {
nlevs <- unique(xlevs <- as.character(labels))
at <- attributes(f)
at$levels <- nlevs
f <- match(xlevs, nlevs)[f]
attributes(f) <- at
}
else if (nlab == 1L)
levels(f) <- paste0(labels, seq_along(levels))
else stop(gettextf("invalid 'labels'; length %d should be 1 or %d",
nlab, length(levels)), domain = NA)
}
class(f) <- c(if (ordered) "ordered", "factor")
f
}
<bytecode: 0x559587e1f9a8>
<environment: namespace:base>
Einige Funktionen sind als Methode implementiert und agieren unterschiedlich, je nachdem, auf was für ein Objekt sie angewendet werden. Mit Hilfe der Funktion method kann man diese Methoden ermitteln. So gibt es beispielsweise für die Funktion mean unter anderem die Methoden mean.Date (für Datumswerte) und mean.default (Standard, für metrische Merkmale). Den Quellcode der Funktion erhalten wir dann mit Hilfe von getAnywhere(mean.default).
Nicht jede Funktion ist komplett in R Code implementiert. Einige Funktionen verwenden Subroutinen, die aus Gründen der Rechengeschwindigkeit in einer anderen Sprache wie etwa C oder FORTRAN implementiert sind (z. B. sum). Dieser Quellcode lässt sich entweder in dem entsprechenden Quellcode des Pakets auf CRAN einsehen oder für Funktionen aus dem R Basispaket wie bei Ligges (2006) beschrieben.
2.8 Kommentare
Kommentierung von Code ist extrem wichtig, wenn man sich nach einiger Zeit wieder mit einem geschriebenen Programm beschäftigen möchte. Ohne Kommentare ist es sehr mühsam, geschriebenen Code nachzuvollziehen. Daher ist es unbedingt notwendig, R Programme ausführlich im Code zu kommentierten bzw. dokumentieren.
Kommentare können in R über die Raute # erfolgen. Im Code wird der gesamte Inhalt einer Zeile, der nach einer # folgt, nicht mehr ausgeführt. Dies kann man nutzen, um im Code Kommentare zu hinterlassen. Dabei kann die mehrfache Verwendung von # eine Art Hierarchie der Kommentare erreichen.
Ein Beispiel:
### Berechnung des Geburtsjahres der Kunden über das Alter
# Erstellen einer neuen Spalte 'Geburtsjahr' im Data Frame `df`
df$Geburtsjahr <- NULL
# Gehe durch alle Zeilen des Datensatzes und berechne Geburtsjahr
for (i in 1:nrow(df)){
df$Geburtsjahr[i] <- 2018-df$Alter[i] # Geburtstjahr = aktuelles Jahr - aktuelles Alter
}
# Prüfe das Ergebnis
dfEs hat sich als gute Praxis erwiesen, den Code in lesbare und schlüssige Abschnitte aufzuteilen. Um die Abschnitte deutlich hervorzuheben, können horizontale Linien eingefügt werden.
# Einlesen der Daten ----------------------------------------
<Code>
# Visualisierung der Daten ----------------------------------
<Code>Alternativ können auch hier durch unterschiedliches Hervorheben Hierarchien geschaffen werden:
# ============================================================
# Datenvorverarbeitung
# ============================================================
# ------------------------------------------------------------
# Daten einlesen
# ------------------------------------------------------------
<Code>
# ------------------------------------------------------------
# Daten visualisieren
# ------------------------------------------------------------
<Code>Für jede .R Datei bietet sich auch die Gestaltung eines Titels an, der vor dem gesamten Code steht und Informationen beinhaltet zu Zweck des Codes, Autor, benötigte Pakete etc.
# ============================================================
# Datei: Churnanalyse.R
# Autor: Michael Bücker
# benötigte Pakete: randomForest, rpart
# Beschreibung: Der Code dient der Analyse des
# Churn-Verhaltens von ...
# ============================================================
<Code>Neben einer ausführlichen und aussagekräftigen Kommentierung des Codes unterstützt auch ein einheitlicher Stil und lesbares Format die Nachvollziehbarkeit für den Autor selbst und andere. Dazu haben sich einige R-Programmierer zu einem “guten Stil” Gedanken gemacht. Es sind verschiedene (sich manchmal in einigen Punkten widersprechende) Style Guides entstanden:
In dieser Veranstaltung und den weiteren Vorlesungen im Erweiterungsmodul QM II wollen wir uns so gut es geht an den tidyverse style guide halten.
Eigene Funktionen
- Schreiben Sie eine Funktion, welche die ersten \(n\) Elemente der Fibonacci-Folge zurückgibt. Speichern Sie die Funktion in einem Skript ab.
- Schreiben Sie eine Funktion, welche alle fehlenden Werte eines Data Frames durch den entsprechenden Spaltenmittelwert ersetzt (falls die Spalte
numericist) oder durch den Modus ersetzt (falls die Spalte nichtnumericist). Kommentieren Sie Ihren Code! Speichern Sie die Funktion in einem Skript ab.
2.9 RStudio Projekte
Für größere Projekte in R, bei denen viel Code – möglicherweise auf mehrere .R Dateien verteilt – erstellt wird, sollten RStudio Projekte verwendet werden. Diese Projekte bündeln alle dazugehörigen .R Dateien, Daten und erlaubt eine Versionskontrolle (siehe Kapitel 2.10).
Neue Projekte können über das Menü in RStudio erstellt werden (siehe Abbildung 2.3).
Eine ausführliche Beschreibung und Anleitung zu RStudio Projekten finden Sie unter support.rstudio.com.
2.10 Versionskontrolle
Die Versionskontrollsysteme Git und Subversion können in Verbindung mit RStudio Projekten genutzt werden (vgl. Abbildung 2.4). Dies ist bei der Erstellung eines Projekts möglich.
Weitere Details zu Versionskontrolle in RStudio finden Sie unter support.rstudio.com.
Eine detallierte Beschreibung zur Verwendung von Git als Versionskontrollsystem im Rahmen dieser Vorlesung unter Verwendung des FH-eigenen GitLab Servers innerhalb von RStudio bzw. Posit finden Sie hier.
2.11 Eigene Pakete
Möchten Sie mehrere eigene Funktionen häufig wiederverwenden und möglicherweise anderen Personen, z. B. Kollegen oder gar der Öffentlichkeit zur Verfügung stellen, können Sie diese als Paket bündeln und diesen Personen schicken bzw. das Paket auf CRAN oder GitHub veröffentlichen.
RStudio bietet ein Interface zur vereinfachten Erstellung von Paketen (siehe Abbildung 2.5).
Weitere Details zur Erstellen von Paketen in RStudio finden Sie unter support.rstudio.com.
RStudio Projekte
- Legen Sie ein neues RStudio Projekt in Ihrem Übungsverzeichnis an.
- Legen Sie Ihre Funktionen aus den Aufgaben zu eigenen Funktionen in dem Projekt ab.
- Schließen Sie das Projekt wieder und löschen Sie es.
Beachten Sie: Da es sich um ein Linux-System handelt, werden Ordner nicht durch einen Backslash “\” sondern einen gewöhnlichen Slash “/” getrennt. Auf einem Windows System muss man ebenfalls die Linux-Schreibweise, also “/” verwenden.↩︎
Der Datensatz liegt streng genommen in der Environment des Pakets
datasets. Da dieses Paket beim Start von R automatisch geladen wird, ist der Datensatz immer verfügbar.↩︎