r - 拆分-应用-合并聚合:应用的函数是否可以接受作为原始数据的指定变量的多个参数?



一些上下文:在我寻求改进我的R代码的过程中,我试图尽可能地用R的应用类函数替换我的for循环。

问题:R的应用函数(如sapply,tapply,aggregate等)对于应用更复杂的函数是否有用,因为它们将原始数据的指定变量作为参数?

什么有效和什么无效的简单示例:我有一个数据帧,其中包含一个时间变量 date.time 和两个数值变量 val.one 和 value.two:

生成数据:

df <- data.frame(date.time = seq(ymd_hms("2000-01-01 00:00:00"),ymd_hms("2000-01-03 00:00:00"), length.out=100),value.one = c(1:100), value.two = c(1:100) + 10)

我想对数据帧的每 10 小时切割应用一个函数,该函数的两个参数是数据帧的两个数值变量。例如,如果我想计算每 10 小时切割的两个值中每个值的平均值,解决方案如下:

一个函数,用于计算 10 小时内每个时间段的值 .1 和值 .2 的平均值:

work_on_subsets <- function(data, time.step = "10 hours"){
aggregate(data[,-1], list(cut(df$date.time, breaks = time.step)), function(x) mean(x))}

但是,如果我想分别使用两个数据值来运行另一个函数,比如计算两个平均值的 som,我就会遇到麻烦。函数work_on_subsets_2给了我以下错误:x$value.one 中的错误:$ 运算符对原子向量无效

计算每 10 小时时间段的值 1 和 value.2 均值之和的函数:

work_on_subsets_2 <- function(data, time.step = "10 hours"){
aggregate(data, list(cut(df$date.time, breaks = time.step)), function(x) mean(x$value.one) + mean(x$value.two)}

在极限下,我希望能够做这样的事情:

一个函数,在 10 小时的每个时间段内对 value.one 和 value.two 运行another_function:

another_function <- function(a,b) {
# do something with a and b
}
work_on_subsets_3 <- function(data, time.step = "10 hours"){aggregate(data, list(cut(df$date.time, breaks = time.step)), another_function(x$value.one, x$value.two))}

我是否为这项工作使用了错误的工具?我已经有一个使用 for 循环的工作解决方案,但我正在尝试掌握拆分-应用-组合策略。如果是这样,是否有任何可行的 for 循环替代方案?

嗨,你在这里做错了一些基本的事情。您正在创建一个函数,该函数data作为其 data.frame,但仍从全局环境中引用df。您还缺少至少一个括号。而且我不太清楚为什么你嵌入了两层功能。

我的解决方案与您的方法不同,但希望会有所帮助。当您想要拆分数据帧并应用函数时,我建议您使用plyr包,因为我发现它更直观。在我看来,将其与dplyr相结合也有帮助。注意:请务必在dplyr之前加载plyr,否则会遇到依赖项问题。

如果我正确理解您的问题,下面应该可以工作,您可以创建不同的函数来应用

library(plyr)
library(dplyr)
#create function you want to apply
MeanFun <- function(data) mean(data[["value.one"]]) + mean(data[["value.two"]])
#add grouping variable to your dataframe. You can link this with pipes (%>%)
# if you don't want to create a new data.frame, but for testing purposes it 
# more clearly shows wants happening 
df1 <- df %>% mutate(Breaks = cut(date.time, breaks = time.step)) 
# use plyr's ssply to split the dataframe on "Breaks" column and apply the function
out <- ddply(df1, "Breaks", MeanFun)

最新更新