2012-05-24 7 views
8

Estoy buscando la mejor alternativa a la asignación aún no implementada (que yo sepa) por referencia en un data.table por grupos. Usando el ejemplo data.table,data.table alternativa eficiente a la asignación agrupada como DT [, x: = f (y), by = 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 

Quiero añadir un nuevo z columna, que contiene f (y, v) agrupados por valores de x (permite echar f (y, v) = media (y) + v). Tenga en cuenta que no quiero imprimir o almacenar el resultado de este cálculo como en

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 

sino más bien quiero añadir el resultado a 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 

mi data.table tiene 262 MB, de tal manera que

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

no es una opción, ya que no puedo encajar DT dos veces en la memoria (que está implícito en la operación de copia, creo). El hecho es que nunca he visto terminar esa operación.

¿Qué alternativas tengo (hasta que data.table viene con DT [, z: = mean (y) + v, by = x])?

Acabo de leer sobre DT [newDT]. ¿Qué pasa aquí?

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 

(que es la memoria factible sabia.) A continuación:

> 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 

pero eso no es lo que quiero. ¿Cuál es el error aquí?

+0

+1 Muy buena pregunta! –

Respuesta

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

+1 solución muy buena, solo escribí la larga porque pensé que la tuya no funciona. Al echar un segundo vistazo a 'ave', creo que solo quisiste decir' DT [, xm: = ave (y, x, FUN = mean) + v] '. Entonces funciona como un encanto y podría ser el más eficiente. –

+1

+1 Dado que ', by' es más rápido que' ave', sin embargo, esto debería ser más eficiente (aunque feo) hasta que '': = 'por grupo" finalice: 'DT [, xm: = DT [, mean (y) + v, by = x] [[2]]] ' –

+0

muchas gracias muchachos. Ni siquiera sabía que 'ave' existía. esperando el ': =' por grupo! –

3

yo haría lo siguiente:

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

Así que, básicamente, que dividirlo en dos partes: En primer lugar, puedo calcular la media de y y añadir que a DT, y luego agrego v a la media de y. En cuanto a la memoria, no estoy seguro si esto realmente ayuda, pero hay una buena posibilidad de que el autor eche un vistazo y nos lo haga saber ;-)

En cuanto a su pregunta, ¿por qué no funciona? Básicamente, termina con dos data.tables que desea fusionar: DT y newDT. Ambos data.tables tienen cada clave tres veces. Entonces, obviamente, cuando los fusionas, cada combinación está en los resultados y es por eso que obtienes una tabla de datos con 9 a, by c.

Así que para hacerlo a su manera, que es bastante similar a la mía necesita una segunda clave:

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 por esfuerzo. Realmente solo necesitamos ': =' por grupo, ¿no? Cerca de allí. Por cierto, compuesto ': =' a veces es útil: 'DT [, newx: = colA + 2] [, newy: = newx * 2] [, newz: = colA + newx + newy] ...' –

+2

Pero yo no estará haciendo múltiples ': =' por 'by' todavía, en caso de que alguien esté esperando eso. Solo será un ': =' por 'by' para la próxima versión. Las versiones futuras podrían ser 'DT [, {newx: = colB + 2; newy: = newx + colC}, by = colA]' –

+0

gracias christoph_J. esa cosa clave tiene mucho sentido. –

Cuestiones relacionadas