2011-03-14 4 views
5

J'ai un data.frame nommé "d" de ~ 1.300.000 lignes et 4 colonnes et un autre data.frame nommé "gc" de ~ 12.000 lignes et 2 colonnes (mais voir l'exemple plus petit ci-dessous).Comment réécrire une commande "sapply" pour augmenter les performances?

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")) 

Voici comment "d" ressemble à:

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 

Et voici "gc":

gene chr 
1 a c1 
2 b c2 
3 c c3 

Je veux ajouter une 5ème colonne "d" en incorporant les données de "gc" qui correspondent à la 1ère colonne de "d". Pour l'instant j'utilise sapply.

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

Mais sur les données réelles, il faut un « très long » temps (je suis en cours d'exécution avec la commande « system.time() » depuis plus de 30 minutes et il est toujours pas fini).

Avez-vous une idée de comment je pourrais réécrire cela d'une manière intelligente? Ou devrais-je envisager d'utiliser plyr, peut-être avec l'option "parallèle" (j'ai quatre cœurs sur mon ordinateur)? Dans un tel cas, quelle serait la meilleure syntaxe?

Merci d'avance.

Répondre

12

Je pense que vous pouvez simplement utiliser le facteur comme indice:

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

fait la même chose 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 

Mais est beaucoup plus rapide:

> 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 

Modifier :

Pour développer un peu mon commentaire. Le gc dataframe exige une ligne pour chaque niveau de gene dans l'ordre des niveaux pour que cela fonctionne:

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 

Mais il est difficile de résoudre ce problème:

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

Merci, c'est exactement ce que je dois . – tflutre

+1

+1 C'est génial, je ne savais pas que c'était même possible. –

+0

Moi non plus tbh :) Mais il y a un piège. C'est-à-dire que gc [, 1] doit ici être exactement le même que d [, 1], avoir une seule ligne pour chaque niveau et chaque niveau doit être dans le même ordre.L'astuce est qu'un facteur numériquement correspond à 1,2 ... –

1

Une solution alternative qui ne pas battre le timing sage approche de Sasha, mais il est plus généralisables et lisible, est simplement merge les deux trames de données:

d <- merge(d, gc) 

J'ai un système plus lent, alors voici mes horaires:

> 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 

L'avantage est que vous pouvez avoir plusieurs clés, commande de précision sur les éléments qui ne correspondent pas, etc.

Questions connexes