该问题后来被更新为询问不是整月的季节,因此这是对原始答案的更新以解决该问题。它使用结束时注释中的输入以及原型季节的开始日期和结束日期。如果季节跨越 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))