我有10年的日降水量数据。我想得到的是12月到次年4月之间的总降水量。另一个复杂的问题是,期间可以改变,例如12月15日到3月15日
我知道如何使用 aggregate
或 group_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
我不需要组名包含周期这个字符串。它可以只是一个索引。
这个问题后来被更新为询问不是整月的季节,所以这是对原始答案的更新,以解决这个问题。 它使用了末尾注释中的输入和原型季节的开始日期和结束日期。 如果季节跨度为2月底,一定要选择一个闰年(如下面例子中的2000年)。
我们创建一个从开始日期到结束日期的所有日期序列,称为模板。 将其转换为季节中所有可能的月日的字符向量,mmdd。
接下来定义in_season,它的每一行pregip都有一个元素,如果该行的月份和日期与模板中的任何月份和日期相匹配,那么它就是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 (在末尾的注解中给出,季节是月号的向量 (1月=1, 2月=2, ..., 12月=12),顺序是它们出现在季节中。 在下面的例子中,我们使用c(12, 1:3),即12月-3月。
下面的代码使用 precip 和 season 来设置以下变量。
然后,我们插入start_year和end_year,并子集到那些季节为true的行。 最后,我们按照起始年和结束年进行汇总。
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))
我相信我是用以下方法解决的 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