spec_tbl_df 在与普通 tibble 相同的操作上慢 10 倍以上

spec_tbl_df is over 10 times slower on same opperations as a normal tibble

所以我真的很想知道为什么两个不同的 R 会话使用相同的数据会产生截然不同的时间来完成相同的任务。 在多次重新启动 R、清除所有变量并真正 运行 一个干净的 R 之后,我发现了问题:vroomreadr 提供的新数据结构对于某些人来说是原因,我的剧本超级迟钝。当然,解决这个问题最简单的方法是在加载数据后立即将其转换为 tibble。或者是否有其他解释,比如我的函数中糟糕的编码实践可以解释缓慢的行为?或者,这是这些软件包最近更新的错误吗?如果是这样,并且如果有人在向 tidyverse 报告错误方面更有经验,那么这里是 repex 显示行为的原因,因为我觉得这超出了我的范围。

#Load packages
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(purrr)
library(vroom)
library(tidyr)
library(microbenchmark)
#Genenrate some dummy data
ex_data <- tibble(
  sd = 1,
  mean = 1:1000,
  a1 = rnorm(1000, mean, sd),
  a2 = rnorm(1000, mean, sd),
  a3 = rnorm(1000, mean, sd)
  ) %>% 
  mutate(
    a1 = if_else(a1<mean, NA_real_, a1),
    a2 = if_else(a2<mean, NA_real_, a2),
    a3 = if_else(a3<mean, NA_real_, a3)
  )
#Wrapper function discovering the behavioure
impute_row <- function(mean, sd, data){
  if(!anyNA(data)){
    return(data)
  }else{
    data <- as.data.frame(data)
    data[is.na(data)] <-  rnorm(n = sum(is.na(data)), mean = mean, sd = sd)
    return(data)
  }
}
#Main function
imputer <- function(data){
  data %>% 
    mutate(
      data = pmap(list(mean, sd, data), impute_row)
    ) %>% 
    unnest(cols = data)
}
#Generate dummy file
out_file <- tempfile(fileext = "csv")
vroom_write(ex_data, out_file, ",")
#Read it in
ex_data_spc <- vroom(out_file, col_types = cols()) %>% 
  nest(data = -c(mean, sd))
#Nest the original data as well
ex_data <- ex_data %>% 
  nest(data = -c(mean, sd))
#Benchmark
microbenchmark(
  tib = imputer(ex_data),
  spc_tib = imputer(ex_data_spc),
  times = 10
)
#> Unit: milliseconds
#>     expr        min         lq       mean     median        uq       max neval
#>      tib   82.81192   87.45288   89.19118   90.47263   91.2216   93.4418    10
#>  spc_tib 1041.90378 1070.00579 1244.97090 1076.92022 1093.0054 2780.0722    10

reprex package (v2.0.0)

于 2021 年 6 月 14 日创建

在最坏的情况下比 运行 慢将近 30 倍。

This 是我想到的问题。众所周知,这些问题会发生在 vroom 上,而不是 spec_tbl_df class,后者的作用并不大。

vroom 做各种事情来尝试加快阅读速度; AFAIK 主要是懒惰阅读。这就是比较两个数据集时获得所有这些不同组件的方式。

有房间:

~~~(snip)~~~
ex_data_spc <- vroom(out_file, col_types = cols()) %>% 
  nest(data = -c(mean, sd))
~~~(snip)~~~

#> Unit: milliseconds
#>     expr       min        lq     mean    median        uq       max neval cld
#>  spc_tib 1679.2088 1704.3085 2106.864 1731.6694 1942.9444 4918.4498    10   b
#>      tib  149.8716  158.8548  169.489  170.3735  182.5681  192.8533    10  a

all.equal(ex_data, ex_data_spc)
#>    [1] "Component \"data\": Component 1: Attributes: < Names: 1 string mismatch >"                                                 
#>    [2] "Component \"data\": Component 1: Attributes: < Length mismatch: comparison on first 2 components >"                        
#>    [3] "Component \"data\": Component 1: Attributes: < Component \"class\": Lengths (3, 4) differ (string compare on first 3) >"   
#>    [4] "Component \"data\": Component 1: Attributes: < Component \"class\": 3 string mismatches >"                                 
#>    [5] "Component \"data\": Component 1: Attributes: < Component 2: Modes: numeric, externalptr >"  
                               
~~~(snip)~~~

有读者:

~~~(snip)~~~
ex_data_spc <- readr::read_csv(out_file, col_types = cols()) %>% 
  nest(data = -c(mean, sd))
~~~(snip)~~~
#> Unit: milliseconds
#>     expr      min       lq     mean   median       uq      max neval cld
#>  spc_tib 148.9432 161.7315 181.2137 184.4592 191.9048 219.7883    10   a
#>      tib 161.9441 166.7826 175.3644 175.3354 181.4598 197.5544    10   a

all.equal(ex_data, ex_data_spc)
#> [1] TRUE

如果你愿意,你可以post你对那个问题的代表。