【问题标题】:Aggregating mean "%H%M" in "week" bins in R在 R 中的“周”箱中聚合平均“%H%M”
【发布时间】:2012-07-17 14:36:55
【问题描述】:

我已经为此苦苦挣扎了一段时间。我是使用 ts 数据和所有相关 R 包的新手。 我有一个带有几个变量的df,包括格林威治标准时间“%H%M”中的“一天中的时间”和发生采样的日期“%Y/%m/%e”。我想将我的日期数据分箱/聚合为“周”(即 %W/%g),并计算在该周发生采样时的平均“一天中的时间”。

我能够通过首先将我的 df 转换为 zoo 对象然后使用如下所示的 aggregate.zoo 命令来计算数值变量(例如重量)的其他 FUN:

#calculate the sum weight captured every week 
x2c <- aggregate(OA_zoo, as.Date(cut(time(OA_zoo), "week")), sum)

但是,我不确定如何解决我正在使用 日期格式 而不是 num 的事实,并且希望有任何提示! 此外,我显然已经通过分别处理我的每个变量来编码。是否有一种方法可以通过使用 plyr 聚合“每周”在我的 df 上应用不同的 FUN(总和/平均值/最大值/最小值)?还是其他一些包?

编辑/澄清 这是我的完整数据集样本的dput 输出。我有 2004-2011 年的数据。我想使用 ggplot2 查看/绘制的是 TIME 的平均值/中位数(%H%M),在几周内随时间(2004-2011)聚合。目前,我的数据不是按周汇总的,而是每天汇总的(随机样本)。

> dput(godin)
structure(list(depth = c(878, 1200, 1170, 936, 942, 964, 951, 
953, 911, 969, 960, 987, 991, 997, 1024, 978, 1024, 951, 984, 
931, 1006, 929, 973, 986, 935, 989, 1042, 1015, 914, 984), duration = c(0.8, 
2.6, 6.5, 3.2, 4.1, 6.4, 7.2, 5.3, 7.4, 7, 7, 5.5, 7.5, 7.3, 
7.5, 7, 4.2, 3, 5, 5, 9.3, 7.9, 7.3, 7.2, 7, 5.2, 8, 6, 7.5, 
7), Greenland = c(0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 40L, 28L, 0L, 
0L, 34L, 7L, 28L, 0L, 0L, 0L, 27L, 0L, 0L, 0L, 44L, 59L, 0L, 
0L, 0L, 0L, 0L, 0L), date2 = structure(c(12617, 12627, 12631, 
12996, 12669, 13036, 12669, 13036, 12670, 13036, 12670, 13037, 
12671, 13037, 12671, 13037, 12671, 13038, 12672, 13038, 12672, 
13038, 12672, 13039, 12631, 12997, 12673, 13039, 12673, 13039
), class = "Date"), TIME = c("0940", "0145", "0945", "2045", 
"1615", "0310", "2130", "1045", "0625", "1830", "1520", "0630", 
"0035", "1330", "0930", "2215", "2010", "0645", "0155", "1205", 
"0815", "1845", "2115", "0350", "1745", "0410", "0550", "1345", 
"1515", "2115")), .Names = c("depth", "duration", "Greenland", 
"date2", "TIME"), class = "data.frame", row.names = c("6761", 
"9019", "9020", "9021", "9022", "9023", "9024", "9025", "9026", 
"9027", "9028", "9029", "9030", "9031", "9032", "9033", "9034", 
"9035", "9036", "9037", "9038", "9039", "9040", "9041", "9042", 
"9043", "9044", "9045", "9046", "9047"))

【问题讨论】:

  • 我不清楚这个问题。是计算时间平均值(而不是数字)还是按周聚合有问题?
  • 您确实需要提供reproducible example 以供任何人提供帮助。
  • 您如何获取一天中某个时间的平均值?你不会做中位数或众数吗?

标签: r aggregate-functions aggregate time-series


【解决方案1】:

我会这样处理: 首先用一个代表星期的字符串创建一个列:

godin$week <- format(godin$date2, "%Y-W%U")

这会给你类似"2004-W26" 的东西,这对于aggregate 来说已经足够了。

那么您需要将表示 HHMM 的字符向量转换为实际时间,以便您可以在其上使用时间数学。

godin$time2 <- as.POSIXct(strptime(godin$TIME, "%H%M"))

注意:以上内容有点小技巧...strptime() 如果未指定任何日期,则假定为当前日期,但这不应妨碍此特定应用程序,因为所有转换后的时间都相同日期,平均值的时间部分将是正确的。我稍后会删除日期...

到那时,我认为你可以简单地聚合:

x2c <- aggregate(time2~week, data=godin, FUN=mean)

并摆脱不相关(和错误)的日期部分

x2c$time2 <- format(x2c$time2,"%H:%M:%S")

瞧瞧。

> x2c
      week    time2
1 2004-W29 09:40:00
2 2004-W30 01:45:00
3 2004-W31 13:45:00
4 2004-W36 12:07:00
5 2004-W37 10:32:30
6 2005-W31 12:27:30
7 2005-W36 10:48:20
8 2005-W37 13:11:06

这里的教训是,在 R 中在没有相关日期的情况下推动时间是很棘手的。我很想听听其他有更好方法的人的意见。

【讨论】:

  • @JoshuaUlrich:呸。你是对的。如何转换没有日期的时间?
  • 改用strptime() 编辑。仍然有点破解,请参阅答案,如果可以的话,请提供帮助,谢谢!
  • strptime 返回POSIXlt 这是一个列表,所以这是行不通的。将as.POSIXct 包裹起来至少可以避免错误,但我认为结果没有意义。
  • @GSee:谢谢!我在测试时发现了这一点。由于特定的应用程序,结果的“废话”日期部分不会妨碍。我新编辑的回复已经过测试并且可以正常工作......终于!
【解决方案2】:

您需要将TIME 列转换为常用单位(即分钟)。这里有几个辅助函数可以做到这一点:

hour2min <- function(hhmm) {
  hhmm <- as.numeric(hhmm)
  trunc(hhmm/100)*60 + hhmm %% 100
}
min2hour <- function(min) {
  min <- as.numeric(min)
  trunc(min/60)*100 + min %% 60
}

然后,您可以根据需要汇总分钟数。我会亲自将它们放在 xts 对象中并使用 apply.weekly:

library(xts)
x <- xts(hour2min(godin$TIME), as.Date(godin$date2), dimnames=list(NULL,"MINS"))
w <- apply.weekly(x, mean)
w$TIME <- min2hour(w$MINS)
#                MINS     TIME
# 2004-07-18 580.0000  940.000
# 2004-08-01 585.0000  945.000
# 2004-09-12 711.2500 1151.250
# 2005-08-02 747.5000 1227.500
# 2005-09-11 746.6667 1226.667
# 2005-09-13 764.1667 1244.167

秒数仍为 100 分之一分钟,但可以更改...

【讨论】:

  • 感谢您的回答@Joshua Ulrich,但这并不是我想要的。请参阅下面的答案。
【解决方案3】:

如果您想要每周所有观察时间的平均值,并且您希望日期很重要(即今天 19:00 和明天 19:00 平均到明天早上 07:00),那么您可以这样做

godin$datetime <- as.POSIXct(paste(godin$date2, godin$TIME), format="%Y-%m-%d %H%M")
aggregate(godin$datetime, list(format(godin$datetime, "%W/%g")), mean)

#  Group.1                   x
#1   28/04 2004-07-18 09:40:00
#2   30/04 2004-07-31 01:45:00
#3   31/05 2005-08-02 00:27:30
#4   36/04 2004-09-10 13:51:15
#5   36/05 2005-09-11 00:26:40
#6   37/05 2005-09-13 00:44:10

但是,我认为您想要平均时间,并且您不关心日期(除了确定它是哪一周)。在这种情况下,您可以使用任意日期作为锚点,并将所有时间视为发生在该日期。

godin$stime <- as.POSIXct(paste("1970-01-01", godin$TIME), format='%Y-%m-%d %H%M')
aggregate(godin$stime, list(format(godin$datetime, "%W/%g")), mean)

#  Group.1                   x
#1   28/04 1970-01-01 09:40:00
#2   30/04 1970-01-01 09:45:00
#3   31/05 1970-01-01 12:27:30
#4   36/04 1970-01-01 11:51:15
#5   36/05 1970-01-01 12:26:40
#6   37/05 1970-01-01 12:44:10

编辑

上述输出与@JoshuaUlrich 提供的输出之间的区别在于,他的输出是按周排序的。如果我对它们进行排序,它就像 Joshua 的,但用秒而不是 100 分之一分钟。 (不过,由于您选择了 format 规范,因此以相同的方式对它们进行排序有点棘手。)

out <- aggregate(godin$stime, list(format(godin$datetime, "%W/%g")), mean)
out[order(as.numeric(paste0(substr(out[, 1], 4, 5), substr(out[, 1], 1, 2)))), ]
#  Group.1                   x
#1   28/04 1970-01-01 09:40:00
#2   30/04 1970-01-01 09:45:00
#4   36/04 1970-01-01 11:51:15
#3   31/05 1970-01-01 12:27:30
#5   36/05 1970-01-01 12:26:40
#6   37/05 1970-01-01 12:44:10

编辑 2

如果您只想返回格式为%H%M 的字符串,您可以在aggregate 中使用format

out <- aggregate(godin$stime, list(format(godin$datetime, "%W/%g")), function(TIME) format(mean(TIME), "%H%M"))
out[order(as.numeric(paste0(substr(out[, 1], 4, 5), substr(out[, 1], 1, 2)))), ]
#  Group.1    x
#1   28/04 0940
#2   30/04 0945
#4   36/04 1151
#3   31/05 1227
#5   36/05 1226
#6   37/05 1244

【讨论】:

  • @GodinA,不要让我的基本 R 答案欺骗了你;如果我亲自这样做,我会在做任何事情之前将我的数据转换为xts
  • 很想知道,为什么您的结果与@mac 不同?
  • 因为我像你问的那样使用了%W/%g ;-)。请注意,例如,@mac 将 2004-07-28 视为与 2004-08-01 不同的一周
  • 如果您在@mac 的回答中将godin$week &lt;- format(godin$date2, "%Y-W%U") 替换为godin$week &lt;- format(godin$date2, "%W/%g"),我们的结果匹配
猜你喜欢
  • 2015-10-21
  • 2021-08-12
  • 1970-01-01
  • 2011-05-17
  • 2021-08-31
  • 2021-04-03
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多