R Language
tabella dati
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 sarebbemtcars[ , 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:
- Usa la sintassi che si comporta allo stesso modo per entrambe le classi.
- Usa una funzione comune che fa la stessa cosa della sintassi più breve.
- Forza
data.table
a comportarsi comedata.frame
(es .: chiama il metodo specificoprint.data.frame
). - Trattali come
list
, che alla fine sono. - Converti la tabella in un
data.frame
prima di fare qualsiasi cosa (cattiva idea se si tratta di una tabella enorme). - 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