В R самый быстрый способ найти первый элемент каждой строки, удовлетворяющий условию - PullRequest
1 голос
/ 20 апреля 2020

Вот матрица, в которой каждая строка является реализацией процесса 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

Исходя из этого, у меня есть три вопроса:

  1. Почему find.min2 медленнее, чем find.min? Я думал, что Position будет быстрее, так как он выходит после нахождения первого TRUE?

  2. Есть ли более быстрый способ, что find.min?

  3. 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 медленно?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...