等效于 min() 的 rowMeans()

Posted

技术标签:

【中文标题】等效于 min() 的 rowMeans()【英文标题】:Equivalent to rowMeans() for min() 【发布时间】:2011-09-14 09:00:45 【问题描述】:

我在 R 邮件列表上看到这个问题被问了多次,但仍然找不到满意的答案。

假设我是一个矩阵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 倍的时间,有没有办法加快速度?

【问题讨论】:

【参考方案1】:
library("sos")
findFn("rowMin")

在来自 Bioconductor 的 Biobase 包中获得成功...

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)快很多

【讨论】:

谢谢,我不知道 sos 包,rowMin 也解决了我的问题。 也想为do.call 解决方案计时?【参考方案2】:

您可以使用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 

【讨论】:

我喜欢使用do.call。我想到了pmin,但没有想到一个巧妙的方法来合并它。所有很酷的孩子似乎都可以使用do.call 来实现他们的目标……我需要对此进行一些阅读。 do.call 在您希望能够动态创建函数参数时派上用场(通常是在不知道通过 ... 传递的参数数量时)。 很好的答案,谢谢!使用 pmin.int() 甚至更快 Hadley 的 functions that you need to know 词汇量不错。还有pmin @danas.zuokas: do.call(pmin, c(na.rm=TRUE, lapply(...)))【参考方案3】:

我一直想在 R 2.13.0 中试用新的 compiler 包。这基本上遵循 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

至少可以说有点不合时宜,不过看起来您还有其他一些不错的选择。

【讨论】:

感谢您的回答,我将不得不深入研究您的回答,这对我来说是新领域:) 编译器在优化显式循环方面效果更好。试试例如:rowMin &lt;- function(x) n &lt;- nrow(x);r &lt;- numeric(n);for (i in 1:n) r[i] &lt;- min(x[i,]);r【参考方案4】:

不是特别 R-idiosyncratic,但肯定最快的方法就是使用 pmin 并遍历列:

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

在我的机器上,对于 1e+07x10 矩阵,它只需要比 rowMeans 长 3 倍的时间,并且比通过 data.framedo.call 方法稍快。

【讨论】:

还有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 很耗时。 虽然打字速度不快,但对于不同的输入来说一般:) 我在对 Joshua 答案的评论中添加了更通用的解决方案。【参考方案5】:

如果你想坚持使用 CRAN 包,那么 matrixStatsfBasics 包都具有函数 rowMins [注意 s 不在 Biobase 函数中 em>] 以及各种其他行和列统计信息。

【讨论】:

【参考方案6】:

聚会迟到了,但作为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

【讨论】:

@HenirkB 如果 matrixStats rowMins 也可以处理 data.frames,那就太好了(无需先将其转换为矩阵) @skan,不幸的是由于各种原因,这不是matrixStats,请看github.com/HenrikBengtsson/matrixStats/issues/18

以上是关于等效于 min() 的 rowMeans()的主要内容,如果未能解决你的问题,请参考以下文章

PHP PDO 等效于 mysql_num_rows [重复]

等效于 R 中 big.matrix 的 row() 和 col()

等效于 Jetpack Compose Lazy Column/Row 中的 adapter.notifydatasetchange 或 Diffutils

MySQL FOUND_ROWS() 方法的 SQL 等效项是啥?

MySQL 中用于插入的 ROW_NUMBER() 等效项[重复]

Oracle 等效于 information_schema.tables