29  data.table – Statistik mit R und RStudio (2024)

Author

Affiliation

Jörg große Schlarmann 29 data.table – Statistik mit R und RStudio (1)

Neben dem zuvor besprochenen tidyverse steht mit data.table ein weiterer R-Dialekt zur Verfügung, der sich immer größerer Beliebtheit erfreut. Im Kern sind data.tables verbesserte Versionen von data.frames, die schneller und speichereffizienter arbeiten und mit einer prägnanteren Syntax manipuliert werden können. Das Paket stellt außerdem eine Reihe zusätzlicher Funktionen zum Lesen und Schreiben von tabellarischen Dateien, zum Umformen von Daten zwischen langen und breiten Formaten und zum Verbinden von Datensätzen zur Verfügung.

29.1 Installation

Alle Funktionen sind über das Paket data.table implementiert, welches wie gewohnt installiert und aktiviert werden kann.

# installiere data.tableinstall.packages("data.table", dependencies=TRUE)
# data.table aktivierenlibrary(data.table)

29.2 Modify-in-Place

Der größte Unterschied besteht darin, dass data.table die Modify-in-Place-Methode verwendet. Das klassische R und auch das Tidyverse verwenden die Copy-on-Modify-Methode, welche besagt, dass bei der Manipulation eines Objektes das Ergebnis in einem neuen Objekt gespeichert wird.

# klassisches "Copy-on-Modify"meine.daten %>%  mutate(Neu = Alt*10)

Bei oben stehendem Code wird das Objekt meine.daten nicht verändert. Das Ergebnis der mutate()-Funktion wird als neues Objekt ausgegeben. Dieses neue Objekt ist eine Kopie der Ursprungsdaten meine.daten, an welcher die Veränderungen vorgenommen werden.

Mit data.table wird der Ansatz Modify-in-Place verfolgt.

# Modify-in-Placemeine.daten[, Neu := Alt*10]

Der oben stehende Code erzeugt keine Kopie von meine.daten. Vielmehr wird das Objekt meine.daten direkt verändert. Im klassischen R entspricht diese Vorgehensweise dem Code

meine.daten$Neu <- meine.daten$Alt*10

Durch Modify-in-Place wird data.table sehr effizient, wenn größere Datenmengen verarbeitet werden sollen. Es kann jedoch auch dazu führen, dass der Code schwieriger zu verstehen ist und überraschende Ergebnisse liefert (insbesondere, wenn ein data.table innerhalb einer Funktion modifiziert wird).

29.3 Grundlegende Syntax

Die generelle Syntax von data.table lautet

dt[i, j, by]

wobei

  • dt ein data.table-Objekt ist.
  • i zum Filtern und für join-Funktionen genutzt wird.
  • j zum Manipulieren, Transformieren und Zusammenfassen der Daten verwendet wird.
  • by zum Gruppieren genutzt wird.

Man kann die Syntax lesen als:

„In diesen Zeilen, mache dies, gruppiert nach jenem“.

29.4 Daten einlesen

Der erste Schritt der meisten Datenanalysen besteht darin, Daten in den Speicher zu laden. Wir können die Funktion data.table::fread() verwenden (das f steht für fast (schnell)), um reguläre, durch Trennzeichen getrennte Dateien wie txt- oder csv-Dateien zu lesen. Diese Funktion ist nicht nur schnell, sondern erkennt automatisch das Trennzeichen und errät die Klasse jeder Spalte sowie die Anzahl der Zeilen in der Datei.

# Daten einlesen mit fread()dt <- fread("data/Befragung22.csv")# anschauenstr(dt)
Classes 'data.table' and 'data.frame': 37 obs. of 6 variables: $ alter : int 20 28 41 34 26 38 28 21 27 26 ... $ geschlecht: chr "weiblich" "weiblich" "männlich" "weiblich" ... $ stifte : int 12 7 1 13 18 25 29 1 2 5 ... $ geburtsort: chr "Düren" "Neuss" "Bonn" "Düsseldorf" ... $ fahrzeit : int 1 45 60 25 15 50 40 60 60 40 ... $ podcast : chr "selten" "selten" "selten" "oft" ... - attr(*, ".internal.selfref")=<externalptr> 

Das Objekt dt gehört sowohl zur Klasse data.frame als auch zu der neuen Klasse data.table.

Die Daten können auch direkt über eine URL eingelesen werden.

# lade per URLdt <- fread("https://www.produnis.de/R/data/Befragung22.csv")

Liegen die Daten bereits als data.frame vor, können sie per as.data.table() umgewandelt werden.

# lade klassisches Datenframedf <- read.table("https://www.produnis.de/R/data/Datentabelle.txt",  header=TRUE)# wandle in data.table umdt2 <- as.data.table(df)
Classes 'data.table' and 'data.frame': 10 obs. of 4 variables: $ Geschlecht: chr "m" "w" "w" "m" ... $ Alter : int 28 18 25 29 21 19 27 26 31 22 $ Gewicht : int 80 55 74 101 84 74 65 56 88 78 $ Groesse : int 170 174 183 190 185 178 169 163 189 184 - attr(*, ".internal.selfref")=<externalptr> 

Sollen die Daten von Hand eingegeben werden, wird die Funktion data.table() verwendet.

# erzeuge von Handdt3 <- data.table(x = 1:10, y = 11:20, z = factor(rep(c("foo", "bar"), 5)) )# anschauenstr(dt3)
Classes 'data.table' and 'data.frame': 10 obs. of 3 variables: $ x: int 1 2 3 4 5 6 7 8 9 10 $ y: int 11 12 13 14 15 16 17 18 19 20 $ z: Factor w/ 2 levels "bar","foo": 2 1 2 1 2 1 2 1 2 1 - attr(*, ".internal.selfref")=<externalptr> 

29.5 Daten speichern

Mit der Funktion fwrite() können data.tables (aber auch data.frames) in eine Datei gespeichert werden. Sie funktioniert ähnlich wie write.csv, ist aber wesentlich schneller. Wird kein Dateiname angegeben, erfolgt die Ausgabe in der Konsole. So kann überprüft werden, was in die Datei geschrieben würde.

# schreibe Objekt "dt2" in die Konsolefwrite(dt2)
Geschlecht,Alter,Gewicht,Groessem,28,80,170w,18,55,174w,25,74,183m,29,101,190m,21,84,185w,19,74,178w,27,65,169w,26,56,163m,31,88,189m,22,78,184
# schreibe Objekt "dt" in datei "dt.csv"fwrite(dt2, "dt2.csv")# schreibe Objekt "dt" in datei "dt.txt"fwrite(dt2, "dt2.txt")

29.6 Fälle filtern mit i

Wir erinnern uns, dass die allgemeine Syntax dt[i, j, by] lautet. Über den Parameter i können die Daten gefilter werden, so dass nur bestimmte Fälle berücksichtigt werden. Beispielsweise könnten wir im Objekt dt nur solche Fälle auswählen, bei denen das Alter größer als 30 ist.

dt[alter > 30]
 alter geschlecht stifte geburtsort fahrzeit podcast <int> <char> <int> <char> <int> <char>1: 41 männlich 1 Bonn 60 selten2: 34 weiblich 13 Düsseldorf 25 oft3: 38 weiblich 25 Dinslaken 50 oft4: 38 männlich 5 Donezk 57 manchmal5: 31 weiblich 16 Charkov Ukraine 135 oft6: 36 weiblich 1 Rybnik 90 manchmal7: 45 männlich 1 Gelsenkirchen 85 oft

Dies ist Vergleichbar mit dem klassischen R-Aufruf

# klassischer R-Befehldt[dt$alter > 30]
 alter geschlecht stifte geburtsort fahrzeit podcast <int> <char> <int> <char> <int> <char>1: 41 männlich 1 Bonn 60 selten2: 34 weiblich 13 Düsseldorf 25 oft3: 38 weiblich 25 Dinslaken 50 oft4: 38 männlich 5 Donezk 57 manchmal5: 31 weiblich 16 Charkov Ukraine 135 oft6: 36 weiblich 1 Rybnik 90 manchmal7: 45 männlich 1 Gelsenkirchen 85 oft

Da alle Ausdrücke in i im Kontext der data.table ausgewertet werden, müssen wir den (eventuell sehr langen) Namen des Objektes nicht erneut eingeben. Dies ist vor allem bei längeren Ausdrücken sehr bequem.

# erzeuge langen Objektnamenlanger.Objekt.name <- dt

Der klassische R-Aufruf

# klassischer R-Befehllanger.Objekt.name[langer.Objekt.name$alter > 25 &  langer.Objekt.name$geschlecht=="männlich" |  langer.Objekt.name$stifte > 30]
 alter geschlecht stifte geburtsort fahrzeit podcast <int> <char> <int> <char> <int> <char>1: 41 männlich 1 Bonn 60 selten2: 26 männlich 5 Düsseldorf 40 nie3: 38 männlich 5 Donezk 57 manchmal4: 20 weiblich 32 Wesel 89 nie5: 45 männlich 1 Gelsenkirchen 85 oft

verkürzt sich auf

langer.Objekt.name[alter > 25 & geschlecht=="männlich" | stifte > 30]
 alter geschlecht stifte geburtsort fahrzeit podcast <int> <char> <int> <char> <int> <char>1: 41 männlich 1 Bonn 60 selten2: 26 männlich 5 Düsseldorf 40 nie3: 38 männlich 5 Donezk 57 manchmal4: 20 weiblich 32 Wesel 89 nie5: 45 männlich 1 Gelsenkirchen 85 oft

29.7 Fälle sortieren mit i

Dem Parameter i können auch Funktionen übergeben werden. So lassen sich die Daten beispielsweise über die order()-Funktion sortieren.

# nehme anderen (kürzeren) Datensatz zur Demonstrationdt2[order(Alter)]
 Geschlecht Alter Gewicht Groesse <char> <int> <int> <int> 1: w 18 55 174 2: w 19 74 178 3: m 21 84 185 4: m 22 78 184 5: w 25 74 183 6: w 26 56 163 7: w 27 65 169 8: m 28 80 170 9: m 29 101 19010: m 31 88 189
# absteigenddt2[order(Gewicht, decreasing = TRUE)]
 Geschlecht Alter Gewicht Groesse <char> <int> <int> <int> 1: m 29 101 190 2: m 31 88 189 3: m 21 84 185 4: m 28 80 170 5: m 22 78 184 6: w 25 74 183 7: w 19 74 178 8: w 27 65 169 9: w 26 56 16310: w 18 55 174

29.8 Daten verarbeiten mit j

Nachdem der Datensatz mittels i eventuell vorsortiert und -gefiltert wurde, erfolgen die eigentlichen Operationen über den Parameter j. So können wir den Mittelwert des Alters der Probanden wie folgt bestimmen:

# Mittelwert des Altersdt[, mean(alter)]
[1] 25.2973
# Mittelwert des Alters der Männerdt[geschlecht == "männlich", mean(alter)]
[1] 29

Innerhalb von j kann jede Funktion verwendet werden. So könnten wir überprüfen, ob die Variablen fahrzeit und alter miteinander korrelieren (ja, das ist quatsch).

# korrelieren alter und fahrzeit? dt[, cor(alter, fahrzeit)]
[1] 0.1504465

Es können auch mehrere Funktionen angewendet werden. Hierfür müssen diese per list() an den Parameter j übergeben werden. Auf diese Weise könnten wir Median, Mittelwert und Standardabweichung des Alters der Probanden bestimmen.

# mehrere Funktionen per list()dt[, list(Median = median(alter), Mittelw = mean(alter), Stdabw = sd(alter))]
 Median Mittelw Stdabw <int> <num> <num>1: 22 25.2973 6.765373

Da der Parameter j immer eine Liste erwartet, kann die Funktion list() mit einem Punkt abgekürzt werden.

# geht auch mit "."dt[, .(Median = median(alter), Mittelw = mean(alter), Stdabw = sd(alter), InterquA = IQR(alter))]
 Median Mittelw Stdabw InterquA <int> <num> <num> <num>1: 22 25.2973 6.765373 6

29.9 Daten bearbeiten mit j

Über den Parameter j können die Daten auch manipuliert werden, ähnlich wie bei der mutate()-Funktion des Tidyverse. Eine neue Variable kann über die Zeichenkette := definiert werden (dem so genannten Walrus Operator (Walross-Operator), der so heisst, weil die Zeichenfolge := an die Stoßzähne eines Walrosses erinnert. Das Logo des data.table-Pakets zeigt eine Robbe, was zur humorvollen Verbindung beigetragen hat).

Mit folgendem Aufruf erzeugen wir eine neue Variable FahrzeitH, welche die fahrzeit in Stunden beinhalten soll.

# FahrzeitH in Stundendt[, FahrzeitH := fahrzeit/60]# anzeigenstr(dt)
Classes 'data.table' and 'data.frame': 37 obs. of 7 variables: $ alter : int 20 28 41 34 26 38 28 21 27 26 ... $ geschlecht: chr "weiblich" "weiblich" "männlich" "weiblich" ... $ stifte : int 12 7 1 13 18 25 29 1 2 5 ... $ geburtsort: chr "Düren" "Neuss" "Bonn" "Düsseldorf" ... $ fahrzeit : int 1 45 60 25 15 50 40 60 60 40 ... $ podcast : chr "selten" "selten" "selten" "oft" ... $ FahrzeitH : num 0.0167 0.75 1 0.4167 0.25 ... - attr(*, ".internal.selfref")=<externalptr> - attr(*, "index")= int(0) ..- attr(*, "__geschlecht")= int [1:37] 3 8 10 11 13 31 33 34 37 1 ...

So können wir auch mittels der cut()-Funktion die Daten klassieren, zum Beispiel das Alter:

dt[, alterK := cut(alter, breaks=c(0,20,25,30,40,50), ordered=TRUE)]# anzeigenstr(dt)
Classes 'data.table' and 'data.frame': 37 obs. of 8 variables: $ alter : int 20 28 41 34 26 38 28 21 27 26 ... $ geschlecht: chr "weiblich" "weiblich" "männlich" "weiblich" ... $ stifte : int 12 7 1 13 18 25 29 1 2 5 ... $ geburtsort: chr "Düren" "Neuss" "Bonn" "Düsseldorf" ... $ fahrzeit : int 1 45 60 25 15 50 40 60 60 40 ... $ podcast : chr "selten" "selten" "selten" "oft" ... $ FahrzeitH : num 0.0167 0.75 1 0.4167 0.25 ... $ alterK : Ord.factor w/ 5 levels "(0,20]"<"(20,25]"<..: 1 3 5 4 3 4 3 2 3 3 ... - attr(*, ".internal.selfref")=<externalptr> - attr(*, "index")= int(0) ..- attr(*, "__geschlecht")= int [1:37] 3 8 10 11 13 31 33 34 37 1 ...

Pro Aufruf kann der Walross-Operator nur einmal verwendet werden. Sollen mehrere Variablen verändert oder hinzugefügt werden, steht die let()-Funktion bereit. Innerhalb von let() werden wie gewohnt einfache Gleichheitszeichen verwendet.

# mehrere Manipulationen per let()dt[, let(geschlecht = factor(geschlecht), geburtsort = factor(geburtsort), podcast = factor(podcast, ordered=TRUE, levels=c("nie", "selten", "manchmal",  "oft", "immer")))]# anzeigenstr(dt)
Classes 'data.table' and 'data.frame': 37 obs. of 8 variables: $ alter : int 20 28 41 34 26 38 28 21 27 26 ... $ geschlecht: Factor w/ 2 levels "männlich","weiblich": 2 2 1 2 2 2 2 1 2 1 ... $ stifte : int 12 7 1 13 18 25 29 1 2 5 ... $ geburtsort: Factor w/ 26 levels "Bagdad","Bonn",..: 9 21 2 10 8 5 21 7 18 10 ... $ fahrzeit : int 1 45 60 25 15 50 40 60 60 40 ... $ podcast : Ord.factor w/ 5 levels "nie"<"selten"<..: 2 2 2 4 NA 4 4 3 1 1 ... $ FahrzeitH : num 0.0167 0.75 1 0.4167 0.25 ... $ alterK : Ord.factor w/ 5 levels "(0,20]"<"(20,25]"<..: 1 3 5 4 3 4 3 2 3 3 ... - attr(*, ".internal.selfref")=<externalptr> - attr(*, "index")= int(0) 

Die Änderungen wurden direkt im Objekt dt gespeichert.

29.10 data.table kopieren

Eine weitere wesentliche Eigenschaft von data.table-Objekten besteht darin, dass man sie gesondert kopieren muss. Wir eine data.table auf klassischem Wege in ein neues Objekt “kopiert”, so erfolgt keine echte Kopie, sondern lediglich ein symbolischer Link auf das ursprüngliche Objekt.

# weise dt einem neuen Objekt zuneu <- dtstr(neu)
Classes 'data.table' and 'data.frame': 37 obs. of 8 variables: $ alter : int 20 28 41 34 26 38 28 21 27 26 ... $ geschlecht: Factor w/ 2 levels "männlich","weiblich": 2 2 1 2 2 2 2 1 2 1 ... $ stifte : int 12 7 1 13 18 25 29 1 2 5 ... $ geburtsort: Factor w/ 26 levels "Bagdad","Bonn",..: 9 21 2 10 8 5 21 7 18 10 ... $ fahrzeit : int 1 45 60 25 15 50 40 60 60 40 ... $ podcast : Ord.factor w/ 5 levels "nie"<"selten"<..: 2 2 2 4 NA 4 4 3 1 1 ... $ FahrzeitH : num 0.0167 0.75 1 0.4167 0.25 ... $ alterK : Ord.factor w/ 5 levels "(0,20]"<"(20,25]"<..: 1 3 5 4 3 4 3 2 3 3 ... - attr(*, ".internal.selfref")=<externalptr> - attr(*, "index")= int(0) 

Wir haben das Objekt dt nur scheinbar in das neue Objekt neu kopiert. Wenn wir Änderungen am Objekt neu vornehmen, so sind diese auch im Objekt dt präsent, weil eben nicht kopiert, sondern nur ein Verweis erstellt wurde.

# erstelle neue Variable in "neu"neu[, kuckuck := fahrzeit * stifte]# die neue Variable ist auch in "dt" enthaltenstr(dt)
Classes 'data.table' and 'data.frame': 37 obs. of 9 variables: $ alter : int 20 28 41 34 26 38 28 21 27 26 ... $ geschlecht: Factor w/ 2 levels "männlich","weiblich": 2 2 1 2 2 2 2 1 2 1 ... $ stifte : int 12 7 1 13 18 25 29 1 2 5 ... $ geburtsort: Factor w/ 26 levels "Bagdad","Bonn",..: 9 21 2 10 8 5 21 7 18 10 ... $ fahrzeit : int 1 45 60 25 15 50 40 60 60 40 ... $ podcast : Ord.factor w/ 5 levels "nie"<"selten"<..: 2 2 2 4 NA 4 4 3 1 1 ... $ FahrzeitH : num 0.0167 0.75 1 0.4167 0.25 ... $ alterK : Ord.factor w/ 5 levels "(0,20]"<"(20,25]"<..: 1 3 5 4 3 4 3 2 3 3 ... $ kuckuck : int 12 315 60 325 270 1250 1160 60 120 200 ... - attr(*, ".internal.selfref")=<externalptr> - attr(*, "index")= int(0) 

Dies ist ein häufiger fataler Anfängerfehler, der zum Datenverlust führen kann!

Um das Objekt tatsächlich zu kopieren, muss die Funktion copy() verwendet werden.

# kopieren dt2 nach neu2neu2 <- copy(dt2)# anzeigenstr(neu2)
Classes 'data.table' and 'data.frame': 10 obs. of 4 variables: $ Geschlecht: chr "m" "w" "w" "m" ... $ Alter : int 28 18 25 29 21 19 27 26 31 22 $ Gewicht : int 80 55 74 101 84 74 65 56 88 78 $ Groesse : int 170 174 183 190 185 178 169 163 189 184 - attr(*, ".internal.selfref")=<externalptr> 
# manipulierenneu2[, Kuckuck := Groesse/Gewicht]# dt2 ist unverändertstr(dt2)
Classes 'data.table' and 'data.frame': 10 obs. of 4 variables: $ Geschlecht: chr "m" "w" "w" "m" ... $ Alter : int 28 18 25 29 21 19 27 26 31 22 $ Gewicht : int 80 55 74 101 84 74 65 56 88 78 $ Groesse : int 170 174 183 190 185 178 169 163 189 184 - attr(*, ".internal.selfref")=<externalptr> 

29.11 pipen

Innerhalb von data.table kann auch die Pipe verwendet werden. Wird die R-Base-Pipe |> verwendet, kann mittels Unterstrich _ auf den weitergeleiteten Datenstrom zugegriffen werden. Bei der Tidyverse-Pipe (eigentlich von magrittr) mit der Zeichenfolge %>% muss ein Punkt . verwendet werden.

Folgende Aufrufe filtern das geschlecht und pipen den Datenstrom weiter. Anschließend wird nach alter sortiert.

# Daten pipen mit R_Basedt2[Geschlecht=="m"] |> _[order(Alter)]
 Geschlecht Alter Gewicht Groesse <char> <int> <int> <int>1: m 21 84 1852: m 22 78 1843: m 28 80 1704: m 29 101 1905: m 31 88 189
# Daten pipen mit magrittrdt2[Geschlecht=="m"] %>%  .[order(Alter)]
 Geschlecht Alter Gewicht Groesse <char> <int> <int> <int>1: m 21 84 1852: m 22 78 1843: m 28 80 1704: m 29 101 1905: m 31 88 189

Oder wir erstellen ein linerares Modell und pipen es an die summary()-Funktion weiter.

dt2[, lm(Gewicht ~ Groesse)] |> summary()
Call:lm(formula = Gewicht ~ Groesse)Residuals: Min 1Q Median 3Q Max -14.9024 -3.4756 -0.3902 1.0915 15.0732 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -146.5366 58.3503 -2.511 0.03630 * Groesse 1.2439 0.3265 3.810 0.00516 **---Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1Residual standard error: 8.992 on 8 degrees of freedomMultiple R-squared: 0.6447, Adjusted R-squared: 0.6003 F-statistic: 14.51 on 1 and 8 DF, p-value: 0.005164

Wir können den Ausdruck aber auch direkt in die summary()-Funktion schreiben.

summary(dt2[, lm(Gewicht ~ Groesse)])
Call:lm(formula = Gewicht ~ Groesse)Residuals: Min 1Q Median 3Q Max -14.9024 -3.4756 -0.3902 1.0915 15.0732 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) -146.5366 58.3503 -2.511 0.03630 * Groesse 1.2439 0.3265 3.810 0.00516 **---Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1Residual standard error: 8.992 on 8 degrees of freedomMultiple R-squared: 0.6447, Adjusted R-squared: 0.6003 F-statistic: 14.51 on 1 and 8 DF, p-value: 0.005164

29.12 Ergebnisse gruppieren mit by

Über den Paramter by können die Ergebnisse gruppiert werden.

# gruppiert nach Geschlechtdt[, .(Median = median(alter), Mittelw = mean(alter), Stdabw = sd(alter)),  by = geschlecht]
 geschlecht Median Mittelw Stdabw <fctr> <num> <num> <num>1: weiblich 21.5 24.10714 5.2517322: männlich 25.0 29.00000 9.617692

Die Ausgabe kann gepipet und weiterverarbeitet werden. In folgendem Beispiel berechnen wir den Variationskoeffizienten (\(sd / \bar x\)) aus den gruppierten Ergebnissen.

dt[, .(Median = median(alter), Mittelw = mean(alter), Stdabw = sd(alter)),  by = geschlecht] |> # berechnen _[, VK := Stdabw / Mittelw] |> # anzeigen _[]
 geschlecht Median Mittelw Stdabw VK <fctr> <num> <num> <num> <num>1: weiblich 21.5 24.10714 5.251732 0.21784962: männlich 25.0 29.00000 9.617692 0.3316446

Bitte beachten Sie, dass wir in diesem Beispiel die Anzeige der Endergebnisse mittels |> _[] erzwingen mussten. Dies ist notwendig, wenn per by gruppierte Ergebnisse weiter manipuliert werden sollen. Data.table speichert Änderungen durch := immer direkt im Objekt, wobei keine Ausgabe der Daten erfolgt. Im vorliegenden Fall von VK := Stdabw / Mittelw ist diese Speicherung jedoch nicht möglich (ausgegeben wird ja eh nichts), da sich das Endergebnis nicht mehr auf das ursprüngliche Objekt dt bezieht. In diesem Fall ist es (sogar) möglich und üblich, das Ergebnis wie gewohnt in einem neuen Objekt zu speichern, ohne dass dabei ein symbolischer Link angelegt wird.

neu3 <- dt[, .(Median = median(alter), Mittelw = mean(alter), Stdabw = sd(alter)),  by = geschlecht] |> _[, VK := Stdabw / Mittelw] |> _[]# anzeigenneu3
 geschlecht Median Mittelw Stdabw VK <fctr> <num> <num> <num> <num>1: weiblich 21.5 24.10714 5.251732 0.21784962: männlich 25.0 29.00000 9.617692 0.3316446

Wir können den letzten Pipevorgang abkürzen, indem wir einfach eckige Klammern [] an unseren Aufruf anhängen.

neu4 <- dt[, .(Median = median(alter), Mittelw = mean(alter), Stdabw = sd(alter)),  by = geschlecht] |> _[, VK := Stdabw / Mittelw][]# anzeigenneu4
 geschlecht Median Mittelw Stdabw VK <fctr> <num> <num> <num> <num>1: weiblich 21.5 24.10714 5.251732 0.21784962: männlich 25.0 29.00000 9.617692 0.3316446

29.13 Weitere Funktionen aus dem data.table Paket

Das Paket data.table bringt zahlreiche eigene Funktionen mit, um typische Aufgabenstellungen effizienter bearbeiten zu können.

29.13.1 Einzigartige bestimmen mit uniqueN

Um zum Beispiel die Anzahl verschiedener Städte innerhalb der Variable geburtsort zu bestimmen, können wir auf die paketeigene Funktion uniqueN() zurückgreifen:

# wieviele unterschiedliche Städte sind in "geburtsort"?dt[, uniqueN(geburtsort)]
[1] 26

29.13.2 Anzahl der Fälle mit .N

Mit der Funktion .N kann die Anzahl der Fälle ermittelt werden.

dt[, .(Anzahl = .N), by = geschlecht]
 geschlecht Anzahl <fctr> <int>1: weiblich 282: männlich 9

Mit Hilfe von nrow() können so prozentuale Anteile berechnet werden.

dt[, .(Anzahl = .N, Prozent = .N/nrow(dt)*100), by = alterK]
 alterK Anzahl Prozent <ord> <int> <num>1: (0,20] 9 24.3243242: (25,30] 6 16.2162163: (40,50] 2 5.4054054: (30,40] 5 13.5135145: (20,25] 15 40.540541

Die Ergebnisse können an ggplot() weitergereicht werden.

# ggplotlibrary(ggplot2)dt[, .(Anzahl = .N, Prozent = .N/nrow(dt)*100), by = alterK] |> ggplot(aes(x=alterK, y=Prozent)) + geom_col(color="black", fill="orchid")

29 data.table – Statistik mit R und RStudio (2)

29.13.3 Lange Tabelle erzeugen mit melt()

Mit der Funktion melt() können breite Tabellen in lange (tidy) umgewandelt werden, ähnlich wie mit dplyr::pivot_longer(). Zur Demonstration verwenden wir die Pflegetabelle von Isfort (2018)

# lade Testdaten load("https://www.produnis.de/R/data/Pflegeberufe.RData")
 1999 2001 2003 2005 2007 2009 2011 2013Krankenpflegeassistenz 16624 19061 19478 21537 27731 36481 46517 54371Altenpflegehilfe 55770 52710 49727 45776 48326 47903 47978 48363Kinderkrankenpflege 47779 48203 48822 48519 49080 49307 48291 48937Krankenpflege 430983 436767 444783 449355 457322 465446 468192 472580Altenpflege 109161 124879 141965 158817 178902 194195 208304 227154 2015Krankenpflegeassistenz 64127Altenpflegehilfe 49507Kinderkrankenpflege 48913Krankenpflege 476416Altenpflege 246412

Die Tabelle ist nicht tidy und liegt im breiten Format vor. Ausserdem ist sie von der Klasse matrix.

# wandle um in data.tablepf <- as.data.table(Pflegeberufe, keep.rownames = "Berufsgruppe")# anzeigenpf
 Berufsgruppe 1999 2001 2003 2005 2007 2009 2011 <char> <num> <num> <num> <num> <num> <num> <num>1: Krankenpflegeassistenz 16624 19061 19478 21537 27731 36481 465172: Altenpflegehilfe 55770 52710 49727 45776 48326 47903 479783: Kinderkrankenpflege 47779 48203 48822 48519 49080 49307 482914: Krankenpflege 430983 436767 444783 449355 457322 465446 4681925: Altenpflege 109161 124879 141965 158817 178902 194195 208304 2013 2015 <num> <num>1: 54371 641272: 48363 495073: 48937 489134: 472580 4764165: 227154 246412

Mittels melt() transformieren wir pf in eine lange (tidy) Tabelle. Dabei übergeben wir dem Parameter

  • id.vars alle Variabelen, welche “Identifikatoren” beinhalten. Damit sind alle Spalten gemeint, die keine konkrekten Messwerte enhalten, sondern weitere bezeichnende Kennwerte. Klassischer Weise sind dies vor allem die Zeilennamen, in unserem Falle also Berufsgruppe. Es können mehrere id.vars mittels c() aneinandergereiht werden.
  • measure.vars alle Spalten, welche die eigentlichen Messwerte enthalten, in unserem Falle 1999:2015 (alles außer Berufsgruppe). Wird dieser Parameter leer gelassen, nimmt data.table automatisch alle Spalten, die keine id.vars sind.
  • variable.name den Name der neuen Spalte, in welche die Bezeichnungen der measure.vars überführt werden sollen, in unserem Fall Jahr.
  • value.name den Name der neuen Spalte, in welche die Werte der measure.vars überführt werden sollen, in unserem Fall Anzahl.

Da wir alle Spalten außer Berufsgruppe melten wollen, kann der Parameter measure.vars weggelassen werden.

# pf mit melt() tidy machenpf_tidy <- melt(pf, id.vars = "Berufsgruppe",  variable.name = "Jahr",  value.name = "Anzahl")# anschauenhead(pf_tidy)
 Berufsgruppe Jahr Anzahl <char> <fctr> <num>1: Krankenpflegeassistenz 1999 166242: Altenpflegehilfe 1999 557703: Kinderkrankenpflege 1999 477794: Krankenpflege 1999 4309835: Altenpflege 1999 1091616: Krankenpflegeassistenz 2001 19061

29.13.4 Breite Tabelle erzeugen mit dcast()

Mittels dcast() können lange Tabellen wieder in breite Tabellen transformiert werden, so wie bei dplyr::pivot_wider().

Der Aufruf folgt der Semantik:

dcast(Bezeichner ~ Spaltenname, value.var = "Wertename")

wobei

  • Bezeichner die Spalten der id.vars meint.
  • Spaltenname die Spalte mit der variable.name meint.
  • value.var den Namen der Spalte meint, welche die konkreten Messwerte enthält. Diese muss in Anführungszeichen angegeben werden. Wird dieser Parameter weggelassen, versucht data.table die korrekte Spalte zu erraten (was einfach ist, wenn nur noch eine Spalte übrig bleibt).
# wandle pf_tdiy mit dcast() in breite Tabellepf_wide <- dcast(pf_tidy, Berufsgruppe ~ Jahr,  value.var = "Anzahl")# anschauenhead(pf_wide)
Key: <Berufsgruppe> Berufsgruppe 1999 2001 2003 2005 2007 2009 2011 <char> <num> <num> <num> <num> <num> <num> <num>1: Altenpflege 109161 124879 141965 158817 178902 194195 2083042: Altenpflegehilfe 55770 52710 49727 45776 48326 47903 479783: Kinderkrankenpflege 47779 48203 48822 48519 49080 49307 482914: Krankenpflege 430983 436767 444783 449355 457322 465446 4681925: Krankenpflegeassistenz 16624 19061 19478 21537 27731 36481 46517 2013 2015 <num> <num>1: 227154 2464122: 48363 495073: 48937 489134: 472580 4764165: 54371 64127
29  data.table – Statistik mit R und RStudio (2024)
Top Articles
Maseca Flour: A Corn-Lover's Delight
Smart #3: Sieht sehr dynamisch aus – und fährt auch so
LOST JEEPS • View forum
Barbara Roufs Measurements
Tony's Delicatessen & Fresh Meats
Craigslist Free En Dallas Tx
Ups Cc Center
Guardians Of The Galaxy Vol 3 Full Movie 123Movies
Restaurants Near Defy Trampoline Park
Swgoh Darth Vader Mods
Msu Ro
His Words Any Sense Figgerits
Folsom Gulch Covid
Craigslist Hutchinson Ks
All classes in Pathfinder: Wrath of the Righteous
Craigslist Boats Rochester
How Much Is 7 Million Pesos
Ds Cuts Saugus
Birmingham City Schools Clever Login
Bank Of America.aomc
Sean Mckenna Eagar Az
What Is My Walmart Store Number
All Obituaries | Dante Jelks Funeral Home LLC. | Birmingham AL funeral home and cremation Gadsden AL funeral home and cremation
Aspenx2 Newburyport
Gay Cest Com
Rochester Ny Missed Connections
Lonesome Valley Barber
Fox News Live Stream USA HD - USNewsON
Marukai Honolulu Weekly Ads
Leonards Truck Caps
20 of the Best Restaurants in Moscow, Russia by a Local
Denise Frazier Leak
Footfetish Telegram
Coors Field Seats In The Shade
Craigslist Hunting Land For Lease In Ga
De Chromecast met Google TV en stembediening instellen
Is Jamie Kagol Married
Air Quality Index Endicott Ny
Podnóżek do krzesła Zion Footrest Outwell | Sklep campingshop.pl
How To Get Stone Can In Merge Mansion 2022
Ice Quartz Osrs
Www.1Tamilmv.cfd
5417873087
Congdon Heart And Vascular Center
Sayuri Pilkey
Sloansmoans Many
Oriellys Tooele
Uncg Directions
Embu village mines precious coltan for years 'without knowing its value’
Netspar on LinkedIn: Netspar is pleased to announce the next Netspar Pension Day, which will…
David Knowles, journalist who helped make the Telegraph podcast Ukraine: The Latest a runaway success
Dtm Urban Dictionary
Latest Posts
Article information

Author: Kerri Lueilwitz

Last Updated:

Views: 5533

Rating: 4.7 / 5 (67 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Kerri Lueilwitz

Birthday: 1992-10-31

Address: Suite 878 3699 Chantelle Roads, Colebury, NC 68599

Phone: +6111989609516

Job: Chief Farming Manager

Hobby: Mycology, Stone skipping, Dowsing, Whittling, Taxidermy, Sand art, Roller skating

Introduction: My name is Kerri Lueilwitz, I am a courageous, gentle, quaint, thankful, outstanding, brave, vast person who loves writing and wants to share my knowledge and understanding with you.