Эквивалентно 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
,