首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么当我使用‘`dplyr::mutate()’时,`furrr::future_map_int()`比`purrr::map_int()‘慢?

为什么当我使用‘`dplyr::mutate()’时,`furrr::future_map_int()`比`purrr::map_int()‘慢?
EN

Stack Overflow用户
提问于 2021-11-02 09:27:48
回答 1查看 304关注 0票数 5

我有一个tibble,里面有一个包含向量的列表列。我想要创建一个新列,说明每个向量的长度。由于这个数据集很大(3M行),我想使用furrr包减少一些处理时间。然而,purrr似乎比furrr更快。怎么会这样?

为了演示这个问题,我首先模拟了一些数据。不要费心去理解模拟部分中的代码,因为它与问题无关。

数据模拟功能

代码语言:javascript
复制
library(stringi)
library(rrapply)
library(tibble)

simulate_data <- function(nrows) {
  split_func <- function(x, n) {
    unname(split(x, rep_len(1:n, length(x))))
  }
  
  randomly_subset_vec <- function(x) {
    sample(x, sample(length(x), 1))
  }
  
  tibble::tibble(
    col_a = rrapply(object = split_func(
      x = setNames(1:(nrows * 5),
                   stringi::stri_rand_strings(nrows * 5,
                                              2)),
      n = nrows
    ),
    f      = randomly_subset_vec),
    col_b = runif(nrows)
  )
  
} 

模拟数据

代码语言:javascript
复制
set.seed(2021)

my_data <- simulate_data(3e6) # takes about 1 minute to run on my machine

my_data
## # A tibble: 3,000,000 x 2
##    col_a      col_b
##    <list>     <dbl>
##  1 <int [3]> 0.786 
##  2 <int [5]> 0.0199
##  3 <int [2]> 0.468 
##  4 <int [2]> 0.270 
##  5 <int [3]> 0.709 
##  6 <int [2]> 0.643 
##  7 <int [2]> 0.0837
##  8 <int [4]> 0.159 
##  9 <int [2]> 0.429 
## 10 <int [2]> 0.919 
## # ... with 2,999,990 more rows

实际问题

我想修改一个新列(length_col_a),它将考虑到col_a的长度。我要做两次。首先使用purrr::map_int(),然后使用furrr::future_map_int()

代码语言:javascript
复制
library(dplyr, warn.conflicts = T)
library(purrr)
library(furrr)
library(tictoc)

# first with purrr:
##################
tic()
my_data %>%
  mutate(length_col_a = map_int(.x = col_a, .f = ~length(.x)))

## # A tibble: 3,000,000 x 3
##    col_a      col_b length_col_a
##    <list>     <dbl>        <int>
##  1 <int [3]> 0.786             3
##  2 <int [5]> 0.0199            5
##  3 <int [2]> 0.468             2
##  4 <int [2]> 0.270             2
##  5 <int [3]> 0.709             3
##  6 <int [2]> 0.643             2
##  7 <int [2]> 0.0837            2
##  8 <int [4]> 0.159             4
##  9 <int [2]> 0.429             2
## 10 <int [2]> 0.919             2
## # ... with 2,999,990 more rows
toc()
## 6.16 sec elapsed


# and now with furrr:
####################
future::plan(future::multisession, workers = 2)

tic()
my_data %>%
  mutate(length_col_a = future_map_int(col_a, length))
## # A tibble: 3,000,000 x 3
##    col_a      col_b length_col_a
##    <list>     <dbl>        <int>
##  1 <int [3]> 0.786             3
##  2 <int [5]> 0.0199            5
##  3 <int [2]> 0.468             2
##  4 <int [2]> 0.270             2
##  5 <int [3]> 0.709             3
##  6 <int [2]> 0.643             2
##  7 <int [2]> 0.0837            2
##  8 <int [4]> 0.159             4
##  9 <int [2]> 0.429             2
## 10 <int [2]> 0.919             2
## # ... with 2,999,990 more rows
toc()
## 10.95 sec elapsed

我知道tictoc不是最精确的基准测试方法,但是-- furrr应该更快(就像这句话所暗示的),但它不是。我已经确保了数据没有分组,因为furrr对分组数据的作者解释不能很好地工作。那么,对于furrrpurrr慢(或不太快),还有什么其他的解释吗?

编辑

我发现本期furrr的github上讨论了几乎相同的问题。然而,情况不同。在github问题上,正在映射的函数是用户定义的函数,需要附加附加包。因此,作者解释说,每个furrr工作人员在进行计算之前都必须附加所需的包。相比之下,我从base R映射length()函数,因此实际上不应该附加任何包的开销。

此外,作者还指出,由于plan(multisession)没有在RStudio中工作,所以可能会出现问题。但是,更新parallelly包以开发版本解决了这个问题。

代码语言:javascript
复制
remotes::install_github("HenrikBengtsson/parallelly", ref="develop")

不幸的是,这次更新对我的情况没有任何影响。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-02 22:59:05

正如我在对原帖子的评论中所指出的那样,我怀疑这是由于工人分发了非常大的数据集而造成的开销。

为了证实我的怀疑,我使用了OP使用的相同代码,只进行了一次修改:我添加了一个延迟的0.000001,结果是:purrr --> 192.45 secfurrr: 44.707 sec (8 workers)。furrr花的时间只有purrr的1/4

按照OP的要求,我的代码如下:

代码语言:javascript
复制
library(stringi)
library(rrapply)
library(tibble)

simulate_data <- function(nrows) {
  split_func <- function(x, n) {
    unname(split(x, rep_len(1:n, length(x))))
  }
  
  randomly_subset_vec <- function(x) {
    sample(x, sample(length(x), 1))
  }
  
  tibble::tibble(
    col_a = rrapply(object = split_func(
      x = setNames(1:(nrows * 5),
                   stringi::stri_rand_strings(nrows * 5,
                                              2)),
      n = nrows
    ),
    f      = randomly_subset_vec),
    col_b = runif(nrows)
  )
  
} 

set.seed(2021)

my_data <- simulate_data(3e6) # takes about 1 minute to run on my machine

my_data

library(dplyr, warn.conflicts = T)
library(purrr)
library(furrr)
library(tictoc)

# first with purrr:
##################

######## ---->  DELAY <---- ########
f <- function(x) {Sys.sleep(0.000001); length(x)}

tic()
my_data %>%
  mutate(length_col_a = map_int(.x = col_a, .f = ~ f(.x)))
toc()

plan(multisession, workers = 8)

tic()
my_data %>%
  mutate(length_col_a = future_map_int(col_a, f))
toc()
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69808082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档