2011-06-14 37 views
16

我看到這個問題在R郵件列表中被多次詢問,但仍然找不到滿意的答案。等價於rowMeans()for min()

假設我一個矩陣m

m <- matrix(rnorm(10000000), ncol=10) 

我可以得到每行的意思是:

system.time(rowMeans(m)) 
    user system elapsed 
    0.100 0.000 0.097 

但是,

system.time(apply(m,1,min)) 
    user system elapsed 
16.157 0.400 17.029 

獲得每行的最低值取超過100倍的時間,有沒有辦法加快速度?

回答

15

快了很多你可以使用pmin,但你必須將矩陣的每一列都放入一個單獨的向量中。一種方法是將其轉換爲data.frame,然後通過do.call調用pmin(因爲data.frames是列表)。

system.time(do.call(pmin, as.data.frame(m))) 
# user system elapsed 
# 0.940 0.000 0.949 
system.time(apply(m,1,min)) 
# user system elapsed 
# 16.84 0.00 16.95 
+0

我喜歡使用'do.call'。我想到了'pmin',但沒有想到一個合適的方法來合併它。所有酷酷的孩子似乎都可以使用'do.call'來實現他們的目標......我需要對此進行一些閱讀。 – Chase 2011-06-14 03:08:00

+0

當您希望能夠動態地創建函數參數時(通常當通過'...'傳遞的參數數量未知時)''do.call'派上用場。 – 2011-06-14 03:17:16

+1

很好的答案,謝謝!與pmin.int()它甚至更快一點 – johannes 2011-06-14 03:35:11

5
library("sos") 
findFn("rowMin") 

得到一個砸在Biobase包,從Bioconductor的...

source("http://bioconductor.org/biocLite.R") 
biocLite("Biobase") 

m <- matrix(rnorm(10000000), ncol=10) 
system.time(rowMeans(m)) 
## user system elapsed 
## 0.132 0.148 0.279 
system.time(apply(m,1,min)) 
## user system elapsed 
## 11.825 1.688 13.603 
library(Biobase) 
system.time(rowMin(m)) 
## user system elapsed 
## 0.688 0.172 0.864 

不一樣快rowMeans,但比apply(...,1,min)

+0

謝謝,我沒有意識到sos包和rowMin也解決了我的問題。 – johannes 2011-06-14 03:36:39

+0

還需要注意確定'do.call'解決方案的時間嗎? – 2011-06-14 07:43:27

5

我一直想嘗試新的compiler包中的R 2.13.0。這基本上遵循由Dirk here概述的帖子。

library(compiler) 
library(rbenchmark) 
rowMin <- function(x, ind) apply(x, ind, min) 
crowMin <- cmpfun(rowMin) 

benchmark(
     rowMin(m,1) 
    , crowMin(m,1) 
    , columns=c("test", "replications","elapsed","relative") 
    , order="relative" 
    , replications=10) 
) 

而且結果:

  test replications elapsed relative 
2 crowMin(m, 1)   10 120.091 1.0000 
1 rowMin(m, 1)   10 122.745 1.0221 

Anticlimatic,至少可以說,雖然看起來很像你已經得到了其他一些不錯的選擇。

+0

感謝您的回答,我將不得不更深入地瞭解您的答案,這是新的地形我:) – johannes 2011-06-14 03:38:07

+1

編譯器在顯式循環的優化方面更好。例如:rowMin < - function(x){n < - nrow(x); r < - numeric(n); for(i in 1:n)r [i] < - min(x [i,])) ; r}' – Marek 2011-06-14 05:22:59

+3

+1,用於避免'發佈偏差' – 2011-06-14 06:52:29

2

不是特別R-特質,但肯定是最快的方法,只是使用pmin和環比列:

x <- m[,1] 
for (i in 2:ncol(m)) x <- pmin(x, m[,i]) 

在我的機器運行時間超過rowMeans爲1E + 07x10矩陣不再僅僅3次,並且通過data.framedo.call方法略快。

+0

另一個速度增益爲'pmin(m [,1],m [,2],m [,3],m [,4],m [,5 ],m [,6],m [,7],m [,8],m [,9],m [,10])''。 Joshua'as.data.frame'非常耗時。 – Marek 2011-06-14 10:05:54

+1

雖然對於打字不太快,或者對一般輸入不一致:) – mdsumner 2011-06-14 12:18:40

+0

我在約書亞的回答中添加了更多通用解決方案。 – Marek 2011-06-14 15:31:06

8

如果你要堅持CRAN的包,那麼無論是matrixStatsfBasics包裝具備的功能rowMins [注意s這是不是在Biobase功能]和各種其他行和列的統計數據。

10

晚會很晚,但作爲matrixStats的作者,如果有人發現這種情況,請注意matrixStats::rowMins()這幾天非常快,

library(microbenchmark) 
library(Biobase)  # rowMin() 
library(matrixStats) # rowMins() 
options(digits=3) 

m <- matrix(rnorm(10000000), ncol=10) 

stats <- microbenchmark(
    rowMeans(m), ## A benchmark by OP 
    rowMins(m), 
    rowMin(m), 
    do.call(pmin, as.data.frame(m)), 
    apply(m, MARGIN=1L, FUN=min), 
    times=10 
) 

> stats 
Unit: milliseconds 
          expr min  lq mean median  uq max 
         rowMeans(m) 77.7 82.7 85.7 84.4 90.3 98.2 
         rowMins(m) 72.9 74.1 88.0 79.0 90.2 147.4 
         rowMin(m) 341.1 347.1 395.9 383.4 395.1 607.7 
    do.call(pmin, as.data.frame(m)) 326.4 357.0 435.4 401.0 437.6 657.9 
apply(m, MARGIN = 1L, FUN = min) 3761.9 3963.8 4120.6 4109.8 4198.7 4567.4 
+0

@HenirkB如果matrixStats rowMins也處理data.frames(不需要首先將其轉換爲矩陣) – skan 2015-07-23 19:51:18

+1

@skan,不幸的是,由於各種原因,這屬於matrixStats並不明顯,請參閱https:/ /github.com/HenrikBengtsson/matrixStats/issues/18 – HenrikB 2015-07-24 20:51:25