R Language
data tafel
Zoeken…
Invoering
Data.table is een pakket dat de functionaliteit van dataframes van base R uitbreidt, met name wat betreft hun prestaties en syntaxis. Zie het Documenten-gedeelte van het pakket op Aan de slag met data.table voor details.
Syntaxis
-
DT[i, j, by]
# DT [waar, selecteer | update | do, door] -
DT[...][...]
# ketenen -
################# Shortcuts, special functions and special symbols inside DT[...]
- . ()
# in verschillende argumenten, vervangt list () - J ()
# in i, vervangt lijst () - : =
# in j, een functie die wordt gebruikt om kolommen toe te voegen of te wijzigen - .N
# in i, het totale aantal rijen
# in j, het aantal rijen in een groep - .IK
# in j, de vector van rijnummers in de tabel (gefilterd door i) - .SD
# in j, de huidige subset van de gegevens
# geselecteerd door het .SDcols argument - .grp
# in j, de huidige index van de subset van de gegevens - .DOOR
# in j, de lijst met waarden voor de huidige subset van gegevens - V1, V2, ...
# standaardnamen voor naamloze kolommen gemaakt in j -
################# Joins inside DT[...]
- DT1 [DT2, on, j]
# voeg twee tafels bij elkaar - ik.*
# speciaal voorvoegsel in de kolommen van DT2 na de join - by = .EACHI
# speciale optie alleen beschikbaar met een join - DT1 [! DT2, on, j]
# anti-join twee tabellen - DT1 [DT2, on, roll, j]
# voeg twee tabellen samen, rollend op de laatste kolom in op = -
################# Reshaping, stacking and splitting
- smelt (DT, id.vars, measure.vars)
# transformeren naar lang formaat
# voor meerdere kolommen, gebruik measure.vars = patronen (...) - dcast (DT, formule)
# transformeren naar breed formaat - rbind (DT1, DT2, ...)
# stapel opgesomde data.tables - rbindlist (DT_list, idcol)
# stapel een lijst met data.tables - splitsen (DT, door)
# splitst een data.table in een lijst -
################# Some other functions specialized for data.tables
- foverlaps
# overlapt joins - samenvoegen
# een andere manier om twee tafels samen te voegen - reeks
# een andere manier om kolommen toe te voegen of te wijzigen - fintersect, fsetdiff, funion, fsetequal, uniek, gedupliceerd, willekeurig
# set-theory operaties met rijen als elementen - uniqueN
# het aantal afzonderlijke rijen - rowidv (DT, cols)
# rij-ID (1 tot .N) binnen elke groep bepaald door cols - rleidv (DT, cols)
# groeps-ID (1 tot .GRP) binnen elke groep bepaald door runs van cols - shift (DT, n, type = c ("lag", "lead"))
# pas een shift-operator toe op elke kolom - setorder, setcolorder, setnamen, setkey, setindex, setattr
# attributen wijzigen en sorteren op referentie
Opmerkingen
Installatie en ondersteuning
Om het data.table pakket te installeren :
# 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")
De officiële site van het pakket heeft wikipagina's voor hulp om aan de slag te gaan en lijsten met presentaties en artikelen van internet. Lees de ondersteuningspagina voordat u een vraag stelt - hier op StackOverflow of ergens anders -.
Het pakket laden
Veel van de functies in de bovenstaande voorbeelden bestaan in de naamruimte data.table. Om ze te gebruiken, moet je eerst een regel zoals een library(data.table)
of hun volledige pad gebruiken, zoals data.table::fread
plaats van gewoon fread
. Voor hulp bij afzonderlijke functies is de syntaxis help("fread")
of ?fread
. Nogmaals, als het pakket niet is geladen, gebruikt u de volledige naam zoals ?data.table::fread
.
Een data.table maken
Een data.table is een verbeterde versie van de data.frame-klasse van base R. Als zodanig is het kenmerk class()
de vector "data.table" "data.frame"
en functies die op een data.frame werken, zullen ook werken met een data.table. Er zijn veel manieren om een data.table te maken, te laden of te forceren.
Bouwen
Vergeet niet het data.table
pakket te installeren en activeren
library(data.table)
Er is een constructor met dezelfde naam:
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
In tegenstelling tot data.frame
, zal data.table
strings niet dwingen tot factoren:
sapply(DT, class)
# x y z
# "character" "integer" "logical"
Inlezen
We kunnen lezen uit een tekstbestand:
dt <- fread("my_file.csv")
In tegenstelling tot read.csv
leest fread
strings als strings, niet als factoren.
Wijzig een data.frame
Voor efficiëntie biedt data.table een manier om een data.frame of lijst te wijzigen om een data.table op zijn plaats te maken (zonder een kopie te maken of de geheugenlocatie te wijzigen):
# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)
Merk op dat we niet <-
het resultaat toewijzen, omdat het object DF
is gewijzigd. De klassenattributen van het data.frame blijven behouden:
sapply(DF, class)
# x y z
# "factor" "integer" "logical"
Object op data.table dwingen
Als u een list
, data.frame
of data.table
, moet u de functie setDT
gebruiken om te converteren naar een data.table
omdat deze de conversie data.table
door verwijzing in plaats van een kopie te maken (wat as.data.table
doet). Dit is belangrijk als u met grote datasets werkt.
Als u een ander R-object (zoals een matrix) hebt, moet u as.data.table
gebruiken om het naar een data.table
te dwingen.
mat <- matrix(0, ncol = 10, nrow = 10)
DT <- as.data.table(mat)
# or
DT <- data.table(mat)
Kolommen toevoegen en wijzigen
DT[where, select|update|do, by]
syntaxis wordt gebruikt om te werken met kolommen van een data.table.
- Het "waar" gedeelte is het
i
argument - Het gedeelte "select | update | do" is het argument
j
Deze twee argumenten worden meestal op positie doorgegeven in plaats van op naam.
Onze voorbeeldgegevens hieronder zijn
mtcars = data.table(mtcars, keep.rownames = TRUE)
Volledige kolommen bewerken
Gebruik de :=
operator in j
om nieuwe kolommen toe te wijzen:
mtcars[, mpg_sq := mpg^2]
Verwijder kolommen door NULL
:
mtcars[, mpg_sq := NULL]
Voeg meerdere kolommen toe met behulp van de :=
operator's multivariate indeling:
mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]
Als de kolommen afhankelijk zijn en in volgorde moeten worden gedefinieerd, is één manier:
mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]
De .()
Syntaxis wordt gebruikt wanneer de rechterkant van LHS := RHS
een lijst met kolommen is.
Gebruik voor dynamisch bepaalde kolomnamen haakjes:
vn = "mpg_sq"
mtcars[, (vn) := mpg^2]
Kolommen kunnen ook worden gewijzigd met set
, hoewel dit zelden nodig is:
set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)
Subsets van kolommen bewerken
Gebruik het i
argument om subreeksen te plaatsen in rijen "waar" moet worden bewerkt:
mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")
Net als in een data.frame kunnen we subset gebruiken met behulp van rijnummers of logische tests. Het is ook mogelijk om een "join" in i
, maar die meer gecompliceerde taak wordt behandeld in een ander voorbeeld.
Kolomkenmerken bewerken
Functies die attributen bewerken, zoals levels<-
of names<-
, vervangen een object in feite door een gewijzigde kopie. Zelfs als slechts één kolom in een data.table wordt gebruikt, wordt het gehele object gekopieerd en vervangen.
Als u een object zonder kopieën wilt wijzigen, gebruikt u setnames
om de kolomnamen van een data.table of setattr
te wijzigen en setattr
om een kenmerk voor een object te wijzigen.
# 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")
Houd er rekening mee dat deze wijzigingen worden aangebracht door middel van verwijzing, dus ze zijn wereldwijd . Als u ze binnen één omgeving wijzigt, is het object in alle omgevingen van invloed.
# 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)
Speciale symbolen in data.table
.SD
.SD
verwijst naar de subset van de data.table
voor elke groep, exclusief alle kolommen die worden gebruikt by
.
.SD
samen met lapply
worden gebruikt om elke functie toe te passen op meerdere kolommen per groep in een data.table
We zullen dezelfde ingebouwde dataset, mtcars
, mtcars
:
mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler
Gemiddelde van alle kolommen in de gegevensset op aantal cilinders , 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
Afgezien van cyl
zijn er andere categorische kolommen in de gegevensset zoals vs
, am
, gear
en carb
. Het heeft geen zin om het mean
van deze kolommen te nemen. Laten we deze kolommen dus uitsluiten. Dit is waar .SDcols
in beeld komt.
.SDcols
.SDcols
geeft de kolommen van de data.table
die zijn opgenomen in .SD
.
Gemiddelde van alle kolommen (continue kolommen) in de gegevensset van het aantal versnellingen gear
en aantal cilinders, cyl
, geregeld door gear
en 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
Misschien willen we het mean
per groep berekenen. Om het gemiddelde voor alle auto's in de gegevensset te berekenen, geven we de variabele by
niet by
.
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
Notitie:
- Het is niet nodig om
cols_chosen
vooraf te definiëren..SDcols
kunnen direct kolomnamen aannemen -
.SDcols
kunnen ook rechtstreeks een vector van kolomnummers gebruiken. In het bovenstaande voorbeeld zijn ditmtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]
.N
.N
staat voor het aantal rijen in een groep.
iris[, .(count=.N), by=Species]
# Species count
#1: setosa 50
#2: versicolor 50
#3: virginica 50
Code schrijven compatibel met zowel data.frame als data.table
Verschillen in syntaxis van subsetting
Een data.table
is een van de verschillende tweedimensionale datastructuren die beschikbaar zijn in R, naast data.frame
, matrix
en (2D) array
. Al deze klassen gebruiken een zeer vergelijkbare maar niet identieke syntaxis voor subsetting, het A[rows, cols]
-schema.
Overweeg de volgende gegevens die zijn opgeslagen in een matrix
, een data.frame
en een 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!
Als u zeker wilt zijn van wat er wordt geretourneerd, is het beter om expliciet te zijn .
Om specifieke rijen te krijgen, voegt u gewoon een komma toe na het bereik:
ma[2:3, ] # \
df[2:3, ] # }---> returns the 2nd and 3rd rows
dt[2:3, ] # /
Maar als u kolommen wilt subset, worden sommige gevallen anders geïnterpreteerd. Alle drie kunnen op dezelfde manier worden gesubset met integer- of tekenindexen die niet in een variabele zijn opgeslagen.
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")] # /
Ze verschillen echter voor niet-genoteerde variabelenamen
mycols <- 2:3
ma[, mycols] # \
df[, mycols] # }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE] # /
dt[, mycols] # ---> Raises an error
In het laatste geval wordt mycols
geëvalueerd als de naam van een kolom. Omdat dt
een kolom met de naam mycols
niet kan vinden, is er een fout mycols
.
Opmerking: voor versies van het data.table
pakket data.table
1.9.8 was dit gedrag enigszins anders. Alles in de kolomindex zou zijn geëvalueerd met dt
als omgeving. Dus zowel dt[, 2:3]
als dt[, mycols]
zouden de vector 2:3
teruggeven. Voor het tweede geval zou geen fout worden gemaakt, omdat de variabele mycols
bestaat in de bovenliggende omgeving.
Strategieën voor het handhaven van compatibiliteit met data.frame en data.table
Er zijn veel redenen om code te schrijven die gegarandeerd werkt met data.frame
en data.table
. Misschien bent u gedwongen om data.frame
te gebruiken, of moet u een code delen waarvan u niet weet hoe deze zal worden gebruikt. Dus, er zijn enkele belangrijke strategieën om dit te bereiken, in volgorde van gemak:
- Gebruik syntaxis die zich voor beide klassen hetzelfde gedraagt.
- Gebruik een algemene functie die hetzelfde doet als de kortste syntaxis.
- Forceer
data.table
om zich te gedragen alsdata.frame
(bijvoorbeeld: roep de specifieke methodeprint.data.frame
). - Behandel ze als een
list
, die ze uiteindelijk zijn. - Converteer de tabel naar een
data.frame
voordat u iets doet (slecht idee als het een enorme tabel is). - Converteer de tabel naar
data.table
, als afhankelijkheden geen probleem zijn.
Subset rijen. Het is eenvoudig, gebruik gewoon de [, ]
selector, met de komma:
A[1:10, ]
A[A$var > 17, ] # A[var > 17, ] just works for data.table
Subset kolommen. Als u een enkele kolom wilt, gebruikt u de selector $
of [[ ]]
:
A$var
colname <- 'var'
A[[colname]]
A[[1]]
Als je een uniforme manier wilt om meer dan één kolom te pakken, moet je een beetje in beroep gaan:
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'))
Subset 'geïndexeerde' rijen. Terwijl data.frame
heeft row.names
, data.table
heeft zijn eigen unieke key
functie. Het beste is om row.names
volledig te vermijden en indien mogelijk gebruik te maken van de bestaande optimalisaties in het geval van data.table
.
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, ]
Krijg een tabel met 1 kolom, een rij als vector. Dit zijn eenvoudig met wat we tot nu toe hebben gezien:
B <- select(A, 2) #---> a table with just the second column
C <- unlist(A[1, ]) #---> the first row as a vector (coerced if necessary)
Sleutels instellen in data.table
Ja, u moet SETKEY pre 1.9.6 instellen
In het verleden (vóór 1.9.6) werd uw data.table
versneld door kolommen in te stellen als sleutels tot de tabel, met name voor grote tabellen. [Zie intrivignetpagina 5 van de versie van september 2015, waar de zoeksnelheid 544 keer beter was.] Mogelijk vindt u oudere code met behulp van deze instellingstoetsen met 'setkey' of een 'key =' kolom bij het instellen van de tabel.
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
Stel uw sleutel in met de opdracht setkey
. U kunt een sleutel met meerdere kolommen hebben.
setkey(DT, y)
Controleer de sleutel van uw tafel in tabellen ()
tables()
> tables()
NAME NROW NCOL MB COLS KEY
[1,] DT 5 3 1 x,y,z y
Total: 1MB
Let op: hiermee worden uw gegevens opnieuw gesorteerd.
#> DT
# x y z
#1: e 1 TRUE
#2: d 2 TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE
Nu is het niet nodig
Voorafgaand aan v1.9.6 moest u een sleutel hebben ingesteld voor bepaalde bewerkingen, met name het deelnemen aan tabellen. De ontwikkelaars van data.table hebben een "on="
-functie versneld en geïntroduceerd die de afhankelijkheid van sleutels kan vervangen. Zie SO antwoord hier voor een gedetailleerde discussie.
In januari 2017 hebben de ontwikkelaars een vignet rond secundaire indices geschreven waarin de syntaxis "aan" wordt uitgelegd en waarmee andere kolommen kunnen worden geïdentificeerd voor snelle indexering.
Secundaire indices maken?
Op een vergelijkbare manier als key, kunt u setindex(DT, key.col)
of setindexv(DT, "key.col.string")
, waarbij DT uw data.table is. Verwijder alle indices met setindex(DT, NULL)
.
Bekijk uw secundaire indices met indices(DT)
.
Waarom secundaire indices?
Dit sorteert de tabel niet (in tegenstelling tot de sleutel), maar maakt snelle indexering mogelijk met de syntaxis "aan". Merk op dat er maar één sleutel kan zijn, maar u kunt meerdere secundaire indices gebruiken, wat bespaart dat u de tabel opnieuw moet invoeren en opnieuw gebruiken. Dit versnelt uw subset bij het wijzigen van de kolommen waarop u wilt subset.
Denk eraan, in het bovenstaande voorbeeld was y de sleutel voor tabel 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