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 dit mtcars[ , 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:

  1. Gebruik syntaxis die zich voor beide klassen hetzelfde gedraagt.
  2. Gebruik een algemene functie die hetzelfde doet als de kortste syntaxis.
  3. Forceer data.table om zich te gedragen als data.frame (bijvoorbeeld: roep de specifieke methode print.data.frame ).
  4. Behandel ze als een list , die ze uiteindelijk zijn.
  5. Converteer de tabel naar een data.frame voordat u iets doet (slecht idee als het een enorme tabel is).
  6. 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


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow