6

我想按时间间隔聚合数据框,对每一列应用不同的函数。我想我几乎已经aggregate失败了,并且已经将我的数据分成了chron包的间隔,这很容易。

但我不确定如何处理子集。所有的映射函数 , 都*apply采用*ply一个函数(我希望能够采用函数向量来应用每列或变量,但没有找到)所以我正在编写一个函数来获取我的数据帧子集,并给我所有变量的平均值,除了“时间”,它是索引,和“径流”,它应该是总和。

我试过这个:

aggregate(d., list(Time=trunc(d.$time, "00:10:00")), function (dat) with(dat, 
list(Time=time[1], mean(Port.1), mean(Port.1.1), mean(Port.2), mean(Port.2.1), 
mean(Port.3), mean(Port.3.1), mean(Port.4), mean(Port.4.1), Runoff=sum(Port.5))))

即使它没有给我这个错误,这也会很丑陋:

Error in eval(substitute(expr), data, enclos = parent.frame()) : 
  not that many frames on the stack

这告诉我我真的做错了什么。根据我对 RI 的了解,我认为必须有一种优雅的方式来做到这一点,但它是什么?

输入:

d. <- structure(list(time = structure(c(15030.5520833333, 15030.5555555556, 
15030.5590277778, 15030.5625, 15030.5659722222), format = structure(c("m/d/y", 
"h:m:s"), .Names = c("dates", "times")), origin = structure(c(1, 
1, 1970), .Names = c("month", "day", "year")), class = c("chron", 
"dates", "times")), Port.1 = c(0.359747, 0.418139, 0.417459, 
0.418139, 0.417459), Port.1.1 = c(1.3, 11.8, 11.9, 12, 12.1), 
    Port.2 = c(0.288837, 0.335544, 0.335544, 0.335544, 0.335544
    ), Port.2.1 = c(2.3, 13, 13.2, 13.3, 13.4), Port.3 = c(0.253942, 
    0.358257, 0.358257, 0.358257, 0.359002), Port.3.1 = c(2, 
    12.6, 12.7, 12.9, 13.1), Port.4 = c(0.352269, 0.410609, 0.410609, 
    0.410609, 0.410609), Port.4.1 = c(5.9, 17.5, 17.6, 17.7, 
    17.9), Port.5 = c(0L, 0L, 0L, 0L, 0L)), .Names = c("time", 
"Port.1", "Port.1.1", "Port.2", "Port.2.1", "Port.3", "Port.3.1", 
"Port.4", "Port.4.1", "Port.5"), row.names = c(NA, 5L), class = "data.frame")
4

4 回答 4

8

你的方法有很多问题。一般的建议是不要直接按照您认为的最终语句应该是什么样子,而是以增量方式工作,否则会使调试(理解和修复错误)变得非常困难。

例如,您可以从以下内容开始:

aggregate(d., list(Time=trunc(d.$time, "00:10:00")), identity)

注意到您的拆分变量有问题。显然aggregate不喜欢使用此类数据。Time您可以通过转换为数字来解决此问题:

aggregate(d., list(Time=as.numeric(trunc(d.$time, "00:10:00"))), identity)

那你可以试试

aggregate(d., list(Time=as.numeric(trunc(d.$time, "00:10:00"))), apply.fun)

apply.fun您的用户定义函数在哪里。这失败了一个相当严厉的消息,但正在运行

aggregate(d., list(Time=as.numeric(trunc(d.$time, "00:10:00"))), print)

有助于实现FUN内部函数aggregate不会为每个数据块调用一次(并传递一个 data.frame),而是为数据块的每一列调用一次(并传递一个未命名的向量),因此您无法得到你想要使用的结果aggregate

相反,您可以使用包中的ddply函数plyr。在那里,应用于每个部分的函数确实会收到一个 data.frame,因此您可以执行以下操作:

apply.fun <- function(dat) with(dat, data.frame(Time=time[1],
                                                mean(Port.1),
                                                mean(Port.1.1),
                                                mean(Port.2),
                                                mean(Port.2.1),
                                                mean(Port.3),
                                                mean(Port.3.1),
                                                mean(Port.4),
                                                mean(Port.4.1),
                                                Runoff=sum(Port.5)))

d.$Time <- as.numeric(trunc(d.$time, "00:10:00"))
library(plyr)
ddply(d., "Time", apply.fun)

#            Time mean.Port.1. mean.Port.1.1. mean.Port.2. mean.Port.2.1.
# 1 15030.5520833    0.4061886           9.82    0.3262026          11.04
#   mean.Port.3. mean.Port.3.1. mean.Port.4. mean.Port.4.1. Runoff
# 1     0.337543          10.66     0.398941          15.32      0

编辑:在下面的第一条评论中跟进@roysc 问题,您可以执行以下操作:

apply.fun <- function(dat) {
  out <- as.data.frame(lapply(dat, mean))
  out$Time <- dat$time[1]
  out$Runoff <- sum(dat$Port.5)
  return(out)
}
于 2012-07-22T18:32:58.097 回答
5

使用by而不是aggregate.

Iff与您的匿名函数相同,只是其中list的内容被替换为data.framef <- function(dat) with(dat, data.frame(...whatever...))然后:

d.by <- by(d., list(Time = trunc(d.$time, "00:10:00")), f)
d.rbind <- do.call("rbind", d.by) # bind rows together

# fix up row and column names
rownames(d.rbind) <- NULL
colnames(d.rbind) <- colnames(d.)

f如果添加名称本身而不是仅添加名称,我们可以删除最后一个分配列名称的语句Time

于 2012-07-22T18:36:35.280 回答
1

这个怎么样?

library(plyr)
ddply(d., .(time), colMeans)
于 2012-07-22T18:30:51.943 回答
1

另一种选择是使用一系列步骤,通过交替运行 aggregate() 然后使用 merge() 在基础 R 中完成相同的任务,如下所示:

agMeans_df <- aggregate(cbind(Port.1,Port1.1,Port.2,Port.2.2,Port.3,Port.3.1,Port.4,Port4.1)~timevar,data=d,mean)
agSum_df <- aggregate(Port.5~timevar,data=d,sum)
ag_all_df <- merge(agMeans_df,agSum_df,by="timevar")

我忽略了其他回复中提出的问题,即组向量需要属于正确的类(此处为“timevar”),并且列的顺序可能会更改。如果您想在同一列上运行多个不同的函数以避免混淆具有相同名称的两个聚合列,则还需要在 merge() 之前进行一些重命名。

于 2018-09-14T22:08:56.583 回答