Ricerca…


introduzione

Data.table è un pacchetto che estende le funzionalità dei frame di dati dalla base R, migliorando in particolare le loro prestazioni e sintassi. Vedi l'area Documenti del pacchetto a Iniziare con data.table per i dettagli.

Sintassi

  • DT[i, j, by]
    # DT [dove, selezionare | update | do, by]
  • DT[...][...]
    # concatenamento
  • ################# Shortcuts, special functions and special symbols inside DT[...]
  • . ()
    # in diversi argomenti, sostituisce lista ()
  • J ()
    # in i, sostituisce lista ()
  • : =
    # in j, una funzione utilizzata per aggiungere o modificare colonne
  • .N
    # in i, il numero totale di righe
    # in j, il numero di righe in un gruppo
  • .IO
    # in j, il vettore dei numeri di riga nella tabella (filtrato da i)
  • .SD
    # in j, il sottoinsieme corrente dei dati
    # selezionato dall'argomento .SDcols
  • .GRP
    # in j, l'indice corrente del sottoinsieme dei dati
  • .DI
    # in j, l'elenco di valori per il sottoinsieme di dati corrente
  • V1, V2, ...
    # nomi predefiniti per colonne senza nome create in j
  • ################# Joins inside DT[...]
  • DT1 [DT2, acceso, j]
    # unire due tabelle
  • io.*
    # prefisso speciale sulle colonne di DT2 dopo il join
  • by = .EACHI
    # opzione speciale disponibile solo con un join
  • DT1 [! DT2, acceso, j]
    # anti-join due tabelle
  • DT1 [DT2, attivato, roll, j]
    # Unire due tabelle, rotolando sull'ultima colonna in = =
  • ################# Reshaping, stacking and splitting
  • fusione (DT, id.vars, measure.vars)
    # trasforma in formato lungo
    # per più colonne, usa measure.vars = patterns (...)
  • dcast (DT, formula)
    # trasforma in formato wide
  • rbind (DT1, DT2, ...)
    # stack ha elencato data.tables
  • rbindlist (DT_list, idcol)
    # impila un elenco di dati.tables
  • split (DT, da)
    # dividere un data.table in una lista
  • ################# Some other functions specialized for data.tables
  • foverlaps
    # si sovrappongono ai join
  • fondersi
    # un altro modo di unire due tavoli
  • impostato
    # altro modo per aggiungere o modificare colonne
  • fintersect, fsetdiff, funion, fsetequal, unique, duplicated, anyDuplicated
    # operazioni con la teoria delle serie con le righe come elementi
  • uniqueN
    # il numero di righe distinte
  • rowidv (DT, cols)
    # row ID (da 1 a .N) all'interno di ciascun gruppo determinato da cols
  • rleidv (DT, cols)
    # ID gruppo (da 1 a .GRP) all'interno di ciascun gruppo determinato da serie di colonne
  • shift (DT, n, type = c ("lag", "lead"))
    # applica un operatore di turno a ogni colonna
  • setorder, setcolorder, setnames, setkey, setindex, setattr
    # modifica gli attributi e ordina per riferimento

Osservazioni

Installazione e supporto

Per installare il pacchetto 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")

Il sito ufficiale del pacchetto ha pagine wiki che forniscono aiuto per iniziare e liste di presentazioni e articoli da tutto il web. Prima di fare una domanda - qui su StackOverflow o altrove - leggi la pagina di supporto .

Caricamento del pacchetto

Molte delle funzioni negli esempi precedenti esistono nello spazio dei nomi data.table. Per usarli, dovrai prima aggiungere una riga come library(data.table) o usare il loro percorso completo, come data.table::fread invece di semplicemente fread . Per informazioni sulle singole funzioni, la sintassi è help("fread") o ?fread . Di nuovo, se il pacchetto non è caricato, usa il nome completo come ?data.table::fread .

Creare un data.table

Un data.table è una versione avanzata della classe data.frame dalla base R. Come tale, l'attributo class() è il vettore "data.table" "data.frame" e le funzioni che funzionano su un data.frame saranno anche funziona con un data.table. Esistono molti modi per creare, caricare o forzare su un data.table.

Costruire

Non dimenticare di installare e attivare il pacchetto data.table

library(data.table)

C'è un costruttore con lo stesso nome:

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

A differenza di data.frame , data.table non costringerà le stringhe a fattori:

sapply(DT, class)
#               x           y           z 
#     "character"   "integer"   "logical" 

Leggi dentro

Possiamo leggere da un file di testo:

dt <- fread("my_file.csv")

A differenza di read.csv , fread leggerà le stringhe come stringhe, non come fattori.

Modifica un data.frame

Per efficienza, data.table offre un modo per modificare un data.frame o un elenco per creare un data.table sul posto (senza fare una copia o modificare la sua posizione di memoria):

# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)

Nota che non <- assegna il risultato, poiché l'oggetto DF è stato modificato sul posto. Gli attributi di classe di data.frame verranno mantenuti:

sapply(DF, class)
#         x         y         z 
#  "factor" "integer" "logical" 

Costruire oggetto su data.table

Se hai una list , data.frame o data.table , dovresti usare la funzione setDT per convertire in data.table perché fa la conversione per riferimento invece di fare una copia (cosa che as.data.table fa). Questo è importante se si lavora con dataset di grandi dimensioni.

Se hai un altro oggetto R (come una matrice), devi usare as.data.table per costringerlo a un data.table .

mat <- matrix(0, ncol = 10, nrow = 10)

DT <- as.data.table(mat)
# or
DT <- data.table(mat)

Aggiunta e modifica di colonne

DT[where, select|update|do, by] è usato per lavorare con le colonne di un data.table.

  • La parte "dove" è l'argomento i
  • La parte "select | update | do" è l'argomento j

Questi due argomenti vengono generalmente passati per posizione anziché per nome.

I nostri dati di esempio qui sotto sono

mtcars = data.table(mtcars, keep.rownames = TRUE)

Modifica di intere colonne

Usa l'operatore := all'interno di j per assegnare nuove colonne:

mtcars[, mpg_sq := mpg^2]

Rimuovi colonne impostando su NULL :

mtcars[, mpg_sq := NULL]

Aggiungere più colonne tramite := formato multivariata dell'operatore:

mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or 
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]

Se le colonne dipendono e devono essere definite in sequenza, un modo è:

mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]

La sintassi .() Viene utilizzata quando il lato destro di LHS := RHS è un elenco di colonne.

Per i nomi di colonna determinati dinamicamente, utilizzare le parentesi:

vn = "mpg_sq"
mtcars[, (vn) := mpg^2]

Le colonne possono anche essere modificate con set , anche se questo è raramente necessario:

set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)

Modifica di sottoinsiemi di colonne

Utilizza l'argomento i per sottoporre a sotto le righe "dove" devono essere apportate modifiche:

mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")  

Come in un data.frame, possiamo impostare sottoinsiemi usando numeri di riga o test logici. È anche possibile usare un "join" in i , ma quell'attività più complicata è trattata in un altro esempio.

Modifica degli attributi della colonna

Le funzioni che modificano gli attributi, come i levels<- oi names<- , in realtà sostituiscono un oggetto con una copia modificata. Anche se usato solo su una colonna in un data.table, l'intero oggetto viene copiato e sostituito.

Per modificare un oggetto senza copie, utilizzare setnames per modificare i nomi delle colonne di data.table o data.frame e setattr per modificare un attributo per qualsiasi oggetto.

# 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")

Essere consapevoli del fatto che queste modifiche sono fatte per riferimento, quindi sono globali . La loro modifica in un ambiente influisce sull'oggetto in tutti gli ambienti.

# 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)

Simboli speciali in data.table

.SD

.SD fa riferimento al sottoinsieme di data.table per ciascun gruppo, escludendo tutte le colonne utilizzate by .

.SD insieme a lapply può essere utilizzato per applicare qualsiasi funzione a più colonne per gruppo in un data.table

Continueremo a utilizzare lo stesso set di dati mtcars , mtcars :

mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler

Media di tutte le colonne nel set di dati per numero di cilindri , 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

Oltre a cyl , ci sono altre colonne categoriali nel set di dati come vs , am , gear e carb . Non ha senso prendere la mean di queste colonne. Quindi escludiamo queste colonne. Questo è dove .SDcols entra nella foto.

.SDcols

.SDcols specifica le colonne di data.table che sono incluse in .SD .

Media di tutte le colonne (colonne continue) dell'insieme di dati di numero di marce gear , e il numero di cilindri, cyl , disposti da gear e 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

Forse non vogliamo calcolare la mean per gruppi. Per calcolare la media per tutte le auto nel set di dati, non specifichiamo la variabile 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

Nota:

  • Non è necessario definire prima cols_chosen . .SDcols può prendere direttamente i nomi delle colonne
  • .SDcols può anche prendere direttamente un vettore di numeri di colonna. Nell'esempio precedente questo sarebbe mtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]

.N

.N è una scorciatoia per il numero di righe in un gruppo.

iris[, .(count=.N), by=Species]

#      Species count
#1:     setosa    50
#2: versicolor    50
#3:  virginica    50

Codice di scrittura compatibile con data.frame e data.table

Differenze nella sintassi di subsetting

Un data.table è una delle diverse strutture dati bidimensionali disponibili in R, oltre data.frame , matrix e (2D) array . Tutte queste classi usano una sintassi molto simile ma non identica per il subsetting, lo schema A[rows, cols] .

Considera i seguenti dati memorizzati in una matrix , un data.frame e un 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!

Se vuoi essere sicuro di ciò che verrà restituito, è meglio essere espliciti .

Per ottenere righe specifiche, aggiungi una virgola dopo l'intervallo:

ma[2:3, ]  # \
df[2:3, ]  #  }---> returns the 2nd and 3rd rows
dt[2:3, ]  # /

Tuttavia, se si desidera impostare sottoinsiemi di colonne , alcuni casi vengono interpretati in modo diverso. Tutti e tre possono essere sottoinsieme allo stesso modo con interi o indici di caratteri non memorizzati in una variabile.

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")]  # /

Tuttavia, si differenziano per nomi di variabili non quotate

mycols <- 2:3
ma[, mycols]                # \
df[, mycols]                #  }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE]  # /

dt[, mycols]                # ---> Raises an error

Nell'ultimo caso, mycols viene valutato come il nome di una colonna. Poiché dt non riesce a trovare una colonna denominata mycols , viene generato un errore.

Nota: per le versioni del data.table pacchetto priorto 1.9.8, questo comportamento era leggermente diverso. Qualunque cosa nell'indice di colonna sarebbe stata valutata usando dt come ambiente. Quindi sia dt[, 2:3] che dt[, mycols] restituirebbero il vettore 2:3 . Nessun errore verrebbe generato per il secondo caso, perché la variabile mycols esiste nell'ambiente padre.

Strategie per mantenere la compatibilità con data.frame e data.table

Ci sono molte ragioni per scrivere codice che è garantito per funzionare con data.frame e data.table . Forse sei costretto a usare data.frame , o potresti aver bisogno di condividere del codice che non sai come verrà usato. Quindi, ci sono alcune strategie principali per raggiungere questo, in ordine di convenienza:

  1. Usa la sintassi che si comporta allo stesso modo per entrambe le classi.
  2. Usa una funzione comune che fa la stessa cosa della sintassi più breve.
  3. Forza data.table a comportarsi come data.frame (es .: chiama il metodo specifico print.data.frame ).
  4. Trattali come list , che alla fine sono.
  5. Converti la tabella in un data.frame prima di fare qualsiasi cosa (cattiva idea se si tratta di una tabella enorme).
  6. Converti la tabella in data.table , se le dipendenze non sono un problema.

Righe sottoinsieme. È semplice, usa il selettore [, ] con la virgola:

A[1:10, ]
A[A$var > 17, ]  # A[var > 17, ] just works for data.table

Colonne sottoinsieme. Se vuoi una singola colonna, usa il selettore $ o [[ ]] :

A$var
colname <- 'var'
A[[colname]]
A[[1]]

Se vuoi un modo uniforme per afferrare più di una colonna, è necessario fare appello un po ':

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'))

Sottoinsieme 'indicizzato' righe. Mentre data.frame ha row.names , data.table ha la sua unica key funzione. La cosa migliore è evitare interamente row.names e sfruttare le ottimizzazioni esistenti nel caso di data.table quando possibile.

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, ]

Ottieni una tabella a 1 colonna, ottieni una riga come vettore. Questi sono facili con quello che abbiamo visto fino ad ora:

B <- select(A, 2)    #---> a table with just the second column
C <- unlist(A[1, ])  #---> the first row as a vector (coerced if necessary)

Impostazione delle chiavi in ​​data.table

Sì, è necessario SETKEY pre 1.9.6

In passato (precedente alla 1.9.6), data.table stato velocizzato impostando le colonne come chiavi della tabella, in particolare per tabelle di grandi dimensioni. [Vedi intro vignette pagina 5 della versione di settembre 2015, dove la velocità di ricerca era 544 volte migliore.] Potresti trovare codice vecchio che usa questi tasti di impostazione con 'setkey' o imposta una colonna 'chiave =' quando si imposta la tabella.

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

Imposta la tua chiave con il comando setkey . Puoi avere una chiave con più colonne.

setkey(DT, y)

Controlla la chiave del tuo tavolo nelle tabelle ()

tables()

> tables()
     NAME NROW NCOL MB COLS  KEY
[1,] DT      5    3  1 x,y,z y  
Total: 1MB

Nota questo ri-ordinare i tuoi dati.

#> DT
#   x y     z
#1: e 1  TRUE
#2: d 2  TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE

Ora non è necessario

Prima della v1.9.6 dovevi impostare una chiave per determinate operazioni, in particolare unendo le tabelle. Gli sviluppatori di data.table hanno accelerato e introdotto una funzione "on=" che può sostituire la dipendenza dalle chiavi. Vedi SO rispondi qui per una discussione dettagliata.

Nel gennaio 2017, gli sviluppatori hanno scritto una vignetta sugli indici secondari che spiega la sintassi "on" e consente di identificare altre colonne per l'indicizzazione rapida.

Creare indici secondari?

In un modo simile al tasto, è possibile setindex(DT, key.col) o setindexv(DT, "key.col.string") , dove DT è il tuo data.table. Rimuovi tutti gli indici con setindex(DT, NULL) .

Vedi i tuoi indici secondari con indices(DT) .

Perché gli indici secondari?

Questo non ordina la tabella (a differenza della chiave), ma consente una rapida indicizzazione usando la sintassi "on". Nota che può esserci solo una chiave, ma puoi usare più indici secondari, il che evita di dover rekeyare e ricorrere alla tabella. Ciò accelera il subset quando si cambiano le colonne su cui si desidera eseguire il subset.

Ricorda, nell'esempio sopra y era la chiave per la tabella 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow