【发布时间】:2016-05-05 23:53:34
【问题描述】:
我们有一个非常大的数据框df,可以按因素拆分。在此拆分创建的数据帧的每个子集上,我们需要执行一个操作以增加该子集的行数,直到达到某个length。之后,我们rbind 的子集得到更大版本的df。
有没有办法在不使用内部函数的情况下快速做到这一点?
假设我们的子集操作(在单独的 .R 文件中)是:
foo <- function(df) { magic }
我们想出了几种方法:
1)
df <- split(df, factor)
df <- lapply(df, foo)
rbindlist(df)
2)
assign('list.df', list(), envir=.GlobalEnv)
assign('i', 1, envir=.GlobalEnv)
dplyr::group_by(df, factor)
dplyr::mutate(df, foo.list(df.col))
df <- rbindlist(list.df)
rm('list.df', envir=.GlobalEnv)
rm('i', envir=.GlobalEnv)
(In a separate file)
foo.list <- function(df.cols) {
magic;
list.df[[i]] <<- magic.df
i <<- i + 1
return(dummy)
}
第一种方法的问题是时间。 lapply 需要很长时间才能真正令人满意(使用我们的数据集大约需要一个小时)。
第二种方法的问题是非常篡改用户全局环境的不良副作用。它明显更快,但如果可以的话,我们宁愿避免这样做。
我们还尝试传入列表和计数变量,然后尝试使用父环境中的变量substitute 它们(一种解决 R 缺乏传递引用的技巧)。
我们查看了一些可能相关的 SO 问题(R applying a function to a subset of a data frame、Calculations on subsets of a data frame、R: Pass by reference 等),但没有一个问题能很好地解决我们的问题。
如果您想运行代码,可以复制和粘贴以下内容:
x <- runif(n=10, min=0, max=3)
y <- sample(x=10, replace=FALSE)
factors <- runif(n=10, min=0, max=2)
factors <- floor(factors)
df <- data.frame(factors, x, y)
## We group by factor, then run foo on the groups.
foo <- function(df.subset) {
min <- min(df.subset$y)
max <- max(df.subset$y)
## We fill out df.subset to have everything between the min and
## max values of y. Then we assign the old values of df.subset
## to the corresponding spots.
df.fill <- data.frame(x=rep(0, max-min+1),
y=min:max,
factors=rep(df.subset$factors[1], max-min+1))
df.fill$x[which(df.subset$y %in%(min:max))] <- df.subset$x
df.fill
}
【问题讨论】:
-
您可能需要查看
expand.grid以填写所有值。 -
@Henrik,感谢您的建议!我会做相应的调整。
-
对于expand.grid,我们肯定考虑过。但是,我们很难让它与分组一起工作。由于每个组都有不同的最小值和最大值,我们需要将其填充到。
-
@Henrik,抱歉不清楚。 Foo(我们相信)尽可能快。我们主要关心的只是将 foo 应用于
df的子组,然后重新聚合。不过谢谢!我已经根据你的 cmets 改进了这个问题。