R microbenchmark: Как передать один и тот же аргумент в вычисляемые функции? - PullRequest
3 голосов
/ 10 января 2020

Я бы хотел оценить время для извлечения данных из растрового временного ряда, используя разные типы файлов (геотиф, бинарный) или объекты (RasterBrick, RasterStack). Я создал функцию, которая извлекает временные ряды из случайной точки растрового объекта, а затем использую микробенчмарк для его проверки.

Пример.

# read a random point from a raster stack
sample_raster <- function(stack) {
  poi <- sample(ncell(stack), 1)
  raster::extract(stack, poi)
}

# opening the data using different methods
data_stack <- stack(list.files(pattern = '3B.*tif'))
data_brick <- brick('gpm_multiband.tif')

bench <- microbenchmark(
  sample_stack = sample_raster(data_stack),
  sample_brick = sample_raster(data_brick),
  times = 10
)

boxplot(bench)

# this fails because sampled point is different
bench <- microbenchmark(
  sample_stack = sample_raster(data_stack),
  sample_brick = sample_raster(data_brick),
  times = 10,
  check = 'equal'
)

Я включил образец мой набор данных здесь

С этим я вижу, что выборка на RasterBrick быстрее, чем стеки (руководство R Raster также говорит так - хорошо). Проблема в том, что я выполняю выборку в разных точках каждого вычисленного выражения. Поэтому я не могу проверить, совпадают ли результаты. Я хотел бы сделать выборку в одном и том же месте (poi) на обоих объектах. Но расположение должно быть разным для каждой итерации. Я попытался использовать опцию setup в microbenchmark, но из того, что я понял, setup оценивается перед синхронизацией каждой функции, а не один раз за итерацию. Таким образом, генерация случайного poi с использованием установки не будет работать.

Можно ли передать тот же аргумент функциям, оцениваемым в микробенчмарке?

Результат

Решение с использованием microbenchmark

Как предложено (и объяснено ниже), я попробовал пакет bench с вызовом press. Но по какой-то причине это было медленнее, чем установка одного и того же начального числа на каждой итерации microbenchmark, как предлагает mnist . Поэтому я вернулся к microbenchmark. Вот код, который я использую:

library(microbenchmark)
library(raster)

annual_brick <- raster::brick('data/gpm_tif_annual/gpm_2016.tif')
annual_stack <- raster::stack('data/gpm_tif_annual/gpm_2016.tif')

x <- 0
y <- 0

bm <- microbenchmark(
  ext = {
    x <- x + 1
    set.seed(x)
    poi = sample(raster_size, 1)
    raster::extract(annual_brick, poi)
  },
  slc = {
    y <- y + 1
    set.seed(y)
    poi = sample(raster_size, 1)
    raster::extract(annual_stack, poi)
  },
  check = 'equal'
)

Решение с использованием bench::press

Для полноты, это было так, как я сделал, используя bench::press , В процессе я также отделил код для выбора случайной ячейки от функции точечной выборки. Таким образом, я могу определить время только части кода. Вот как я это делаю:

library(bench)
library(raster)

annual_brick <- raster::brick('data/gpm_tif_annual/gpm_2016.tif')
annual_stack <- raster::stack('data/gpm_tif_annual/gpm_2016.tif')

bm <- bench::press(
  pois = sample(ncell(annual_brick), 10),
  mark(
    iterations = 1,
    sample_brick = raster::extract(annual_brick, pois),
    sample_stack = raster::extract(annual_stack, pois)
  )
)

Ответы [ 2 ]

2 голосов
/ 11 января 2020

Мой подход заключается в том, чтобы установить одинаковые места для каждого параметра в микробенахе, но изменять их перед каждым вызовом функции. Посмотрите результаты и то, как одни и те же места используются для обоих вызовов в конечном итоге

x <- 0
y <- 0

microbenchmark::microbenchmark(
  "checasdk" = {
    # increase seat value by 1
    x <- x + 1
    print(paste("1", x))
    set.seed(x)}, 

  "check2" = {
    y <- y + 1
    print(paste("2", y))
    set.seed(y)
    }
  )
2 голосов
/ 10 января 2020

Если я правильно понимаю, у ОП есть два требования:

  1. При синхронизации двух выражений следует выбирать одинаковые точки данных для проверки идентичности результатов.
  2. Кроме того, синхронизация двух выражений должна повторяться для различных выборок точек данных.

Использование одинаковых случайных чисел

Как предполагает Roman , set.seed() может использоваться для установки начальных значений для генератора случайных чисел R. Если используется один и тот же параметр, последовательность сгенерированных случайных чисел будет одинаковой.

sample_raster() можно изменить, чтобы обеспечить инициализацию генератора случайных чисел для при каждом вызове .

sample_raster <- function(stack) {
  set.seed(1L)
  poi <- sample(ncell(stack), 1)
  raster::extract(stack, poi)
}

Это будет соответствовать требованию 1, но не требованию 2, поскольку одни и те же выборки данных будут использоваться для всех повторений.

Различные случайные числа в повторениях

ОП имеет спросил:

Можно ли передать один и тот же аргумент функциям, оцениваемым в микробенчмарке?

Одной из возможностей является использование for или lapply() для l oop для последовательности начальных значений, как предлагается в ответах на аналогичный вопрос .

В этом случае я предлагаю использовать пакет bench для сравнительного анализа. Он имеет функцию press(), которая запускает bench::mark() в сетке параметров.

Для этого sample_raster() получает второй параметр:

sample_raster <- function(stack, seed) {
  set.seed(seed)
  poi <- sample(ncell(stack), 1L)
  # cat(substitute(f), s, poi, "\n") # just to check, NOT to use for timings
  raster::extract(stack, poi)
}

Времена выполняются для разных семена как указано в векторе seed_vec.

library(bench)
bm <- press(
  seed_vec = 1:10,
  mark(
    iterations = 1L,
    sample_stack = sample_raster(data_stack, seed_vec),
    sample_brick = sample_raster(data_brick, seed_vec)
  )
)

Обратите внимание, что длина seed_vec определяет количество повторений с различными poi, сейчас. Параметр iterations для mark() указывает, как часто нужно повторять время для того же семени / poi.

Результаты могут быть нанесены с использованием

library(ggplot2)
autoplot(bm)

или суммировано с использованием

library(dplyr)
bm %>% 
  group_by(expression = expression %>% as.character()) %>% 
  summarise(median = median(median), n_itr = n())
...