2012-04-11 4 views
6

Utilizzando un data.table, quale sarebbe il modo più rapido per "spazzare" una statistica attraverso una selezione di colonne?data.tables e funzione sweep

Partendo (versioni molto più grandi di) DT

p <- 3 
DT <- data.table(id=c("A","B","C"),x1=c(10,20,30),x2=c(20,30,10)) 
DT.totals <- DT[, list(id,total = x1+x2) ] 

mi piacerebbe arrivare al seguente risultato data.table indicizzando le colonne di destinazione (2: p) al fine di saltare la chiave:

id x1 x2 
[1,] A 0.33 0.67 
[2,] B 0.40 0.60 
[3,] C 0.75 0.25 

risposta

4

credo che qualcosa di simile a quanto segue (che utilizza la relativamente nuova funzione set()) sarà più veloce:

DT <- data.table(id = c("A","B","C"), x1 = c(10,20,30), x2 = c(20,30,10)) 
total <- DT[ , x1 + x2] 

rr <- seq_len(nrow(DT)) 
for(j in 2:3) set(DT, rr, j, DT[[j]]/total) 
DT 
#  id  x1  x2 
# [1,] A 0.3333333 0.6666667 
# [2,] B 0.4000000 0.6000000 
# [3,] C 0.7500000 0.2500000 

FWIW, chiama set() assume la seguente forma:

# set(x, i, j, value), where: 
#  x is a data.table 
#  i contains row indices 
#  j contains column indices 
#  value is the value to be assigned into the specified cells 

mio sospetto circa la velocità relativa di questo, rispetto ad altre soluzioni, si basa su questo passaggio da data.table's NEWS file, nella sezione dedicata ai cambiamenti nella versione 1.8.0:

o New function set(DT,i,j,value) allows fast assignment to elements 
    of DT. Similar to := but avoids the overhead of [.data.table, so is 
    much faster inside a loop. Less flexible than :=, but as flexible 
    as matrix subassignment. Similar in spirit to setnames(), setcolorder(), 
    setkey() and setattr(); i.e., assigns by reference with no copy at all. 

     M = matrix(1,nrow=100000,ncol=100) 
     DF = as.data.frame(M) 
     DT = as.data.table(M) 
     system.time(for (i in 1:1000) DF[i,1L] <- i) # 591.000s 
     system.time(for (i in 1:1000) DT[i,V1:=i])  # 1.158s 
     system.time(for (i in 1:1000) M[i,1L] <- i) # 0.016s 
     system.time(for (i in 1:1000) set(DT,i,1L,i)) # 0.027s 
+0

Grazie per la risposta. Ho aggiornato a data.table 1.8.0 e ho eseguito correttamente il codice di test sopra. Ricevo un avvertimento elaborato (che non si adatta qui) sulla coercizione da raddoppiare quando sia il numeratore che i denominatori sono colonne intere di data.tables. Modificherò la domanda in questo senso. –

+0

Oggi mi trovo in difficoltà con le modifiche: nessun feed di riga. Ad ogni modo, ecco il codice: per (j in 2: p) { set (dt, allrows, j, dt [[j]]/denom [[2]]) } e per entrambi dt e denom, colonne 2 a p sono numeri interi. L'avvertimento che ricevo è –

+0

"Messaggio di avviso: In set (dt, allrows, j, dt [[j]]/denom [[2]]): Costretto 'double' RHS a 'numero intero' per abbinare il tipo di colonna ; può avere una precisione troncata. O cambiare prima la colonna di destinazione in "doppio" (creando una nuova lunghezza "double" del vettore 16863 (nrows di tutta la tabella) e assegnare quella colonna, ad esempio "replace"), o forzare RHS a "intero" '(ad es. 1L, NA_ [reale | intero] _, come. *, ecc.) per rendere chiaro e veloce il tuo intento oppure impostare il tipo di colonna correttamente in primo piano quando crei la tabella e attenersi ad essa, per favore. " –