簡體   English   中英

R 中不同年份的時間匯總

[英]Time aggregate across years in R

我有 10 年的每日降水數據。 我正在嘗試獲取例如在次年 12 月和 4 月之間發生的總降水量。 另一個復雜因素是該時期可能會發生變化,例如 12 月 15 日至 3 月 15 日

如果我不需要 go 多年來,我知道如何使用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

我不需要組名將句點包含為字符串。 它可能只是一個索引。

該問題后來被更新以詢問不是整月的季節,因此這是對原始答案的更新以解決該問題。 它使用結束時注釋中的輸入以及原型季節的開始日期和結束日期。 如果季節跨越 2 月底,請務必選擇閏年(例如 2000 年,如下例所示)。

我們創建了一個從開始日期到結束日期的所有日期序列,稱為模板。 將其轉換為季節中所有可能的月/日的字符向量,mmdd。

接下來定義 in_season 每行 precip 有一個元素,如果該行的月份和日期與模板中的任何月份和日期匹配,則為 TRUE。

然后定義 season_no ,它每行有一個元素,用唯一的數字標識每個季節。 對於日期不在季節的行,該數字為 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 class 向量。 在內部,它表示為 1 月加 0,2 月為 1/12,...,12 月為 11/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 從那時起我們可以很容易地 plot prec vs. 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM