【发布时间】:2021-10-21 11:44:36
【问题描述】:
我第一次尝试 dtplyr 和 data.table 在我现有的 dplyr 中进行一些时间优化 > 代码。
问题: 如果我使用 data.table / dtplyr 数据对象,则无法使用 ggplot 进行绘图。在绘制 pipe/chain 命令之前,如果我只是将 data.table / dtplyr 对象转换为 tibble 那么它可以与 ggplot 但这比完全使用 data.frame/tibble 需要更多的时间,这将在本文后面显示。
library(tidyverse)
library(dtplyr)
library(data.table)
library(scale)
library(lubridate)
library(bench)
我的代码尝试次数和时间基准:
数据:
data.frame 对象
df_ind_stacked_daily <- read.csv(url("https://raw.githubusercontent.com/johnsnow09/covid19-df_stack-code/main/df_ind_stacked_daily.csv")) %>%
mutate(Date = ymd(Date))
data.table 对象
df_ind_stacked_daily2 <- setDT(df_ind_stacked_daily)
使用 data.table/dtplyr 对象绘图:
df_ind_stacked_daily2 %>%
filter(Daily_cases_type == "Daily_confirmed",
Date >= max(Date) - 6 & Date <= max(Date),
State.UnionTerritory != "India"
) %>%
group_by( Date) %>%
slice_max(order_by = Daily_cases_counts, n = 10) %>%
ungroup() %>%
# as.tibble() %>%
ggplot(aes(x = Daily_cases_counts,
y = reorder_within(State.UnionTerritory,
by = Daily_cases_counts, within = Date),
fill = State.UnionTerritory)) +
geom_col(show.legend = FALSE) +
facet_wrap(~Date, scales = "free_y") +
geom_text(aes(label = Daily_cases_counts), size=3, color="white",
# position = "dodge",
hjust = 1.2) +
# theme_minimal() +
theme(legend.position = "none") +
scale_x_continuous(labels = comma) + # unit_format(scale = 1e-3, unit = "k")
scale_fill_tableau(palette = "Tableau 20") +
scale_y_reordered() +
coord_cartesian(clip = "off")
错误:data 必须是数据框,或由fortify() 强制的其他对象,而不是具有类 dtplyr_step_group/dtplyr_step 的 S3 对象。
P.S - 如果我在上面的代码块中取消注释 as.tibble(),那么 ggplot 可以工作。
代码时间基准:
- data.table/dtplyr 对象而不转换为 tibble
library(bench)
bench::mark(
df_ind_stacked_daily2 %>%
filter(Daily_cases_type == "Daily_confirmed",
Date >= max(Date) - 6 & Date <= max(Date),
State.UnionTerritory != "India"
) %>%
group_by( Date) %>%
slice_max(order_by = Daily_cases_counts, n = 10) %>%
ungroup()
# as.tibble() %>%
)
expression min median itr/sec
<S3: bench_expr> 2.45ms 2.75ms 320.3396
- 转换为 tibble 后的 data.table/dtplyr 对象
library(bench)
bench::mark(
df_ind_stacked_daily2 %>%
filter(Daily_cases_type == "Daily_confirmed",
Date >= max(Date) - 6 & Date <= max(Date),
State.UnionTerritory != "India"
) %>%
group_by( Date) %>%
slice_max(order_by = Daily_cases_counts, n = 10) %>%
ungroup() %>%
as.tibble()
)
expression min median itr/sec
<S3: bench_expr> 12.7ms 14ms 65.41098
- data.frame 或 tibble 对象
library(bench)
bench::mark(
df_ind_stacked_daily %>%
filter(Daily_cases_type == "Daily_confirmed",
Date >= max(Date) - 6 & Date <= max(Date),
State.UnionTerritory != "India"
) %>%
group_by( Date) %>%
slice_max(order_by = Daily_cases_counts, n = 10) %>%
ungroup()
)
expression min median itr/sec
<S3: bench_expr> 6.71ms 7.97ms 120.3636
问题:那么我怎样才能使 ggplot 与 data.table / dtplyr 一起工作而不将其转换为 data.frame /小标题 ??
############################
(更新:对答案的回应)
感谢@teunbrand,我主要使用下面的代码并添加了另一个功能,并将其用于 3 个场景:
我创建了两个函数:(1) 执行处理并且不对 tibble 进行强制,(2) 在处理后将其强制为 tibble。
我总共在 3 个场景中运行这些 - (1) data.table,(2) data.table 在处理后转换为 tibble,(3 ) 从头开始使用 tibble
# 1. function doesn't convert to tibble
fun <- function(x) {
x %>%
filter(Daily_cases_type == "Daily_confirmed",
Date >= max(Date) - 6 & Date <= max(Date),
State.UnionTerritory != "India"
) %>%
group_by( Date) %>%
slice_max(order_by = Daily_cases_counts, n = 10) %>%
ungroup() #%>%
# as_tibble() # Always coerce to tibble
}
# 2. function convert it to tibble after all processing
fun_to_tbl <- function(x) {
x %>%
filter(Daily_cases_type == "Daily_confirmed",
Date >= max(Date) - 6 & Date <= max(Date),
State.UnionTerritory != "India"
) %>%
group_by( Date) %>%
slice_max(order_by = Daily_cases_counts, n = 10) %>%
ungroup() %>%
as_tibble() # Always coerce to tibble
}
# Make data larger
dt <- do.call(rbind, rep(list(as.data.table(df_ind_stacked_daily)), 20))
tbl_df <- do.call(rbind, rep(list(as_tibble(df_ind_stacked_daily)), 20))
# Run data.table on single thread
setDTthreads(1)
由于未知原因,我的基准测试没有同时运行,所以我不得不一个接一个地运行它们。
(bm <- bench::mark(
dt_res = fun(dt), # bench dt
min_iterations = 20
))
expression min median itr/sec mem_alloc
<S3: bench_expr> 4.35ms 6.05ms 148.1923 5.12KB
(bm <- bench::mark(
dt_to_tbl_res = fun_to_tbl(dt), # bench dt converted to tibble at end
min_iterations = 20
))
expression min median itr/sec mem_alloc
<S3: bench_expr> 65.8ms 72.2ms 12.28566 47.6MB
(bm <- bench::mark(
tbl_res = fun(tbl_df), # bench tbl
min_iterations = 20
))
expression min median itr/sec mem_alloc
<S3: bench_expr> 55ms 67.8ms 13.70603 47.4MB
目标:我的主要目标是将其整合到具有动态变量选择的闪亮应用中,因此想用对其进行优化数据表。 但我想 ggplot 无法使用 s3 objects / data.table。
我得到的唯一时差是当我使用 data.table 并将其作为 data.table 传递时,否则没有任何好处。
【问题讨论】:
标签: r ggplot2 data.table dtplyr