如何在 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))
当我将数据分块到更小的大小时,该过程需要:
- 20k 行 = 1.9 秒
- 20 万行 = 1.7 分钟
- 50 万行 = 10 分钟
- 1 米行 = 34 分钟
任何比这更大的东西都超出了我准备等待的...
您可以使用 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_else
和 ifelse
,虽然矢量化,但确实需要创建所有 true
/yes
和所有 false
/no
, 在它们之间进行子集化之前,如果它们很大,尤其是与您的可用内存相比,这可能会很昂贵。
如果你想要 0
和 1
以外的东西,你可以使用以下技巧:
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 创建
我是 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))
当我将数据分块到更小的大小时,该过程需要:
- 20k 行 = 1.9 秒
- 20 万行 = 1.7 分钟
- 50 万行 = 10 分钟
- 1 米行 = 34 分钟
任何比这更大的东西都超出了我准备等待的...
您可以使用 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_else
和 ifelse
,虽然矢量化,但确实需要创建所有 true
/yes
和所有 false
/no
, 在它们之间进行子集化之前,如果它们很大,尤其是与您的可用内存相比,这可能会很昂贵。
如果你想要 0
和 1
以外的东西,你可以使用以下技巧:
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 创建