2011-03-16 17 views
8

Si tomo un trozo de una tabla usando, digamos los nombres de las columnas, R asigna memoria para mantener la división en una nueva ubicación? Específicamente, tengo una tabla con columnas depth1 y depth2, entre otras. Quiero agregar columnas que contengan el máximo y el mínimo de los dos. Tengo 2 enfoques:¿Las rebanadas de la tabla toman la memoria en R?

dd = dat[,c("depth1","depth2")] 
dat$mindepth = apply(dd,1,min) 
dat$maxdepth = apply(dd,1,max) 
remove(dd) 

o

dat$mindepth = apply(dat[,c("depth1","depth2")],1,min) 
dat$maxdepth = apply(dat[,c("depth1","depth2")],1,max) 

Si no estoy usando hasta nueva memoria, prefiero tomar la rebanada de una sola vez, de lo contrario me gustaría guardar la reasignación. ¿Cuál es mejor? Los problemas de memoria pueden ser críticos cuando se trata de grandes conjuntos de datos, así que no descarten esto con la raíz de todos los malos memes.

+5

Subconjunto prácticamente de todo en R crea una copia. Hay algunas excepciones en los paquetes contribuidos. – hadley

+0

@hadley - ¿Desea publicar eso como una respuesta, por lo que puede ser aceptado, etc. solo para los registros ...? –

Respuesta

6

Sé que esto no es en realidad responden al empuje principal de la pregunta (@hadley lo ha hecho y merece crédito), pero hay otras opciones para los que sugiere. Aquí podría usar pmin() y pmax() como otra solución, y usando with() o within() podemos hacerlo sin subconjuntos explícitos para crear un dd.

R> set.seed(1) 
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10)) 
R> dat <- within(dat, mindepth <- pmin(depth1, depth2)) 
R> dat <- within(dat, maxdepth <- pmax(depth1, depth2)) 
R> 
R> dat 
     depth1 depth2 mindepth maxdepth 
1 0.26550866 0.2059746 0.20597457 0.2655087 
2 0.37212390 0.1765568 0.17655675 0.3721239 
3 0.57285336 0.6870228 0.57285336 0.6870228 
4 0.90820779 0.3841037 0.38410372 0.9082078 
5 0.20168193 0.7698414 0.20168193 0.7698414 
6 0.89838968 0.4976992 0.49769924 0.8983897 
7 0.94467527 0.7176185 0.71761851 0.9446753 
8 0.66079779 0.9919061 0.66079779 0.9919061 
9 0.62911404 0.3800352 0.38003518 0.6291140 
10 0.06178627 0.7774452 0.06178627 0.7774452 

Podemos mirar a la cantidad de copias que pasa con tracemem() pero solamente si su R fue compilado con la siguiente opción de configuración activa --enable-memory-profiling.

R> set.seed(1) 
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10)) 
R> tracemem(dat) 
[1] "<0x2641cd8>" 
R> dat <- within(dat, mindepth <- pmin(depth1, depth2)) 
tracemem[0x2641cd8 -> 0x2641a00]: within.data.frame within 
tracemem[0x2641a00 -> 0x2641878]: [<-.data.frame [<- within.data.frame within 
R> tracemem(dat) 
[1] "<0x2657bc8>" 
R> dat <- within(dat, maxdepth <- pmax(depth1, depth2)) 
tracemem[0x2657bc8 -> 0x2c765d8]: within.data.frame within 
tracemem[0x2c765d8 -> 0x2c764b8]: [<-.data.frame [<- within.data.frame within 

Y vemos que R copiado dat dos veces durante cada within() llamada. Compare eso con sus dos sugerencias:

R> set.seed(1) 
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10)) 
R> tracemem(dat) 
[1] "<0x2e1ddd0>" 
R> dd <- dat[,c("depth1","depth2")] 
R> tracemem(dd) 
[1] "<0x2df01a0>" 
R> dat$mindepth = apply(dd,1,min) 
tracemem[0x2df01a0 -> 0x2cf97d8]: as.matrix.data.frame as.matrix apply 
tracemem[0x2e1ddd0 -> 0x2cc0ab0]: 
tracemem[0x2cc0ab0 -> 0x2cc0b20]: $<-.data.frame $<- 
tracemem[0x2cc0b20 -> 0x2cc0bc8]: $<-.data.frame $<- 
R> tracemem(dat) 
[1] "<0x26b93c8>" 
R> dat$maxdepth = apply(dd,1,max) 
tracemem[0x2df01a0 -> 0x2cc0e30]: as.matrix.data.frame as.matrix apply 
tracemem[0x26b93c8 -> 0x26742c8]: 
tracemem[0x26742c8 -> 0x2674358]: $<-.data.frame $<- 
tracemem[0x2674358 -> 0x2674478]: $<-.data.frame $<- 

Aquí, dd se copia una vez en cada llamada a apply porque apply() convierte dd a una matriz antes de continuar. Las últimas tres líneas en cada bloque de salida tracemem indican que se están haciendo tres copias de dat para insertar la nueva columna.

¿Qué pasa con su segunda opción?

R> set.seed(1) 
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10)) 
R> tracemem(dat) 
[1] "<0x268bc88>" 
R> dat$mindepth <- apply(dat[,c("depth1","depth2")],1,min) 
tracemem[0x268bc88 -> 0x26376b0]: 
tracemem[0x26376b0 -> 0x2637720]: $<-.data.frame $<- 
tracemem[0x2637720 -> 0x2637790]: $<-.data.frame $<- 
R> tracemem(dat) 
[1] "<0x2466d40>" 
R> dat$maxdepth <- apply(dat[,c("depth1","depth2")],1,max) 
tracemem[0x2466d40 -> 0x22ae0d8]: 
tracemem[0x22ae0d8 -> 0x22ae1f8]: $<-.data.frame $<- 
tracemem[0x22ae1f8 -> 0x22ae318]: $<-.data.frame $<- 

Aquí esta versión evita la copia conlleva la creación de dd, pero en todos los demás aspectos es similar a la sugerencia anterior.

¿Podemos hacer algo mejor? Sí, y una manera sencilla es utilizar la opción within() empecé con mas ejecutar ambas afirmaciones para crear nuevos mindepth y maxdepth variables en la llamada a within():

R> set.seed(1) 
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10)) 
R> tracemem(dat) 
[1] "<0x21c4158>" 
R> dat <- within(dat, { mindepth <- pmin(depth1, depth2) 
+      maxdepth <- pmax(depth1, depth2) }) 
tracemem[0x21c4158 -> 0x21c44a0]: within.data.frame within 
tracemem[0x21c44a0 -> 0x21c4628]: [<-.data.frame [<- within.data.frame within 

En esta versión sólo invocamos dos copias de dat en comparación con las 4 copias de la versión original within().

¿Qué pasa si coaccionamos dat a una matriz y luego hacemos las inserciones?

R> set.seed(1) 
R> dat <- data.frame(depth1 = runif(10), depth2 = runif(10)) 
R> tracemem(dat) 
[1] "<0x1f29c70>" 
R> mat <- as.matrix.data.frame(dat) 
tracemem[0x1f29c70 -> 0x1f09768]: as.matrix.data.frame 
R> tracemem(mat) 
[1] "<0x245ff30>" 
R> mat <- cbind(mat, pmin(mat[,1], mat[,2]), pmax(mat[,1], mat[,2])) 
R> 

Eso es una mejora, ya que sólo incurrir en el coste de la copia única de dat cuando coaccionar a una matriz.Intenté engañar un poco llamando directamente al método as.matrix.data.frame(). Si hubiéramos usado as.matrix(), habríamos incurrido en otra copia de mat.

Esto destaca una de las razones por las que las matrices son mucho más rápidas de usar que los marcos de datos.

Cuestiones relacionadas