【问题标题】:Slow dplyr query in RR中的慢dplyr查询
【发布时间】:2020-04-02 20:27:36
【问题描述】:

我在 R 中有一些代码:

library(dplyr)

df_temp <- df %>%
   group_by(policy_number, policy_year) %>% 
   summarise(term_start_date  = last(term_start_date),
             term_end_date    = last(term_end_date),
             on_cover_after   = last(on_cover_after),
             termination_code = last(termination_code),
             termination_date = last(termination_date))

主表df 大约有 700,000 行 x 130 列。按policy_number 和policy_year 分组,大约有300,000 个(policy_number/policy_year)分组。

我在last() 中提到的 5 列中有 4 列是日期。

这个查询运行大约需要 3 分钟,这很麻烦,因为我的其余代码运行得非常快。我希望能加快速度。请问有什么我可以尝试的方法吗?

(理想情况下会提供一个代表,但我怎么能在这里做到这一点?不确定)

谢谢。

编辑:由于我总是使用给定 (policy_number/policy_year) 对的最后一条记录,因此我可以编写以下代码:

df_temp <- df %>%
   group_by(policy_number, policy_year) %>% 
   mutate(counter = 1:n()) %>%
   filter(counter == max(counter)) %>%
   select(term_start_date,
          term_end_date,
          on_cover_after,
          termination_code,
          termination_date)

?

【问题讨论】:

  • 您可以通过共享代码来提供一个代表来模拟数据。首先使用set.seed,这样它就可以完全重现。类似n = 7e5; df = tibble(policy_number = sample(1:1e5, size = n, replace = TRUE), policy_year = sample(2017:2019, size = n, replace = TRUE), ...)
  • 至于您的编辑,df %&gt;% group_by(policy_number, policy_year) %&gt;% select(term_start_date, term_end_date, on_cover_after, termination_code, termination_date) %&gt;% slice(n()) 会起作用。不确定它是否更快。将select before 放在summarize(或slice,在这种情况下)可能也有帮助。添加一些数据,我们会做一些基准测试。
  • 是否存在行顺序所基于的列?提供一个有助于了解的data.table 解决方案。

标签: r dplyr


【解决方案1】:

有一个很好的来源here 关于这个。作者提出了几个很好的建议(参见他的 cmets 部分)。我会考虑用 data.table 聚合你的数据,或者如果你坚持使用 dplyr,那么考虑定义一个键。一些相对基准的指标:

From source

【讨论】:

  • 另一个伟大的来源here dplyr vs data.table 中的可比解决方案
【解决方案2】:

用summarise_at代替summarise

library(dplyr)
df %>%
   group_by(policy_number, policy_year) %>%
   summarise_at(vars(term_start_date, term_end_date,
       term_end_date,termination_code, termination_date), last)

【讨论】:

  • 哦,这很有趣。谢谢你。我不知道 summarise_at()。我明天试试。
【解决方案3】:

您可以直接尝试dtplyr 包(data.table 后端为dplyr)或data.table 包以加快计算速度。请参阅以下iris 数据集的基准

library(microbenchmark)
library(data.table)
library(dtplyr)
library(dplyr, warn.conflicts = FALSE)

# create a “lazy” data table for dtplyr
iris2 <- lazy_dt(iris)

# create a data table for data.table
dt <- setDT(copy(iris))

# dplyr calculation
dplyr_func <- function() {
  iris %>% 
    group_by(Species) %>% 
    summarise_at(vars(Sepal.Length:Petal.Width), last)      
}

# dtplyr calculation
dtplyr_func <- function() {
  iris2 %>% 
    group_by(Species) %>% 
    summarise_at(vars(Sepal.Length:Petal.Width), last)  %>% 
    as_tibble()      
}

# data.table calculation
dt_func <- function() {
  dt[ 
    , lapply(.SD, last)
    , Species]
}

基准测试

microbenchmark(
  dplyr_func(),
  dtplyr_func(),
  dt_func(),
  times = 1000L
)

#> Unit: microseconds
#>           expr    min     lq   mean median     uq   max neval cld
#>   dplyr_func() 4605.0 4892.9 5180.3 4999.9 5155.1 23253  1000   c
#>  dtplyr_func() 2503.9 2633.6 2885.0 2714.3 2812.2 39490  1000  b 
#>      dt_func()  949.2 1155.3 1848.1 2036.0 2302.1  7251  1000 a

由reprex package (v0.3.0) 于 2020-04-02 创建

【讨论】:

猜你喜欢
  • 2021-12-12
  • 2021-07-06
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 1970-01-01
  • 2019-09-01
  • 2018-12-02
  • 1970-01-01
相关资源
最近更新 更多