2012-05-24 1 views
8

Sto cercando la migliore alternativa al non ancora implementato (a mia conoscenza) assegnazione per riferimento in un data.table per gruppi. Utilizzando l'esempio data.table,data.table alternativa efficiente all'assegnazione raggruppata come DT [, x: = f (y), per = z]?

DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9) 
    x y v 
[1,] a 1 1 
[2,] a 3 2 
[3,] a 6 3 
[4,] b 1 4 
[5,] b 3 5 
[6,] b 6 6 
[7,] c 1 7 
[8,] c 3 8 
[9,] c 6 9 

voglio aggiungere un nuovo z colonna, contenente f (y, v) raggruppati per valori di x (immobili prendere f (y, v) = medio (y) + v). Si noti che io non voglio di stampare o memorizzare il risultato di questo calcolo come in

DT[,mean(y)+v,by=x] 
     x  V1 
[1,] a 4.333333 
[2,] a 5.333333 
[3,] a 6.333333 
[4,] b 7.333333 
[5,] b 8.333333 
[6,] b 9.333333 
[7,] c 10.333333 
[8,] c 11.333333 
[9,] c 12.333333 

ma voglio aggiungere il risultato al DT:

 x y v  V1 
[1,] a 1 1 4.333333 
[2,] a 3 2 5.333333 
[3,] a 6 3 6.333333 
[4,] b 1 4 7.333333 
[5,] b 3 5 8.333333 
[6,] b 6 6 9.333333 
[7,] c 1 7 10.333333 
[8,] c 3 8 11.333333 
[9,] c 6 9 12.333333 

mia data.table ha 262 MB, in modo tale che

DT <- DT[,transform(.SD,mean(y)+v),by=x] 

non è un'opzione, dato che non posso andare bene DT due volte in memoria (che è implicito l'operazione di copia, credo). Il fatto è che non ho mai visto quell'operazione finire.

Quali alternative ho (fino a data.table viene fornito con DT [, z: = mean (y) + v, by = x])?

Ho appena letto su DT [newDT]. Cosa c'è che non va qui?

newDT <- DT[,mean(y)+v,by=x] 
     x  V1 
[1,] a 4.333333 
[2,] a 5.333333 
[3,] a 6.333333 
[4,] b 7.333333 
[5,] b 8.333333 
[6,] b 9.333333 
[7,] c 10.333333 
[8,] c 11.333333 
[9,] c 12.333333 

(che è la memoria fattibile saggia.) Allora:

> DT[newDT] 
setkey(DT,x) 
setkey(newDT,x) 
x y v  V1 
a 1 1 4.333333 
a 3 2 4.333333 
a 6 3 4.333333 
a 1 1 5.333333 
a 3 2 5.333333 
a 6 3 5.333333 
a 1 1 6.333333 
a 3 2 6.333333 
a 6 3 6.333333 
b 1 4 7.333333 
b 3 5 7.333333 
b 6 6 7.333333 
b 1 4 8.333333 
b 3 5 8.333333 
b 6 6 8.333333 
b 1 4 9.333333 
b 3 5 9.333333 
b 6 6 9.333333 
c 1 7 10.333333 
c 3 8 10.333333 
c 6 9 10.333333 
c 1 7 11.333333 
c 3 8 11.333333 
c 6 9 11.333333 
c 1 7 12.333333 
c 3 8 12.333333 
c 6 9 12.333333 

ma non è questo quello che voglio. Qual è l'errore qui?

+0

+1 Grande domanda! –

risposta

4
DT[, xm := ave(y, x, FUN=mean) + v] 
+0

+1 soluzione molto bella, ho scritto solo il mio lungo perché pensavo che il tuo non funzionasse. Avendo un secondo sguardo su 'ave', penso che tu intendessi semplicemente' DT [, xm: = ave (y, x, FUN = mean) + v] '. Quindi funziona come un fascino e potrebbe essere il più efficiente. –

+1

+1 Dal momento che ', by' è più veloce di' ave', tuttavia, questo dovrebbe essere più efficiente (anche se brutto) fino a quando "': = 'per gruppo" è finito: 'DT [, xm: = DT [, mean (y) + v, by = x] [[2]]] " –

+0

grazie a tutti ragazzi. Non sapevo nemmeno che esistesse. non vedo l'ora di ': =' per gruppo! –

3

vorrei fare le seguenti operazioni:

DT[, list(fvy = mean(y)), by="x"][DT][, fvy := fvy + v] 

Quindi, in pratica, ho dividerlo in due parti: in primo luogo, io calcolare la media dei y e aggiungo che a DT, poi aggiungo v a la media di . Per quanto riguarda la memoria, non sono sicuro che questo aiuti davvero, ma c'è una buona possibilità che l'autore possa darci un'occhiata e facci sapere ;-)

Per quanto riguarda la tua domanda, perché non funziona: in sostanza, si finisce con due data.tables che si desidera unire: DT e newDT. Entrambi data.tables hanno ogni tasto tre volte. Quindi, ovviamente, quando li unisci, ogni combinazione è nei risultati ed è per questo che ottieni un data.table con 9 a, b, e c's.

Quindi, per fare a modo tuo che è abbastanza simile alla mia hai bisogno di una seconda chiave:

newDT <- DT[,list(fvy=mean(y)+v, v),by=x] 
setkey(newDT, x, v) 
setkey(DT, x, v) 
DT[newDT] 
     x v y  fvy 
[1,] a 1 1 4.333333 
[2,] a 2 3 5.333333 
[3,] a 3 6 6.333333 
[4,] b 4 1 7.333333 
[5,] b 5 3 8.333333 
[6,] b 6 6 9.333333 
[7,] c 7 1 10.333333 
[8,] c 8 3 11.333333 
[9,] c 9 6 12.333333 
+1

+1 per sforzo. Abbiamo davvero bisogno di ': =' per gruppo, no? Quasi arrivati. Btw, composto ': =' a volte è utile: 'DT [, newx: = colA + 2] [, newy: = newx * 2] [, newz: = colA + newx + newy] ...' –

+2

Ma io non farà più ': =' by 'by' ancora, nel caso qualcuno lo speri. Sarà solo un ': =' by 'by' per la prossima versione. Le future versioni potrebbero essere 'DT [, {newx: = colB + 2; newy: = newx + colC}, di = colA]' –

+0

grazie christoph_J. quella cosa chiave ha perfettamente senso. –