1) Bene, una ragione per non utilizzare, almeno per l'esempio rowsums
è la prestazione, e la creazione di una colonna inutile. Confronta all'opzione f2 sotto, che è quasi 4 volte più veloce e non ha bisogno di colonna rowpos:
dt <- data.table(V0 =LETTERS[c(1,1,2,2,3)], V1=1:5, V2=3:7, V3=5:1)
f1 <- function(dt){
dt[, rowpos := .I]
dt[ , sdd := rowSums(.SD[, 2:4, with=FALSE]), by = rowpos ] }
f2 <- function(dt){dt[, sdd := rowSums(dt[, 2:4, with=FALSE])]}
library(microbenchmark)
microbenchmark(f1(dt),f2(dt))
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# f1(dt) 3.669049 3.732434 4.013946 3.793352 3.972714 5.834608 100 b
# f2(dt) 1.052702 1.085857 1.154132 1.105301 1.138658 2.825464 100 a
2) Sulla tua seconda domanda, anche se dt[, sdd := sum(.SD[, 2:4, with=FALSE]), by = .I]
non funziona, dt[, sdd := sum(.SD[, 2:4, with=FALSE]), by = 1:NROW(dt)]
funziona perfettamente. Dato che secondo ?data.table
".I è un vettore intero uguale a seq_len (nrow (x))", ci si potrebbe aspettare che questi siano equivalenti. La differenza, tuttavia, è che .I
è per l'uso in j
, non in by
, perché il valore viene restituito da by
anziché valutato in anticipo.
Potrebbe anche essere previsto (si veda il commento alla domanda precedente da @eddi) che by = .I
dovrebbe solo generare un errore. Ma questo non si verifica, perché il caricamento del pacchetto data.table
crea un oggetto .I
nello spazio dei nomi data.table accessibile dall'ambiente globale e il cui valore è NULL
. È possibile verificare ciò digitando .I
al prompt dei comandi. (Si noti, lo stesso vale per .SD
, .EACHI
, .N
, .GRP
e .BY
)
.I
# Error: object '.I' not found
library(data.table)
.I
# NULL
data.table::.I
# NULL
Il risultato di questo è che il comportamento di by = .I
è equivalente a by = NULL
.
3) Anche se abbiamo già visto nella parte 1 che nel caso di rowSums
che loop già row-wise efficiente, ci sono modi molto superiori rispetto creare la colonna rowpos. Ma per quanto riguarda il ciclo quando non abbiamo una funzione veloce per la riga?
Benchmarking le by = rowpos
e by = 1:NROW(dt)
versioni contro un ciclo for
con set()
è informativo qui, e dimostra che la versione loop è più veloce di una delle by =
approcci:
f.rowpos <- function(){
dt <- data.table(V0 = rep(LETTERS[c(1,1,2,2,3)], 1e3), V1=1:5, V2=3:7, V3=5:1)
dt[, rowpos := .I]
dt[ , sdd := sum(.SD[, 2:4, with=FALSE]), by = rowpos ][]
}
f.nrow <- function(){
dt <- data.table(V0 = rep(LETTERS[c(1,1,2,2,3)], 1e3), V1=1:5, V2=3:7, V3=5:1)
dt[, sdd := sum(.SD[, 2:4, with=FALSE]), by = 1:NROW(dt) ][]
}
f.forset<- function(){
dt <- data.table(V0 = rep(LETTERS[c(1,1,2,2,3)], 1e3), V1=1:5, V2=3:7, V3=5:1)
dt[, sdd:=0L]
for (i in 1L:NROW(dt)) {
set(dt, i, 5L, sum(dt[i, 2:4]))
}
dt
}
microbenchmark(f.rowpos(),f.nrow(), f.forset(), times = 5)
Unit: seconds
expr min lq mean median uq max neval cld
f.rowpos() 4.465371 4.503614 4.510916 4.505922 4.521629 4.558042 5 b
f.nrow() 4.499120 4.499920 4.541131 4.558701 4.571267 4.576647 5 b
f.forset() 2.540556 2.603505 2.654036 2.606108 2.750719 2.769292 5 a
Quindi, in conclusione, anche in situazioni in cui non esiste una funzione ottimizzata come rowSums
che già funziona per riga, ci sono sempre alternative all'utilizzo di una colonna rowpos che sono più veloci, mentre non richiedono la creazione di una colonna ridondante.
In questo caso, è possibile utilizzare 'Riduci (" + ", dt [, 2: 4, con = FALSE])' a (1) _not_ loop per righe e (2) _non_ convertire in "matrice". Per altre operazioni su riga, si potrebbe considerare simile alle operazioni "Riduci" per evitare di applicare una funzione a ciascuna riga o, eventualmente, memorizzare i dati come "matrice" e utilizzare "matrice" - funzioni specifiche/efficienti –
..con 'sd', anche, guardando [qui] (http://stackoverflow.com/questions/25099825/row-wise-variance-of-a-matrix-in-r) e [qui] (http: // stackoverflow .com/questions/17549762/is-there-such-colsd-in-r), un'opzione sembra essere 'sqrt (rowSums ((dt [, 2: 4, with = FALSE] - Reduce (" + ", dt [, 2: 4, con = FALSE])/3)^2)/(3 - 1)) ' –
Non so perché' di = .I' non dà errore, ma non è equivalente a ' 1: nrow (dt) '- Scriverò un bug report se fossi in te – eddi