Эквивалентно 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 раз, есть ли способ ускорить это?
Ответы
Ответ 1
Вы можете использовать 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
Ответ 2
Довольно поздно вечеринке, но как автор 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
Ответ 3
Если вы хотите придерживаться пакетов CRAN, то пакеты matrixStats
и fBasics
имеют функцию rowMins
[обратите внимание на s
, которая не находится в функции Biobase
], и множество другие статистики строк и столбцов.
Ответ 4
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)
Ответ 5
Я хотел попробовать новый пакет compiler
в R 2.13.0. Это в основном следует за сообщением, описанным Dirk здесь.
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
Актиматический, если не сказать больше, хотя, похоже, у вас есть другие хорошие варианты.
Ответ 6
Не особенно R-идиосинкразированный, но, безусловно, самым быстрым методом является просто использовать pmin
и перебирать столбцы:
x <- m[,1]
for (i in 2:ncol(m)) x <- pmin(x, m[,i])
На моей машине, которая занимает всего 3 раза дольше, чем rowMeans для матрицы 1e + 07x10, и немного быстрее, чем метод do.call
через data.frame
.