Sul tuo ultimo caso, è una conseguenza della funzione di indicizzazione automatica in data.table
, poiché v1.9.4 +. Leggi di più per l'immagine completa :-).
Quando si esegue DT[col == .]
o DT[col %in% .]
, un indice viene generato automaticamente su la prima esecuzione. L'indice è solo il order
della colonna specificata. Il calcolo degli indici è abbastanza veloce (usando il conteggio sort/true radix sorting).
La tabella è di 120 milioni di righe e ci vogliono circa:
# clean session
require(data.table)
set.seed(1L)
DF = data.table(x=rep(c("a","b","c"),each=40000000), y=sample(c(1,3,6),40000000,T), v=1:9)
system.time(data.table:::forderv(DF, "y"))
# 3.923 0.736 4.712
Nota a margine: Colonna y
Non bisogna essere davvero doppia (su cui ordinamento richiede più tempo). Se convertiamo al tipo intero:
DF[, y := as.integer(y)]
system.time(data.table:::forderv(DF, "y"))
# user system elapsed
# 0.569 0.140 0.717
Il vantaggio è che ogni sottoinsiemi successivi su quella colonna utilizzando ==
o %in%
saranno velocissimo (Slides, R script, video della presentazione di Matt). Ad esempio:
# clean session, copy/paste code from above to create DF
system.time(DF[y==6, y := 10])
# user system elapsed
# 4.750 1.121 5.932
system.time(DF[y==6, y := 10])
# user system elapsed
# 4.002 0.907 4.969
Oh aspetta un minuto .. non è veloce. Ma ... indicizzazione ..?!? Sostituiamo sempre la stessa colonna con un nuovo valore. Ciò si traduce nell'ottenere la modifica di quella colonna (rimuovendo quindi l'indice). sottoinsiemi di Let y
, ma modificando v
:
# clean session
require(data.table)
set.seed(1L)
DF = data.table(x=rep(c("a","b","c"),each=40000000), y=sample(c(1,3,6),40000000,T), v=1:9)
system.time(DF[y==6, v := 10L])
# user system elapsed
# 4.653 1.071 5.765
system.time(DF[y==6, v := 10L])
# user system elapsed
# 0.685 0.213 0.910
options(datatable.verbose=TRUE)
system.time(DF[y==6, v := 10L])
# Using existing index 'y'
# Starting bmerge ...done in 0 secs
# Detected that j uses these columns: v
# Assigning to 40000059 row subset of 120000000 rows
# user system elapsed
# 0.683 0.221 0.914
si può vedere che il tempo per calcolare gli indici (usando la ricerca binaria) batte 0 secondi. Controlla anche ?set2key()
.
Se non avete intenzione di fare ripetute sottoinsiemi, o come nel tuo caso, sottoinsiemi e modificando la stessa colonna, allora ha senso per disattivare la funzione facendo options(datatable.auto.index = FALSE)
, depositata #1264:
# clean session
require(data.table)
options(datatable.auto.index = FALSE) # disable auto indexing
set.seed(1L)
DF = data.table(x=rep(c("a","b","c"),each=40000000), y=sample(c(1,3,6),40000000,T), v=1:9)
system.time(DF[y==6, v := 10L])
# user system elapsed
# 1.067 0.274 1.367
system.time(DF[y==6, v := 10L])
# user system elapsed
# 1.100 0.314 1.443
La differenza non è molto qui. Il tempo di scansione vettoriale è system.time(DF$y == 6)
= 0.448s
.
Per riassumere, nel tuo caso, la scansione vettoriale ha più senso. Ma in generale, l'idea è che è meglio pagare la penalità una volta e avere risultati rapidi su sottoinsiemi futuri su quella colonna, piuttosto che scansionare ogni volta.
funzione Auto indicizzazione è relativamente nuovo, e sarà esteso nel corso del tempo, e probabilmente ottimizzato (forse ci sono posti non abbiamo guardato). Rispondendo a questo Q, mi sono reso conto che non mostriamo il tempo per calcolare l'ordinamento (usando fsort()
, e immagino che il tempo trascorso lì potrebbe essere il motivo per cui i tempi sono piuttosto vicini, archiviati #1265).
Per quanto riguarda il secondo caso è lento, non del tutto sicuro perché. Sospetto che potrebbe essere dovuto a copie non necessarie della parte di R. Quale versione di R stai usando? Per il futuro, pubblica sempre l'output sessionInfo()
.
@DavidArenburg, il tempo di scansione vettoriale/ricerca binaria non cambia (che è la parte che richiede tempo qui). – Arun
Mi chiedo se potresti spiegare perché 'DF [y == 6," y "] <- 10' funziona mentre' DF [y == 6, "y"] 'praticamente non fa nulla. Questo tipo di colpi alla testa. –
@DavidArenburg, controlla 'data.table ::: \' [<-. Data.table \ ''. Non l'ho mai usato così. Non credo che nessuno lo usi. Deve essere ancora lì per compatibilità con le versioni precedenti, non è sicuro. Qualsiasi e tutti i miglioramenti non si verificano anche in quella funzione (dal momento che non è idiomatico) sarebbe la mia ipotesi. – Arun