Эквивалентно rowMeans() для min()

Я видел этот вопрос несколько раз в списке рассылки 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 раз больше времени, есть ли способ ускорить это?

6 ответов

Решение

Вы могли бы использовать pmin, но вы должны получить каждый столбец вашей матрицы в отдельный вектор. Один из способов сделать это - преобразовать его в data.frame, а затем вызвать pmin с помощью do.call (поскольку 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 

Довольно поздно на вечеринку, но как автор 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

Если вы хотите придерживаться пакетов CRAN, то оба matrixStats и fBasics пакеты имеют функцию rowMins [ обратите внимание на s которого нет в Biobase функция ] и множество других статистик строк и столбцов.

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

получает удар в 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)

Я хотел попробовать новый compiler пакет в R 2.13.0. Это по существу следует за постом, обрисованным в общих чертах Дирком здесь.

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

Антиклиматический, если не сказать больше, хотя, похоже, у вас есть и другие хорошие варианты.

Не особенно R-идиосинкразический, но, безусловно, самый быстрый метод - это просто использовать pmin и цикл по столбцам:

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

На моей машине это занимает всего 3 раза больше, чем rowMeans для матрицы 1e+07x10, и немного быстрее, чем do.call метод через data.frame,

Другие вопросы по тегам