R Language
Datentabelle
Suche…
Einführung
Data.table ist ein Paket, das die Funktionalität von Datenrahmen von der Basis R aus erweitert und insbesondere deren Leistung und Syntax verbessert. Weitere Informationen finden Sie im Docs-Bereich des Pakets unter Erste Schritte mit data.table .
Syntax
-
DT[i, j, by]
# DT [wo, wählen Sie | update | do, by] -
DT[...][...]
# ketten -
################# Shortcuts, special functions and special symbols inside DT[...]
- ()
# in mehreren Argumenten ersetzt list () - J ()
# in i ersetzt list () - : =
# in j, eine Funktion zum Hinzufügen oder Ändern von Spalten - .N
# in i die Gesamtzahl der Zeilen
# in j die Anzahl der Zeilen in einer Gruppe - .ICH
# in j der Vektor der Zeilennummern in der Tabelle (gefiltert nach i) - .SD
# in j, die aktuelle Untermenge der Daten
# ausgewählt durch das Argument .SDcols - .GRP
# in j der aktuelle Index der Untermenge der Daten - .DURCH
# in j die Liste der by-Werte für die aktuelle Datenuntermenge - V1, V2, ...
# Standardnamen für nicht benannte Spalten, die in j erstellt wurden -
################# Joins inside DT[...]
- DT1 [DT2, Ein, J]
# zwei Tische verbinden - ich.*
# Sonderpräfix für DT2-Spalten nach dem Join - von = .EACHI
# spezielle Option nur mit einem Join verfügbar - DT1 [! DT2, Ein, J]
# Anti-Join von zwei Tabellen - DT1 [DT2, ein, rollen, j]
# Verbinden Sie zwei Tabellen und rollen Sie in der letzten Spalte von on = -
################# Reshaping, stacking and splitting
- Schmelze (DT, id.vars, measure.vars)
# in langes Format umwandeln
# Für mehrere Spalten verwenden Sie measure.vars = pattern (...). - dcast (DT, Formel)
# in ein Breitformat umwandeln - rbind (DT1, DT2, ...)
# Stack aufgezählte data.tables - rbindlist (DT_list, idcol)
# stapeln Sie eine Liste von data.tables - Split (DT, von)
# eine Datentabelle in eine Liste aufteilen -
################# Some other functions specialized for data.tables
- Foverlaps
# Überlappungen - verschmelzen
# eine andere Möglichkeit, zwei Tabellen zu verbinden - einstellen
# eine andere Möglichkeit, Spalten hinzuzufügen oder zu ändern - fintersect, fsetdiff, funion, fsetequal, einzigartig, dupliziert, anyDuplicated
# Mengenoperationsoperationen mit Zeilen als Elementen - uniqueN
Anzahl der verschiedenen Zeilen - rowidv (DT, Spalten)
# Zeilen-ID (1 bis .N) innerhalb jeder Gruppe, bestimmt durch Spalten - rleidv (DT, cols)
# Gruppen-ID (1 bis .GRP) innerhalb jeder Gruppe, bestimmt durch Anzahl von Spalten - Verschiebung (DT, n, Typ = c ("Lag", "Lead"))
# Einen Schichtoperator auf jede Spalte anwenden - setorder, setcolorder, setnames, setkey, setindex, setattr
# Attribute und Reihenfolge nach Verweis ändern
Bemerkungen
Installation und Unterstützung
So installieren Sie das Paket "data.table":
# install from CRAN
install.packages("data.table")
# or install development version
install.packages("data.table", type = "source", repos = "http://Rdatatable.github.io/data.table")
# and to revert from devel to CRAN, the current version must first be removed
remove.packages("data.table")
install.packages("data.table")
Auf der offiziellen Website des Pakets finden Sie Wiki-Seiten, die Ihnen den Einstieg erleichtern, sowie Listen mit Präsentationen und Artikeln aus dem Internet. Bevor Sie eine Frage stellen - hier bei StackOverflow oder anderswo - lesen Sie bitte die Support-Seite .
Paket laden
Viele der Funktionen in den obigen Beispielen sind im Namespace data.table enthalten. Um sie zu verwenden, müssen Sie zuerst eine Zeile wie die library(data.table)
hinzufügen oder ihren vollständigen Pfad verwenden, beispielsweise data.table::fread
anstatt nur fread
. Für Hilfe zu den einzelnen Funktionen ist die Syntax - help("fread")
oder ?fread
. Wenn das Paket nicht geladen ist, verwenden Sie erneut den vollständigen Namen wie ?data.table::fread
.
Eine Datentabelle anlegen
Eine data.table ist eine erweiterte Version der data.frame-Klasse von Basis R. Das class()
-Attribut ist daher der Vektor "data.table" "data.frame"
Funktionen, die auch auf einem data.frame funktionieren, werden verwendet Arbeit mit einer Datentabelle. Es gibt viele Möglichkeiten, eine data.table zu erstellen, zu laden oder zu zwingen.
Bauen
Vergessen Sie nicht, das Paket data.table
zu installieren und zu aktivieren
library(data.table)
Es gibt einen Konstruktor mit demselben Namen:
DT <- data.table(
x = letters[1:5],
y = 1:5,
z = (1:5) > 3
)
# x y z
# 1: a 1 FALSE
# 2: b 2 FALSE
# 3: c 3 FALSE
# 4: d 4 TRUE
# 5: e 5 TRUE
Im Gegensatz zu data.frame
data.table
data.frame
data.table
nicht zu Faktoren:
sapply(DT, class)
# x y z
# "character" "integer" "logical"
Einlesen
Wir können aus einer Textdatei lesen:
dt <- fread("my_file.csv")
Im read.csv
fread
liest fread
Strings als Strings und nicht als Faktoren.
Ändern Sie einen Datenrahmen
Aus Gründen der Effizienz bietet data.table eine Möglichkeit, ein data.frame oder eine Liste zu ändern, um eine data.table an Ort und Stelle zu machen (ohne eine Kopie zu erstellen oder den Speicherort zu ändern):
# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)
Beachten Sie, dass wir das Ergebnis nicht <-
zuweisen, da das Objekt DF
vor Ort geändert wurde. Die Klassenattribute des data.frame bleiben erhalten:
sapply(DF, class)
# x y z
# "factor" "integer" "logical"
Erzwingen Sie ein Objekt in data.table
Wenn Sie über eine list
, einen data.frame
oder eine data.table
, sollten Sie die Funktion setDT
zum Konvertieren in eine data.table
da sie die Konvertierung nach Verweis as.data.table
anstatt eine Kopie zu as.data.table
(wie as.data.table
). Dies ist wichtig, wenn Sie mit großen Datensätzen arbeiten.
Wenn Sie ein anderes R-Objekt haben (z. B. eine Matrix), müssen Sie as.data.table
, um es in eine data.table
.
mat <- matrix(0, ncol = 10, nrow = 10)
DT <- as.data.table(mat)
# or
DT <- data.table(mat)
Spalten hinzufügen und ändern
DT[where, select|update|do, by]
Syntax wird verwendet, um mit Spalten einer data.table zu arbeiten.
- "Wo" ist das
i
Argument - Der Teil "select | update | do" ist das Argument
j
Diese beiden Argumente werden normalerweise nach Position statt nach Name übergeben.
Unsere Beispieldaten sind unten
mtcars = data.table(mtcars, keep.rownames = TRUE)
Ganze Spalten bearbeiten
Verwenden Sie den Operator :=
in j
, um neue Spalten zuzuweisen:
mtcars[, mpg_sq := mpg^2]
Spalten entfernen, indem Sie NULL
:
mtcars[, mpg_sq := NULL]
Fügen Sie mehrere Spalten hinzu, indem Sie das multivariate Format des Operators :=
verwenden:
mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]
Wenn die Spalten abhängig sind und nacheinander definiert werden müssen, gibt es eine Möglichkeit:
mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]
Die Syntax .()
Wird verwendet, wenn die rechte Seite von LHS := RHS
eine Liste von Spalten ist.
Verwenden Sie für dynamisch bestimmte Spaltennamen Klammern:
vn = "mpg_sq"
mtcars[, (vn) := mpg^2]
Spalten können auch mit set
geändert werden, obwohl dies selten notwendig ist:
set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)
Untermengen von Spalten bearbeiten
Verwenden Sie das Argument " i
, um die Zeilen in den Untermengen zu sortieren, in denen "Änderungen" vorgenommen werden sollen:
mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")
Wie in einem data.frame können wir eine Teilmenge mit Zeilennummern oder logischen Tests vornehmen. Es ist auch möglich, einen "Join" in i
, die kompliziertere Aufgabe wird jedoch in einem anderen Beispiel behandelt.
Spaltenattribute bearbeiten
Funktionen, die Attribute bearbeiten, z. B. levels<-
oder names<-
, ersetzen ein Objekt tatsächlich durch eine modifizierte Kopie. Auch wenn nur eine Spalte in einer Datentabelle verwendet wird, wird das gesamte Objekt kopiert und ersetzt.
Um ein Objekt ohne Kopien zu ändern, verwenden Sie setnames
, um die Spaltennamen von data.table oder data.frame und setattr
zu ändern, um ein Attribut für ein beliebiges Objekt zu ändern.
# Print a message to the console whenever the data.table is copied
tracemem(mtcars)
mtcars[, cyl2 := factor(cyl)]
# Neither of these statements copy the data.table
setnames(mtcars, old = "cyl2", new = "cyl_fac")
setattr(mtcars$cyl_fac, "levels", c("four", "six", "eight"))
# Each of these statements copies the data.table
names(mtcars)[names(mtcars) == "cyl_fac"] <- "cf"
levels(mtcars$cf) <- c("IV", "VI", "VIII")
Beachten Sie, dass diese Änderungen durch Verweis vorgenommen werden, sodass sie global sind . Wenn Sie sie innerhalb einer Umgebung ändern, wirkt sich dies auf das Objekt in allen Umgebungen aus.
# This function also changes the levels in the global environment
edit_levels <- function(x) setattr(x, "levels", c("low", "med", "high"))
edit_levels(mtcars$cyl_factor)
Spezielle Symbole in data.table
.SD
.SD
bezieht sich auf die Teilmenge der data.table
für jede Gruppe, ausgenommen alle Spalten, die in verwendet by
.
.SD
zusammen mit lapply
verwendet werden, um jede Funktion auf mehrere Spalten nach Gruppe in einer data.table
Wir werden weiterhin dasselbe eingebaute Dataset, mtcars
:
mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler
Mittelwert aller Spalten im Datensatz nach Zylinderanzahl , cyl
:
mtcars[ , lapply(.SD, mean), by = cyl]
# cyl mpg disp hp drat wt qsec vs am gear carb
#1: 6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
#2: 4 26.66364 105.1364 82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
#3: 8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000
Neben cyl
gibt es im Datensatz weitere Kategoriespalten wie vs
, am
, gear
und carb
. Es macht keinen Sinn, den mean
dieser Spalten zu nehmen. Lassen Sie uns diese Spalten ausschließen. Hier kommt das .SDcols
ins .SDcols
.
.Scols
.SDcols
gibt die Spalten der data.table
, die in .SD
.
Mittel aller Spalten (continuous Spalten) in der Datenmenge durch die Anzahl der Zahnräder gear
und die Anzahl der Zylinder, cyl
, angeordnet durch gear
und cyl
:
# All the continuous variables in the dataset
cols_chosen <- c("mpg", "disp", "hp", "drat", "wt", "qsec")
mtcars[order(gear, cyl), lapply(.SD, mean), by = .(gear, cyl), .SDcols = cols_chosen]
# gear cyl mpg disp hp drat wt qsec
#1: 3 4 21.500 120.1000 97.0000 3.700000 2.465000 20.0100
#2: 3 6 19.750 241.5000 107.5000 2.920000 3.337500 19.8300
#3: 3 8 15.050 357.6167 194.1667 3.120833 4.104083 17.1425
#4: 4 4 26.925 102.6250 76.0000 4.110000 2.378125 19.6125
#5: 4 6 19.750 163.8000 116.5000 3.910000 3.093750 17.6700
#6: 5 4 28.200 107.7000 102.0000 4.100000 1.826500 16.8000
#7: 5 6 19.700 145.0000 175.0000 3.620000 2.770000 15.5000
#8: 5 8 15.400 326.0000 299.5000 3.880000 3.370000 14.5500
Vielleicht möchten wir den mean
nach Gruppen berechnen. Um den Mittelwert für alle Autos im Datensatz zu berechnen, geben wir die by
Variable nicht an.
mtcars[ , lapply(.SD, mean), .SDcols = cols_chosen]
# mpg disp hp drat wt qsec
#1: 20.09062 230.7219 146.6875 3.596563 3.21725 17.84875
Hinweis:
- Es ist nicht notwendig, vorher
cols_chosen
zu definieren..SDcols
können.SDcols
direkt übernehmen -
.SDcols
können auch direkt einen Vektor von Spaltennummern aufnehmen. Im obigen Beispiel wäre diesmtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]
.N
.N
ist die Abkürzung für die Anzahl der Zeilen in einer Gruppe.
iris[, .(count=.N), by=Species]
# Species count
#1: setosa 50
#2: versicolor 50
#3: virginica 50
Code schreiben, der mit data.frame und data.table kompatibel ist
Unterschiede in der Subsetting-Syntax
A data.table
ist eines von mehreren zweidimensionalen Datenstrukturen in R neben data.frame
, matrix
und (2D) array
. Alle diese Klassen verwenden eine sehr ähnliche, jedoch nicht identische Syntax für das Subsetting, das Schema A[rows, cols]
.
Betrachten Sie die folgenden Daten, die in einer matrix
, einem data.frame
und einer data.table
:
ma <- matrix(rnorm(12), nrow=4, dimnames=list(letters[1:4], c('X', 'Y', 'Z')))
df <- as.data.frame(ma)
dt <- as.data.table(ma)
ma[2:3] #---> returns the 2nd and 3rd items, as if 'ma' were a vector (because it is!)
df[2:3] #---> returns the 2nd and 3rd columns
dt[2:3] #---> returns the 2nd and 3rd rows!
Wenn Sie sicher sein möchten, was zurückgegeben wird, ist es besser, explizit zu sein .
Um bestimmte Zeilen zu erhalten , fügen Sie nach dem Bereich ein Komma hinzu:
ma[2:3, ] # \
df[2:3, ] # }---> returns the 2nd and 3rd rows
dt[2:3, ] # /
Wenn Sie jedoch Teilmengen von Spalten erstellen möchten, werden einige Fälle unterschiedlich interpretiert. Alle drei können auf dieselbe Weise Teilmengen mit Ganzzahlen- oder Zeichenindizes sein, die nicht in einer Variablen gespeichert sind.
ma[, 2:3] # \
df[, 2:3] # \
dt[, 2:3] # }---> returns the 2nd and 3rd columns
ma[, c("Y", "Z")] # /
df[, c("Y", "Z")] # /
dt[, c("Y", "Z")] # /
Sie unterscheiden sich jedoch für nicht benannte Variablennamen
mycols <- 2:3
ma[, mycols] # \
df[, mycols] # }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE] # /
dt[, mycols] # ---> Raises an error
Im letzten Fall wird mycols
als Name einer Spalte ausgewertet. Da dt
keine Spalte namens mycols
, wird ein Fehler mycols
.
Anmerkung: Bei Versionen des data.table
Pakets vor 1.9.8 unterschied sich dieses Verhalten geringfügig. Alles, was sich im Spaltenindex befindet, wurde unter Verwendung von dt
als Umgebung bewertet. Also würden sowohl dt[, 2:3]
als auch dt[, mycols]
den Vektor 2:3
. Für den zweiten Fall wird kein Fehler mycols
, da die Variable mycols
in der übergeordneten Umgebung vorhanden ist.
Strategien zur Aufrechterhaltung der Kompatibilität mit data.frame und data.table
Es gibt viele Gründe, Code zu schreiben, der garantiert mit data.frame
und data.table
. Möglicherweise müssen Sie data.frame
, oder Sie müssen Code data.frame
, der nicht weiß, wie er verwendet wird. Es gibt also einige Hauptstrategien, um dies in der Reihenfolge der Bequemlichkeit zu erreichen:
- Verwenden Sie eine Syntax, die für beide Klassen gleich ist.
- Verwenden Sie eine allgemeine Funktion, die dasselbe tut wie die kürzeste Syntax.
-
data.table
, dassdata.table
sich wiedata.frame
(Beispiel: Aufruf der spezifischen Methodeprint.data.frame
). - Behandle sie als
list
, was sie letztendlich sind. - Konvertieren Sie die Tabelle in einen
data.frame
bevor Sie etwas tun (schlechte Idee, wenn es sich um eine große Tabelle handelt). - Konvertieren Sie die Tabelle in
data.table
, wenn Abhängigkeiten keinedata.table
.
Teilmengenzeilen Es ist einfach, verwenden Sie einfach die [, ]
Auswahl mit dem Komma:
A[1:10, ]
A[A$var > 17, ] # A[var > 17, ] just works for data.table
Teilmengenspalten Wenn Sie eine einzelne Spalte wünschen, verwenden Sie die $
oder [[ ]]
:
A$var
colname <- 'var'
A[[colname]]
A[[1]]
Wenn Sie möchten, dass mehrere Spalten einheitlich erfasst werden, müssen Sie ein wenig ansprechen:
B <- `[.data.frame`(A, 2:4)
# We can give it a better name
select <- `[.data.frame`
B <- select(A, 2:4)
C <- select(A, c('foo', 'bar'))
Teilmenge 'indizierte' Zeilen Während data.frame
hat row.names
, data.table
hat sein einzigartiges key
Am besten vermeiden Sie row.names
vollständig und nutzen die vorhandenen Optimierungen im Fall von data.table
Möglichkeit.
B <- A[A$var != 0, ]
# or...
B <- with(A, A[var != 0, ]) # data.table will silently index A by var before subsetting
stuff <- c('a', 'c', 'f')
C <- A[match(stuff, A$name), ] # really worse than: setkey(A); A[stuff, ]
Holen Sie sich eine 1-Spalten-Tabelle, erhalten Sie eine Zeile als Vektor. Das ist einfach mit dem, was wir bisher gesehen haben:
B <- select(A, 2) #---> a table with just the second column
C <- unlist(A[1, ]) #---> the first row as a vector (coerced if necessary)
Schlüssel in data.table setzen
Ja, Sie müssen SETKEY vor 1.9.6 einstellen
In der Vergangenheit (vor 1.9.6) wurde Ihre data.table
beschleunigt, indem Sie Spalten als Schlüssel für die Tabelle data.table
, insbesondere für große Tabellen. [Siehe Intro-Vignette Seite 5 der Version von September 2015, bei der die Suchgeschwindigkeit 544-mal besser war.] Möglicherweise finden Sie älteren Code, der diese Einstellungstasten mit 'setkey' verwendet oder beim Einrichten der Tabelle eine Spalte 'key =' setzt.
library(data.table)
DT <- data.table(
x = letters[1:5],
y = 5:1,
z = (1:5) > 3
)
#> DT
# x y z
#1: a 5 FALSE
#2: b 4 FALSE
#3: c 3 FALSE
#4: d 2 TRUE
#5: e 1 TRUE
setkey
Sie Ihren Schlüssel mit dem Befehl setkey
. Sie können einen Schlüssel mit mehreren Spalten haben.
setkey(DT, y)
Überprüfen Sie den Schlüssel Ihrer Tabelle in Tabellen ()
tables()
> tables()
NAME NROW NCOL MB COLS KEY
[1,] DT 5 3 1 x,y,z y
Total: 1MB
Beachten Sie, dass dadurch Ihre Daten neu sortiert werden.
#> DT
# x y z
#1: e 1 TRUE
#2: d 2 TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE
Jetzt ist es unnötig
Vor v1.9.6 mussten Sie für bestimmte Operationen einen Schlüssel festgelegt haben, insbesondere das Verbinden von Tabellen. Die Entwickler von data.table haben eine "on="
-Funktion eingeführt, die die Abhängigkeit von Schlüsseln ersetzen kann. Siehe SO-Antwort hier für eine ausführliche Diskussion.
Im Januar 2017 haben die Entwickler eine Vignette um Sekundärindizes geschrieben, die die "Ein" -Syntax erläutert und die Identifizierung anderer Spalten für eine schnelle Indizierung ermöglicht.
Sekundärindizes erstellen?
In ähnlicher Weise wie key können Sie setindex(DT, key.col)
oder setindexv(DT, "key.col.string")
, wobei DT Ihre data.table ist. Entfernen Sie alle Indizes mit setindex(DT, NULL)
.
Sehen Sie Ihre Sekundärindizes mit indices(DT)
.
Warum Sekundärindizes?
Dies sortiert die Tabelle nicht (im Gegensatz zu key), ermöglicht jedoch eine schnelle Indizierung mit der "on" -Syntax. Beachten Sie, dass es nur einen Schlüssel geben kann. Sie können jedoch mehrere sekundäre Indizes verwenden, sodass Sie die Tabelle nicht erneut eingeben und neu sortieren müssen. Dadurch wird Ihr Subsetting beschleunigt, wenn Sie die Spalten ändern, für die Sie einen Subset erstellen möchten.
Erinnern Sie sich, im obigen Beispiel war y der Schlüssel für die Tabelle DT:
DT
# x y z
# 1: e 1 TRUE
# 2: d 2 TRUE
# 3: c 3 FALSE
# 4: b 4 FALSE
# 5: a 5 FALSE
# Let us set x as index
setindex(DT, x)
# Use indices to see what has been set
indices(DT)
# [1] "x"
# fast subset using index and not keyed column
DT["c", on ="x"]
#x y z
#1: c 3 FALSE
# old way would have been rekeying DT from y to x, doing subset and
# perhaps keying back to y (now we save two sorts)
# This is a toy example above but would have been more valuable with big data sets