Wie schreibe ich einen „Sapply“ -Fehl um, um die Leistung zu erhöhen?
-
24-10-2019 - |
Frage
Ich habe einen Daten.Frame mit dem Namen "D" von ~ 1.300.000 Zeilen und 4 Spalten und einem weiteren Daten.Frame mit dem Namen "GC" von ~ 12.000 Zeilen und 2 Spalten (siehe jedoch das kleinere Beispiel unten).
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") )
So sieht "D" aus:
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
Und hier ist "GC":
gene chr
1 a c1
2 b c2
3 c c3
Ich möchte "D" eine 5. Spalte hinzufügen, indem ich Daten von "GC" einbeziehe, die mit der 1. Spalte von "D" übereinstimmen. Für den Moment benutze ich schlau.
d$chr <- sapply( 1:nrow(d), function(x) gc[ gc$gene==d[x,1], ]$chr )
Bei den realen Daten dauert es jedoch eine "sehr lange" Zeit (ich führe den Befehl mit "System.Time ()" seit mehr als 30 Minuten aus und ist immer noch nicht fertig).
Haben Sie eine Vorstellung davon, wie ich das auf clevere Weise umschreiben könnte? Oder sollte ich in Betracht ziehen, zu verwenden PLYR, Vielleicht mit der "parallelen" Option (ich habe vier Kerne auf meinem Computer)? Was wäre in einem solchen Fall die beste Syntax?
Danke im Voraus.
Lösung
Ich denke, Sie können den Faktor nur als Index verwenden:
gc[ d[,1], 2]
[1] c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3
Levels: c1 c2 c3
macht das gleiche wie:
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
Aber ist viel schneller:
> 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
Bearbeiten:
Ein bisschen in meinem Kommentar zu erweitern. Das gc
DataFrame erfordert eine Zeile für jede Ebene von gene
in der Reihenfolge der Ebenen, damit dies funktioniert:
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
Aber es ist nicht schwer zu beheben:
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
Andere Tipps
Eine alternative Lösung, die Sashas Ansatz nicht übertroffen, aber verallgemeinerbarer und lesbarer ist, ist einfach einfach merge
Die beiden Datenrahmen:
d <- merge(d, gc)
Ich habe ein langsameres System, also hier sind mein Zeitpunkt:
> 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
Der Vorteil ist, dass Sie mehrere Schlüssel, eine feine Kontrolle über nicht übereinstimmende Gegenstände haben können.