Una tarea para mis lectores: ¡resultados!

El otro día dejé planteada una tarea para mis lectores (que han sido menos diligentes que yo, incluso). Trataba de una comparación entre varios métodos para acceder a diccionarios (o hashes) de datos desde R para tratar de identificar el más eficiente en términos de velocidad de acceso.

Acá van los resultados:

n <- 100000
dat <- data.frame( id = paste( "id", 1:n, sep = "_" ),
   valor = rnorm( n ), stringsAsFactors = F )

n.sample <- 20000
seleccion <- sample( dat$id, n.sample )

### Con vectores:
system.time( res <- sapply( seleccion,
    function( x ) dat$valor[ dat$id == seleccion ] ) )

#  user  system elapsed
# 84.79    5.24   90.14

### Con listas:
mi.lista <- sapply( dat$valor, I, simplify = F )
names( mi.lista ) <- dat$id
system.time( res <- sapply( seleccion, function( x ) mi.lista[[x]] ) )

#  user  system elapsed
# 19.15    0.00   19.20

### Con entornos:
mi.entorno.0 <- new.env()
invisible( sapply( 1:n, function(i)
  assign( dat$id[i], dat$valor[i], env = mi.entorno.0 ) ) )
system.time( res <- sapply( seleccion, function( x ) mi.entorno.0[[x]] ) )

#  user  system elapsed
# 67.89    0.03   68.06

### Con el paquete data.table:
require( data.table )
tmp.dat <- dat
tmp.dat$id <- factor( tmp.dat$id )
mi.data.table <- data.table( tmp.dat )
setkey( mi.data.table, id )
system.time( res <- sapply( seleccion,
 function( x ) mi.data.table[ J(x) ]$valor ) )

#   user  system elapsed
# 371.07   25.91  400.39

### Con hashes:
mi.entorno.1 <- new.env( hash = T )
invisible( sapply( 1:n, function(i)
  assign( dat$id[i], dat$valor[i], env = mi.entorno.1 ) ) )
system.time( res <- sapply( seleccion,
   function( x ) mi.entorno.1[[x]] ) )

#  user  system elapsed
#  0.14    0.00    0.14

Los números son tan concluyentes que me excusan de la necesidad de ofrecer explicaciones y distingos. Aunque para que mis lectores no tengan que ir subiendo y bajando por la entrada para realizar comparaciones, los resumo en un gráfico:

5 comentarios sobre “Una tarea para mis lectores: ¡resultados!

  1. rvaquerizo 8 septiembre, 2010 7:26

    Como te puedes imaginar ya sabía el resultado. «Curiosamente» estaba trabajando en paralelo con lo mismo que planteas pero con SAS.

    ¿Uso de memoría de cada proceso? gc()

  2. datanalytics 8 septiembre, 2010 12:45

    El uso de memoria es complicado de estimar. Al menos, la memoria más o menos temporal que usa la llamada a la función de búsqueda.

    Obviamente, por definición, un objeto hash ocupa mucha más memoria que un vector (que empaca la infomación sin hiatos). Los hiatos fprman parte de la esencia misma de los hashes.

  3. rvaquerizo 11 septiembre, 2010 20:21

    ¿Hiatos? me llama la atención el nombre. ¿Imagen sería más adecuado?

  4. datanalytics 12 septiembre, 2010 14:23

    Bueno, con un hash tienes que reservar memoria de donde potencialmente pueden «colgar» o no «colgar» datos. Si quieres evitar las colisiones, tienes que aumentar la memoria reservada. Si aumentas la memoria, disminuyes la probabilidad de que en todas las casillas de memoria «cuelguen» datos. Luego se producen hiatos que ocupan espacio pasivamente.

Los comentarios están desabilitados.