【发布时间】:2021-07-08 15:41:38
【问题描述】:
我正在尝试找到在 R 中使用 for 循环(或 purrrr 中的映射)生成表格的最快和最有效的方法。
我有 15,881 个值要循环,在本例中假设这些值是数字 1 到 15,881 加 1,即这个变量:
values <- c(1:15881)
然后我尝试过滤列与值匹配的现有数据帧,然后执行一些数据清理过程 - 此单个数据帧的输出,为清楚起见,我的过程如下:
假设在这种情况下,我从值对象中选择了一个值,例如value = values[1]
那么对于单个值,我有以下内容:
df <- df_to_filter %>%
filter(code == value) %>%
group_by(code, country) %>%
group_split() %>%
purrr::map_dfr(some_other_function) %>%
filter(!is.na(country))
当我为单个值运行上面的代码时,它工作得非常好。输出是所需的数据帧。对于单个值,此过程大约需要 0.7 秒。
但是,我正在尝试将此输出的结果附加到变量 values
中找到的每个单个值的空数据框中到目前为止,我已经尝试了以下方法:
For 循环方法
# empty dataframe to append values to
empty_df <- tibble()
for (value in values){
df <- df_to_filter %>%
filter(code == value) %>%
group_by(code, country) %>%
group_split() %>%
purrr::map_dfr(some_other_function) %>%
filter(!is.na(country))
empty_df <- bind_rows(empty_df, df)
}
但是上面的速度非常慢 - 我做了一个快速计算,大约需要 186 分钟 ((0.7 seconds per table x 15,881)/60 - seconds in a minute = around 185.7 minutes) - 这对于处理一个数据帧来说是一个巨大的时间。
有没有比 for 循环更快的方法来加快上述过程?我想不出任何方法来改进上述代码的基础,因为它可以很好地完成工作,并且 0.7 秒生成一个表对我来说似乎很快,但 15,881 个表显然需要很长时间。
我尝试将purrr 包与data.table 一起使用,但我得到的最远的是:
combine_dfs <- function(value){
df <- df_to_filter %>%
filter(code == value) %>%
group_by(code, country) %>%
group_split() %>%
purrr::map_dfr(some_other_function) %>%
filter(!is.na(country))
df <- data.table(df)
rbindlist(list(df, empty_df))
}
然后用map_df 运行是这样的:
map_df(values, ~combine_dfs(.))
但是,即使是上述方法也非常缓慢,而且似乎需要大约相同的时间!
感谢任何帮助!
【问题讨论】:
-
如果您可以共享现有数据帧的可重现部分会更好。
-
您确实需要首先提供一个可重现的示例。否则我们无法提供完整的解决方案,也无法与您想要的结果进行比较。
-
你能在你的答案中添加一些数据吗?
-
在
for循环中rbind 帧表的最快方法是... 不要。这打破了R Inferno 的第二个圆圈,标题为“Growing Objects”。意识到每次执行此操作时,在创建新对象之前,数据都会在内存中完美复制,而旧对象会被垃圾收集(最终)。这意味着如果您有 1M 行并且想要rbind再添加 10 行,那么您将在某个时间点在内存中拥有 2M+ 行。 不要这样做。
标签: r dataframe dplyr data.table tidyverse