2012-03-26 8 views
5

El objetivo es crear indicadores para una variable de factor/cadena en un marco de datos. Ese dataframe tiene filas de> 2 mm y ejecuta R en Windows, no tengo la opción de usar plyr con .parallel = T. Así que estoy tomando la ruta "divide y vencerás" con plyr y reshape2.Generando indicadores en cuadros de datos grandes

Correr carreras de fusión y fundido fuera de la memoria, y el uso de

ddply(idata.frame(items) , c("ID") , function(x){ 
     ( colSums(model.matrix(~ x$element - 1)) > 0 ) 
} , .progress="text")  

o

ddply(idata.frame(items) , c("ID") , function(x){ 
      ( elements %in% x$element ) 
    } , .progress="text") 

toma un tiempo. El enfoque más rápido es la llamada a tapply a continuación. ¿Ves una forma de acelerar esto? La instrucción% en% se ejecuta más rápido que la llamada model.matrix. Gracias.

set.seed(123) 

dd <- data.frame(
    id = sample(1:5, size=10 , replace=T) , 
    prd = letters[sample(1:5, size=10 , replace=T)] 
) 

prds <- unique(dd$prd) 

tapply(dd$prd , dd$id , function(x) prds %in% x) 
+0

Estoy confundido por su ejemplo. Estás dividiendo 'dd $ prd' por' dd $ id', luego preguntando qué valores de 'prds' están representados en cada id, pero' prds' no está ordenado (!) ¿Querías 'prds <- sort (unique (dd $ prd)) '(eso tendría mucho más sentido para mí ...)? –

+0

Siempre que los indicadores (los lógicos) correspondientes a los elementos disponibles en los pds tengan el mismo orden en los ID, no importa cómo estén ordenados. –

+0

OK. Ver mi otra pregunta, en mi respuesta a continuación ... –

Respuesta

4

Para este problema, los paquetes bigmemory y bigtabulate podrían ser sus amigos. Aquí es un ejemplo un poco más ambicioso:

library(bigmemory) 
library(bigtabulate) 

set.seed(123) 

dd <- data.frame(
    id = sample(1:15, size=2e6 , replace=T), 
    prd = letters[sample(1:15, size=2e6 , replace=T)] 
) 

prds <- unique(dd$prd) 

benchmark(
bigtable(dd,c(1,2))>0, 
table(dd[,1],dd[,2])>0, 
xtabs(~id+prd,data=dd)>0, 
tapply(dd$prd , dd$id , function(x) prds %in% x) 
) 

Y los resultados de la evaluación comparativa (estoy aprendiendo cosas nuevas todo el tiempo):

          test replications elapsed relative user.self sys.self user.child sys.child 
1      bigtable(dd, c(1, 2)) > 0   100 54.401 1.000000 51.759 3.817   0   0 
2     table(dd[, 1], dd[, 2]) > 0   100 112.361 2.065422 107.526 6.614   0   0 
4 tapply(dd$prd, dd$id, function(x) prds %in% x)   100 178.308 3.277660 166.544 13.275   0   0 
3    xtabs(~id + prd, data = dd) > 0   100 229.435 4.217478 217.014 16.660   0   0 

Y que muestra bigtable ganar por una cantidad considerable. Los resultados son más o menos que todos los pds están en todos los ID, pero vea ?bigtable para obtener detalles sobre el formato de los resultados.

+0

Muchas gracias. –

+0

La ejecución acaba de completarse (utilizando una gran tabla) en el conjunto de datos real (!). –

1

Parece que el uso de la función %in% me parece retroactivo. Y si desea un resultado verdadero/falso para cada fila de datos, debe usar% en% como operación vectorial o ave. Aunque no es necesario aquí, es posible que desee utilizarlo si hubiera una función más compleja que deba aplicarse a cada elemento.

set.seed(123) 

dd <- data.frame(
    id = sample(1:5, size=10 , replace=T) , 
    prd = letters[sample(1:5, size=10 , replace=T)] 
) 

prds <- unique(dd$prd) 
target.prds <- prds[1:2] 
dd$prd.in.trgt <- with(dd, prd %in% target.prds) 
+0

Habrá tantos indicadores como 'prds' (o' target.prds'): 'c (1,2,3)% en% c (1)' indicará que 1 está en ese registro, pero ninguno 2 ni 3. –

+0

No puede simplemente redefinir% en% para que sea algo que no es. Y un marco de datos necesita que todos los elementos tengan un número regular de entradas por fila. Necesitará usar una estructura de datos que acomode un número variable si "acierta", ... una matriz lógica de TRUEs y FALSE o una lista. –

+0

No estoy seguro de entender lo que dices. La llamada a '% in%' siempre devolverá el mismo número de lógicos. Empecé con 'function (x) unique (x $ prd)' en la llamada 'tapply', y eso hubiera producido una matriz desigual. –

2

puedes decir un poco más de cómo el problema se escala en términos de número de niveles, números de identificaciones, etc. (si se mantiene el número de niveles fijos, entonces para el número suficiente de individuos matriz de indicadores que 'la computación se acercará a todos los TRUE/all 1 ...)? Yo esperaba que xtabs sería más rápido, pero no es un ejemplo de este tamaño ...

library(rbenchmark) 
benchmark(
      tapply(dd$prd , dd$id , function(x) prds %in% x), 
      xtabs(~id+prd,data=dd)>0) 

    test  replications elapsed relative 
1 tapply(...)    100 0.053 1.000000 
2 xtabs(...) > 0   100 0.120 2.264151 
+0

Hay 13,5 millones de artículos (en 780,000 ID, por lo que hay varios artículos por ID).Hay 83 elementos diferentes en prd. Gracias por llamar mi atención a benchmark por cierto. –