【问题标题】:R microbenchmark: How to pass same argument to evaluated functions?R microbenchmark:如何将相同的参数传递给评估函数?
【发布时间】:2020-01-10 18:02:37
【问题描述】:

我想评估使用不同文件类型(geotiff、二进制)或对象(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'
)

我包含了我的数据集here 的样本

有了这个,我可以看到 RasterBrick 上的采样比堆栈快(R Raster 手册也这么说——很好)。问题是我在每个评估表达式的不同点进行采样。所以我无法检查结果是否相同。我想做的是在两个对象的同一位置(poi)采样。但是每次迭代的位置都不同。我尝试在 microbenchmark 中使用 setup 选项,但据我所知,setup 在每个函数计时之前进行评估,而不是每次迭代一次。因此使用设置生成随机 poi 将不起作用。

是否可以将相同的参数传递给在 microbenchmark 中评估的函数?

结果

使用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)
  )
)

【问题讨论】:

  • 也许github.com/r-lib/benchmicrobenchmark 更适合您的需求?可以分享一些数据吗?如果不知道数据是什么样的,我很难理解你的问题。
  • 我正在处理的数据集有点大。我将尝试分离一小块并制作一个可重现的示例
  • 你可以做dput(head(annual_brick, 20))
  • 设置set.seed() 会起作用吗?
  • 不会在微基准测试中的每个表达式之前评估 set.seed() 吗?所以我对每个表达式都有不同的种子(和随机点)。如果我修复了种子,那么我将在基准测试的所有迭代中采样相同的点。

标签: r r-raster microbenchmark


【解决方案1】:

我的方法是为 microbenchmark 中的每个选项设置相同的席位,但在每个函数调用之前更改它们。查看输出以及最终如何将相同的座位用于两个呼叫

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】:

    如果我理解正确,OP 有 两个 要求:

    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,因为相同的数据样本将用于所有重复。

    重复的不同随机数

    OP 要求:

    是否可以将相同的参数传递给正在执行的函数 在微基准测试中评估?

    一种可能性是使用forlapply() 循环一系列种子值,如对类似question 的回答中所建议的那样。

    在这种情况下,我建议使用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 的重复次数。 mark()iterations 参数指定为 same 种子/poi 重复计时的频率。

    可以使用绘制结果

    library(ggplot2)
    autoplot(bm)
    

    或总结使用

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

    【讨论】:

    • 但是在基准过程的每次迭代中采样点不会相同吗?
    • 是的,没错。也许,bench 包中的press() 可能是这里的替代方案。在那里,您可以将 set.seed() 的不同值作为参数传递给基准测试。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多