如何在 R 中加速简单的 mutate 命令

How to speed up simple mutate command in R

我是 R 的新手,但我有一个相对简单的 mutate 命令,我正在 运行ning 处理一个大型数据集(4,000,000 多行 x 150 列),目前需要 15 多个小时才能完成运行。

该查询使用一个 if 语句,该语句只查看几列 - 一个数字变量和一个日期(nb - 一些日期是 NA)和 returns 一个二进制标志。在一个小示例上运行良好,但在超过 1m 行的任何内容上似乎效率都很低。

我正在使用 R v3.5、RStudio 1.2.1335 和 dplyr 0.8.0.1

## create dummy dataframe
df <- data.frame(diff = c(35,432,-278,6556,90,10,76,-24,6),
      date_a = as.Date(c("2017-03-21","2017-01-08",NA,"2015-12-01",
                    "2019-03-09",NA,"2018-09-06","2017-06-01",
                    "2018-05-30")))
library(dplyr)
df <- df %>%
    mutate(flag = if_else(diff > 21 | is.na(date_a),1,0))

当我将数据分块到更小的大小时,该过程需要:

任何比这更大的东西都超出了我准备等待的...

您可以使用 as.numeric 将布尔值转换为 0 和 1:

df <- df %>%
    mutate(flag = as.numeric(diff > 21 | is.na(date_a)))

对于这个 特殊的 问题,您可以使用这样一个事实,即 will 的布尔值映射到您的 if_else 语句生成的值。

df <- df %>%
    mutate(flag = as.numeric(diff > 21 | is.na(date_a)))

if_elseifelse,虽然矢量化,但确实需要创建所有 true/yes 和所有 false/no, 在它们之间进行子集化之前,如果它们很大,尤其是与您的可用内存相比,这可能会很昂贵。

如果你想要 01 以外的东西,你可以使用以下技巧:

c("no","yes")[as.numeric(diff > 21 | is.na(date_a))+1]

作为参考,我什至无法远程重现这些时间。我怀疑 dplyr 之外的某些东西,可能是 R 之外的东西,例如您与 CPU 的连接或操作系统中的某些其他进程是您遇到的慢速背后的原因。

hh_ss <- function (form = "%H:%M:%S") {
  cat(format(Sys.time(), format = form), "\n")
}
hh_ss()
#> 23:36:22
df <- data.frame(diff = rep_len(c(35,432,-278,6556,90,10,76,-24,6), 4e6),
                 date_a = as.Date(c("2017-03-21","2017-01-08",NA,"2015-12-01",
                                    "2019-03-09",NA,"2018-09-06","2017-06-01",
                                    "2018-05-30", 
                                    "2018-05-30")))
hh_ss()
#> 23:36:22
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
df <- df %>%
  mutate(flag = if_else(diff > 21 | is.na(date_a),1,0))
hh_ss()
#> 23:36:23

reprex package (v0.3.0)

于 2019-09-05 创建

添加 150 列变化不大:

hh_ss <- function (form = "%H:%M:%S") {
  cat(format(Sys.time(), format = form), "\n")
}
hh_ss()
#> 23:40:16
df <- data.frame(diff = rep_len(c(35,432,-278,6556,90,10,76,-24,6), 4e6),
                 date_a = as.Date(c("2017-03-21","2017-01-08",NA,"2015-12-01",
                                    "2019-03-09",NA,"2018-09-06","2017-06-01",
                                    "2018-05-30", 
                                    "2018-05-30")))

# Add 150 columns
for (j in paste0(c(letters, LETTERS)[1:50], 1:150)) {
  df[[j]] <- 0L
}


hh_ss()
#> 23:40:17
suppressPackageStartupMessages(library(dplyr))
df <- df %>%
  mutate(flag = if_else(diff > 21 | is.na(date_a),1,0))
hh_ss()
#> 23:40:18

reprex package (v0.3.0)

于 2019-09-05 创建