2011-06-14 51 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