【问题标题】:Group_by and mutate slow on large dataframeGroup_by 和 mutate 在大型数据帧上变慢
【发布时间】:2019-03-13 13:22:12
【问题描述】:

我正在处理大型(最少 8 百万行)dataframes,并希望根据几个分组变量和rmultinom 进行一些基本计算。就我的代码而言,完成计算至少需要约 1 秒,这不是问题,但我需要做数千次,所以我真的很想加快速度。

我目前正在使用dataframestidyverse,但我与其中任何一个都无关。我曾尝试使用data.table 来实现,但无法弄清楚。任何关于我如何加快速度的建议将不胜感激。

一个例子(真实数据可以大一个数量级或更多):

library(tidyverse)
library(microbenchmark)

# create dummy data
df <- data.frame(fact = rep(letters, each = 312000), 
                 month = rep(month.name, 26), 
                 num = rep(sample(10000:100000, 12), 26), 
                 prob = runif(312))

# Order by month     
df <- df[order(df$month), ]

# group by two factor variables and calculate new variable 
microbenchmark({
  df2 <- df %>%
    group_by(fact, month) %>%
    mutate(res = ifelse(prob > 0, c(rmultinom(1, num[1], prob = prob)), 0))}, times = 10)


 > Unit: milliseconds
 > min      lq       mean     median   uq        max         neval
 > 816.3126 822.4083 840.7966 834.6163 855.5139  879.9345    10

【问题讨论】:

    标签: r dataframe data.table tidyverse


    【解决方案1】:

    评论有点太长了,所以我在这里发布。

    跑步

    library(profr)
    plot(profr(
    df %>% group_by(fact, month) %>% 
       mutate(res = ifelse(prob > 0, c(rmultinom(1, num[1], prob = prob)), 0))
    ))
    

    我得到以下信息:

    因此,您似乎真的想为multinom 找到更快的实现,这似乎是瓶颈。对于dplyrdata.table,这个瓶颈是相同的,这意味着只有加速rmultinorm 才能给你带来显着的速度提升。

    【讨论】:

    • 好的,谢谢,在进一步调查后,另一个用户对rmultinom here 有同样的问题,他们使用Rcpp 实施了一个解决方案,我没有使用过,但会调查。
    【解决方案2】:

    使用,您可以:

    dt <- copy(df)
    setDT(dt)
    
    dt[, res := 0L][prob > 0, res := c(rmultinom(1, num[1], prob = prob)), by = .(fact, month)]
    

    这会给您带来轻微的速度提升:

    microbenchmark(dp = df %>%
                     group_by(fact, month) %>%
                     mutate(res = ifelse(prob > 0, c(rmultinom(1, num[1], prob = prob)), 0)),
                   dt = dt[, res := 0L][prob > 0, res := c(rmultinom(1, num[1], prob = prob)), by = .(fact, month)],
                   times = 1)
    
    Unit: seconds
     expr      min       lq     mean   median       uq      max neval
       dp 1.356745 1.356745 1.356745 1.356745 1.356745 1.356745     1
       dt 1.063363 1.063363 1.063363 1.063363 1.063363 1.063363     1
    

    【讨论】:

    • @Jaap 谢谢,这一切都加起来了!你认为我能做进一步的实质性改进吗?或者这可能和我能得到的一样好?需要决定我是继续寻找改进还是继续前进。干杯。
    • 嗯,我刚刚在我的机器上运行了你的代码,我根本没有获得任何性能提升。
    【解决方案3】:

    dplyrDT 语法中,您不妨减少由管道运算符引起的开销。

    为了说明管道造成的开销:

    microbenchmark(pipe = iris %>%
                     group_by(Species) %>% 
                     mutate(mean = mean(Sepal.Length)),
                   no_pipe = mutate(group_by(iris, Species), mean = mean(Sepal.Length)),
                   times = 100) %>% autoplot()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-01
      • 2017-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-02
      相关资源
      最近更新 更多