【发布时间】:2017-01-25 12:05:48
【问题描述】:
df %>% split(.$x)
对于 x 的大量唯一值变得缓慢。如果我们改为手动将数据帧拆分为更小的子集,然后对每个子集执行拆分,我们将时间减少至少一个数量级。
library(dplyr)
library(microbenchmark)
library(caret)
library(purrr)
N <- 10^6
groups <- 10^5
df <- data.frame(x = sample(1:groups, N, replace = TRUE),
y = sample(letters, N, replace = TRUE))
ids <- df$x %>% unique
folds10 <- createFolds(ids, 10)
folds100 <- createFolds(ids, 100)
运行microbenchmark 给了我们
## Unit: seconds
## expr mean
l1 <- df %>% split(.$x) # 242.11805
l2 <- lapply(folds10, function(id) df %>%
filter(x %in% id) %>% split(.$x)) %>% flatten # 50.45156
l3 <- lapply(folds100, function(id) df %>%
filter(x %in% id) %>% split(.$x)) %>% flatten # 12.83866
split 不是为大型团体设计的吗?除了手动初始子集,还有其他选择吗?
我的笔记本电脑是 2013 年末的 macbook pro,2.4GHz 8GB
【问题讨论】:
-
我想并行处理生成的列表项,即
list_of_dataframes %>% map(sequentially_process_each_row_of_df) -
还要考虑,
orderingdf在splitting 之前,这样.Internal(split())会更连续地访问内存 --system.time({ a = split(df, df$x) }); system.time({ odf = df[order(df$x), ]; b = split(odf, odf$x) }); identical(a, b) -
@alexis_laz 实际上,排序会创建行名,而不是改善内存访问模式——比较
.row_names_info(df)和.row_names_info(df[order(df$x),]);第一种情况下的负值表示行名紧凑地存储为c(NA, 1000000),第二种情况下的正值表示它们按字面意思存储为整数向量。 -
@MartinMorgan:你说得对——我完全错过了,谢谢。设置
row.names() = NULL会显着增加执行时间。此外,我猜,因为每个df$x包含少量元素,连续填充每个组的索引(在内部拆分中)不应该产生这种差异。
标签: r performance purrr