【问题标题】:Time aggregate across years in RR中跨年份的时间汇总
【发布时间】:2020-06-03 01:31:09
【问题描述】:

我有 10 年的每日降水数据。我正在尝试获取例如在次年 12 月和 4 月之间发生的总降水量。 另一个复杂因素是,时间段可能会发生变化,例如 12 月 15 日至 3 月 15 日

我知道如何使用aggregategroup_by 来做到这一点,如果我不必经历多年。但是我完全不知道如何解决今年的交叉问题。

这是我想要得到的代码示例。

library(lubridate)

precip <- data.frame(d = seq.Date(from = as.Date('2001-01-01'),
                                  to = as.Date('2004-12-31'),
                                  by = 'day'),
                     prec = runif(1461))

precip$y <- year(precip$d)
precip$m <- month(precip$d)

# I can aggregate by year
aggregate(precip$prec, by = list(precip$y), sum)

# I can aggregate by year, month
aggregate(precip$prec, by = list(precip$y, precip$m), sum)

# How can I aggregate by a period that crosses between years?
# my desired output would be something like
# Group.1        x
# 1 2001-12-15 to 2002-03-15 184.4885
# 2 2002-12-15 to 2003-03-15 192.8315
# 3 2003-12-15 to 2004-03-15 178.8507

我不需要组名将句点作为字符串包含。它可能只是一个索引。

【问题讨论】:

  • 如果您将此问题具体化而不是笼统地提出来,会更容易提供帮助。包括示例数据并显示它的预期输出。
  • 回声罗纳克。你的 data.frame 是什么样的?简单的索引不起作用吗?
  • 添加了代码示例

标签: r aggregate


【解决方案1】:

该问题后来被更新为询问不是整月的季节,因此这是对原始答案的更新以解决该问题。它使用结束时注释中的输入以及原型季节的开始日期和结束日期。如果季节跨越 2 月底,请务必选择闰年(例如 2000 年,如下例所示)。

我们创建一个从开始日期到结束日期的所有日期序列,称为模板。将其转换为季节中所有可能的月/日的字符向量,mmdd。

接下来定义 in_season ,其中每行 precip 有一个元素,如果该行的月份和日期与模板中的任何月份和日期匹配,则为 TRUE。

然后定义 season_no ,其中每行 precip 有一个元素,用唯一的数字标识每个季节。对于日期不在季节的行,该数字为 0,否则为递增的正数。

将数据子集到季节行,并计算每个季节中的最小和最大日期,给出 precip0。

最后按开始/结束日期聚合 prec,并使用聚合来查找每个季节的天数。这将包括部分季节(如果存在)。如果不希望首先对数据进行子集化,或者在代码中注释掉的行中对结果进行子集化。

没有使用任何包。

# to change definition of season change next 2 lines
start_template <- as.Date("1999-12-15")
end_template <- as.Date("2000-03-15")  # note that year 2000 incl Feb 29

# mmdd character vector contains the mm-dd values in season
template <- seq(start_template, end_template, "day")
mmdd <- format(template, "%m-%d")

in_season <- format(precip$d, "%m-%d") %in% mmdd
season_no <- with(rle(in_season), rep(seq_along(lengths), lengths)) * in_season

precip0 <- transform(subset(cbind(precip, season_no), in_season),
  start_date = ave(d, season_no, FUN = min),
  end_date = ave(d, season_no, FUN = max))

ag <- aggregate(cbind(days = 1, prec) ~ start_date + end_date, precip0, sum)

# uncomment if partial seasons not wanted
# ag <- subset(ag, days >= length(mmdd) - 1)  

给予:

> ag
  start_date   end_date days      prec
2 2001-01-01 2001-03-15   74 37.963828
3 2001-12-15 2002-03-15   91 44.543114
4 2002-12-15 2003-03-15   91 43.182177
5 2003-12-15 2004-03-15   92 44.083236
1 2004-12-15 2004-12-31   17  9.180353

原始答案假设整月

输入是 precip(在末尾的注释中给出,并且季节是月份数字的向量(Jan=1,Feb=2,...,Dec=12),以便它们出现在季节内。在下面的示例中,我们使用 c(12, 1:3),即 Dec - Mar。

下面的代码使用 precip 和 season 来设置以下变量:

  • last_month 是本季最后一个月的月份数
  • ym 是具有相应年/月的 yearmon 类向量。在内部,它表示为年份加 0 表示 1 月,1/12 表示 2 月,...,11/12 表示 12 月。ym 与 x 的长度相同。
  • cross 是一个逻辑标量,如果季节跨越一年边界,则为 TRUE,否则为 FALSE
  • 如果相应的日期在季节内,则 in_season 为 TRUE。 in_season 的长度与 x 相同。
  • start_year 和 end_year 是季节开始和结束的对应年份,如果日期是季节,则为 0,如果不是季节。 start_year 和 end_year 的长度都与 x 相同。
  • start_date 和 end_date 是对应的季节开始和结束日期

然后,我们将 start_year 和 end_year 以及子集插入到季节为 TRUE 的那些行中。最后我们按 start_year 和 end_year 聚合。

library(zoo)

# define season as Dec - Mar
season <- c(12, 1:3)  # month numbers in order they appear in season

last_month <- tail(season, 1)
ym <- as.yearmon(precip$d)
cross <- last_month < season[1]
in_season <- cycle(ym) %in% season

start_year <- as.integer(ym - cross * last_month / 12) * in_season
end_year <- start_year + cross * in_season

start_date <- as.Date(paste(start_year, season[1], 1, sep = "-"))
end_date <- as.Date(as.yearmon(paste(end_year, last_month, sep = "-")), frac = 1)

precip0 <- subset(data.frame(start_date, end_date, precip), in_season)
aggregate(prec ~ start_date + end_date, precip0, sum)

给予:

  start_date   end_date     prec
1 2000-12-01 2001-03-31 45.70959
2 2001-12-01 2002-03-31 58.67224
3 2002-12-01 2003-03-31 57.93712
4 2003-12-01 2004-03-31 59.66424
5 2004-12-01 2005-03-31 16.69944

或者也许使用 start_year 和 end_year 从那时起我们可以很容易地绘制 prec 与 end_year 的关系。

precip0 <- subset(data.frame(start_year, end_year, precip), in_season)
aggregate(prec ~ start_year + end_year, precip0, sum)

注意

我们假设输入 precip 如下。这与问题中的相同,只是我们添加了 set.seed 以使其可重现。

set.seed(123)
precip <- data.frame(d = seq.Date(from = as.Date('2001-01-01'),
                                  to = as.Date('2004-12-31'),
                                  by = 'day'),
                     prec = runif(1461))

【讨论】:

  • 哇!这很棒。对不起,我的例子不够清楚。我的时期需要以“更精细的时间尺度”来定义。例如,如何汇总每年 12 月 15 日到 3 月 15 日的所有数据?我将更新问题以使其更清楚。同时,我还将尝试在您的出色答案的基础上获得我想要的输出
  • 添加了另一种解决每日粒度问题的解决方案。
【解决方案2】:

我相信我使用cut 解决了它。这样我就可以设置任意的开始日期和结束日期,只要它们不在同一个月内。那是因为我使用开始月份作为过滤器来排除淡季观察。

我不确定这是最简单或最优雅的解决方案。但是……

startDate <- as.Date('2003-12-01')
endDate <- as.Date('2004-04-01')

start_month <- month(startDate)
start_day <- day(startDate)

end_month <- month(endDate)
end_day <- day(endDate)

start_year <- min(year(precip$d))
end_year <- max(year(precip$d))

breaks <- lapply(start_year:end_year, function (x) {
  c(paste (x, start_month, start_day), paste ( x + 1, end_month, end_day))
})

breaks <- unlist(breaks)

precip$season <- cut(precip$d, ymd(breaks))

precip0 <- precip[month(ymd(precip$season)) == start_month,]

aggregate(prec ~ season, precip0, sum)

这会导致

      season     prec
1 2001-12-01 58.67224
2 2002-12-01 57.93712
3 2003-12-01 59.66424
4 2004-12-01 16.69944

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-28
    • 2016-09-12
    • 1970-01-01
    • 2021-10-06
    • 1970-01-01
    • 1970-01-01
    • 2014-04-10
    • 1970-01-01
    相关资源
    最近更新 更多