2011-03-14 48 views
5

我有一個名爲「d」的〜1,300,000行和4列data.frame和另一個data.frame,名爲「gc」,約12,000行和2列(但請看下面的小例子)。如何重寫「sapply」命令以提高性能?

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

這裏是 「d」 的樣子:

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 

這裏是 「GC」:

gene chr 
1 a c1 
2 b c2 
3 c c3 

我想通過將增加一個第5列,以 「d」來自「gc」的數據與「d」的第一列匹配。目前我正在使用sapply

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

但在真實的數據,它需要一個「很長」的時間(我正在用命令「system.time()」以來,超過30分鐘,它仍然沒有完成)。

你有什麼想法我可以用聰明的方式改寫這個嗎?或者我應該考慮使用plyr,也許與「並行」選項(我的電腦上有四個核心)?在這種情況下,最好的語法是什麼?

在此先感謝。

回答

12

我想你可以只使用係數爲指數:

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] c1 c2 c3 c1 c2 c3 c1 c2 c3 c1 c2 c3 
Levels: c1 c2 c3 

但速度要快得多:

> 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 

編輯:

擴大一下我的評論。該gc數據幀需要在這個級別的順序gene每個級別有一個行的工作:

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 

但它不是很難解決這個問題:

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

感謝,這正是我需要的。 – tflutre 2011-03-14 20:30:11

+1

+1這太棒了,我不知道這甚至是可能的。 – 2011-03-15 00:46:26

+0

我既不tbh :)但有一個問題。那就是gc [,1]在這裏必須與d [,1]完全相同,每個級別只有一行,每個級別必須是相同的順序。訣竅是,一個因素在數字上對應於1,2 ... – 2011-03-15 07:33:37

1

另一種解決方案,它不打薩沙的接近時刻,明智的,但更普及和可讀性,是簡單地merge兩個數據幀:

d <- merge(d, gc) 

我有一個速度較慢的系統,所以這裏是我的時刻:

> 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 

的好處是,你可以有多個按鍵,在不匹配的項目精細控制等