2011-03-14 9 views
5

Tengo un data.frame llamado "d" de ~ 1,300,000 líneas y 4 columnas y otro data.frame llamado "gc" de ~ 12,000 líneas y 2 columnas (pero vea el ejemplo más pequeño a continuación).¿Cómo volver a escribir un comando "sapply" para aumentar el rendimiento?

d <- data.frame(gene=rep(c("a","b","c"),4), val=rnorm(12), ind=c(rep(rep("i1",3),2), rep(rep("i2",3),2)), exp=c(rep("e1",3), rep("e2",3), rep("e1",3), rep("e2",3))) 
gc <- data.frame(gene=c("a","b","c"), chr=c("c1","c2","c3")) 

Aquí es cómo "d" se parece a:

gene   val ind exp 
1  a 1.38711902 i1 e1 
2  b -0.25578496 i1 e1 
3  c 0.49331256 i1 e1 
4  a -1.38015272 i1 e2 
5  b 1.46779219 i1 e2 
6  c -0.84946320 i1 e2 
7  a 0.01188061 i2 e1 
8  b -0.13225808 i2 e1 
9  c 0.16508404 i2 e1 
10 a 0.70949804 i2 e2 
11 b -0.64950167 i2 e2 
12 c 0.12472479 i2 e2 

Y aquí es "GC":

gene chr 
1 a c1 
2 b c2 
3 c c3 

Quiero añadir una quinta columna para "d" mediante la incorporación datos de "gc" que coinciden con la primera columna de "d". Por el momento estoy usando sapply.

d$chr <- sapply(1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr) 

Pero en los datos reales, se necesita un tiempo "muy largo" (Estoy funcionando con el comando "system.time()" desde hace más de 30 minutos y todavía no ha terminado).

¿Tiene alguna idea de cómo podría volver a escribir esto de una manera inteligente? ¿O debería considerar usar plyr, tal vez con la opción "paralelo" (tengo cuatro núcleos en mi computadora)? En tal caso, ¿cuál sería la mejor sintaxis?

Gracias de antemano.

Respuesta

12

creo que sólo se puede utilizar el factor como el índice:

gc[ d[,1], 2] 
[1] c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 
Levels: c1 c2 c3 

hace lo mismo que:

sapply(1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr) 
[1] c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 
Levels: c1 c2 c3 

Pero es mucho más rápido:

> system.time(replicate(1000,sapply(1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr))) 
    user system elapsed 
    5.03 0.00 5.02 
> 
> system.time(replicate(1000,gc[ d[,1], 2])) 
    user system elapsed 
    0.12 0.00 0.13 

Editar :

Para ampliar un poco en mi comentario. La trama de datos gc requiere una fila para cada nivel de gene en el orden de los niveles para que esto funcione:

d <- data.frame(gene=rep(c("a","b","c"),4), val=rnorm(12), ind=c(rep(rep("i1",3),2), rep(rep("i2",3),2)), exp=c(rep("e1",3), rep("e2",3), rep("e1",3), rep("e2",3))) 
gc <- data.frame(gene=c("c","a","b"), chr=c("c1","c2","c3")) 

gc[ d[,1], 2] 
[1] c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 
Levels: c1 c2 c3 

sapply(1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr) 
[1] c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 
Levels: c1 c2 c3 

Pero no es difícil de solucionar que:

levels(gc$gene) <- levels(d$gene) # Seems redundant as this is done right quite often automatically 
gc <- gc[order(gc$gene),] 


gc[ d[,1], 2] 
[1] c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 
Levels: c1 c2 c3 

sapply(1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr) 
[1] c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 
Levels: c1 c2 c3 
+0

Gracias, eso es exactamente lo que necesito . – tflutre

+1

+1 Eso es brillante, no sabía que eso fuera posible. –

+0

Yo ni tbh :) Pero hay una trampa. Es decir que gc [, 1] aquí debe ser exactamente el mismo factor que d [, 1], tener solo una fila para cada nivel y cada nivel debe estar en el mismo orden.El truco es que un factor corresponde numéricamente a 1,2 ... –

1

Una solución alternativa que hace no superar el enfoque de Sasha tiempo-sabio, pero es más generalizable y legible, es simplemente merge los marcos de dos datos:

d <- merge(d, gc) 

Tengo un sistema más lento, así que aquí están mis tiempos:

> system.time(replicate(1000,sapply(1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr))) 
    user system elapsed 
    11.22 0.12 11.86 
> system.time(replicate(1000,gc[ d[,1], 2])) 
    user system elapsed 
    0.34 0.00 0.35 
> system.time(replicate(1000, merge(d, gc, by="gene"))) 
    user system elapsed 
    3.35 0.02 3.40 

La ventaja es que se pueden tener varias llaves, control preciso de los elementos no coincidentes, etc.

Cuestiones relacionadas