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)
。 - Rickarddf
进行排序,以便.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)
,第二个情况中的正值表示它们被字面上存储为整数向量。 - Martin Morganrow.names() = NULL
设置为null会显著增加执行时间。此外,我猜想,由于每个df$x
包含少量元素,因此为每个组连续填充索引(在内部拆分中)不应该有太大的影响。 - alexis_laz