Вот матрица, в которой каждая строка является реализацией процесса MA (1).
V <- matrix(rnorm(1000*10, mean = -1, sd = 1),
nrow = 1000, ncol = 10)
H <- matrix(nrow = 1000, ncol = 10)
H[,1] <- -.5
for (t in seq_len(9)) {
H[,t+1] <- V[,t+1] + .9 * V[,t]
}
Я хотел бы найти первый элемент каждой строки, который больше 0. Если элементов нет в строке больше 0, тогда я хотел бы вернуть Inf
.
Вот три различных способа, которые я пробовал.
find.min <- function (x) {
e <- which(x >= 0)
if (length(e) > 0) {
return(min(e))
} else {
return(Inf)
}
}
find.min2 <- function (x) {
e <- Position(function(a) (a >= 0), x)
if (is.na(e)) {
return(Inf)
} else {
return(e)
}
}
library("purrr")
find.min3 <- function (x) {
e <- detect_index(x, function(a) (a >= 0))
if (e == 0) {
return(Inf)
} else {
return(e)
}
}
И результаты сравнительного анализа:
library("microbenchmark")
> microbenchmark(apply(H, 1, find.min),
+ apply(H, 1, find.min2),
+ apply(H, 1, find.min3))
Unit: milliseconds
expr min lq mean median uq
apply(H, 1, find.min) 1.361127 1.490270 1.732356 1.588842 1.668582
apply(H, 1, find.min2) 3.587456 3.791422 4.460397 4.172458 4.265154
apply(H, 1, find.min3) 29.167030 31.414109 34.781083 33.170437 35.959100
max neval
6.824049 100
10.003467 100
135.689261 100
Исходя из этого, у меня есть три вопроса:
Почему find.min2
медленнее, чем find.min
? Я думал, что Position
будет быстрее, так как он выходит после нахождения первого TRUE
?
Есть ли более быстрый способ, что find.min
?
find.min
была моей первой попыткой, и я начал бенчмаркинг, потому что профилирование показало, что это было узким местом в симуляции Монте-Карло, которая, по сути, вычисляет среднее значение столбца H
во всех строках, где первый положительный результат в H
был столбец 4 (скажем). Я немного новичок в R, но я был удивлен, что просто определение набора строк для усреднения может стать узким местом. Я что-то не так делаю?
ОБНОВЛЕНИЕ
На основании комментария обновленный тест:
library("microbenchmark")
> microbenchmark(apply(H, 1, find.min),
+ apply(H, 1, find.min2),
+ apply(H, 1, find.min3),
+ replace(y <- max.col(H > 0, ties.method = "first"), y == 1, Inf),
+ unit = "ms")
Unit: milliseconds
expr min lq
apply(H, 1, find.min) 1.321301 1.4468300
apply(H, 1, find.min2) 3.669489 3.7948605
apply(H, 1, find.min3) 29.390980 31.4460145
replace(y <- max.col(H > 0, ties.method = "first"), y == 1, Inf) 0.053014 0.0854115
mean median uq max neval
1.71449367 1.5661085 1.630354 7.575459 100
4.40715776 4.1524930 4.322261 10.553739 100
34.21487510 33.5333335 37.028033 44.427120 100
0.09416856 0.0996835 0.107846 0.213543 100
Итак предлагаемый подход выглядит намного быстрее. Но почему? apply
медленно?