使用R计算季节性均值的最优雅方法是什么?

时间:2013-09-24 09:52:18

标签: r time-series mean

我将时间序列与每日平均观察数据均匀分布。

如何计算季节性意味着最简单的方法?季节应遵循DJF(=冬季:12月,1月,2月),MAM,JJA和SON的气象命名。

这意味着12月的价值来自x-1年。

这里很好地展示了每月平均值的计算方法: How to calculate a monthly mean?

在计算季节性手段时可以遵循这个想法。但是,有几点需要注意,它不是很透明,必须要小心!

我还在前一个帖子中处理了这个问题的一小部分:How to switch rows in R?

现在是完整的故事:

0:制作随机时间序列

ts.pdsi <- data.frame(date = seq(
                from=as.Date("1901-01-01"), 
                to=as.Date("2009-12-31"), 
                by="day"))
ts.pdsi$scPDSI <- rnorm(dim(ts.foo)[1],  mean=1, sd=1)    # add some data

1st:使用海洋套餐并将季节添加到您的时间序列中,必须将其格式化为data.frame。

library(seas)
# add moth/seasons
ts.pdsi$month  <- mkseas(ts.pdsi,"mon")   # add months
ts.pdsi$seas <- mkseas(ts.pdsi,"DJF")     # add seasons
ts.pdsi$seasyear <- paste(format(ts.pdsi[,1],"%Y"), 
                          ts.pdsi$seas ,sep="")   # add seasyears, e.g. 1950DJF

这给出了

> head(ts.pdsi)
    date      scPDSI month seas seasyear
1 1901-01-01 -0.10881074   Jan  DJF  1901DJF
2 1901-02-01 -0.22287750   Feb  DJF  1901DJF
3 1901-03-01 -0.12233192   Mär  MAM  1901MAM
4 1901-04-01 -0.04440915   Apr  MAM  1901MAM
5 1901-05-01 -0.36334082   Mai  MAM  1901MAM
6 1901-06-01 -0.52079030   Jun  JJA  1901JJA

第二名:然后您可以使用$ seasyear

列按照上述方法计算季节性均值
> MEAN <- tapply(pdsi$scPDSI, ts.pdsi$seasyear, mean, na.rm = T)
> head(MEAN)
1901DJF     1901JJA     1901MAM     1901SON     1902DJF     1902JJA 
-0.45451556 -0.72922229 -0.17669396 -1.12095590 -0.86523850 -0.04031273 

注意:spring(MAM)和Summer(JJA)由于严格的字母排序而被切换。

第3名将其切换回来

foo <- MEAN
for(i in 1:length(MEAN)) {
    if (mod (i,4) == 2) {
        foo[i+1] <- foo[i]    #switch 2nd 3rd row (JJA <-> MAM)
        foo[i] <- MEAN[i+1]
    }
}
# and generate new names for the array
d <- data.frame(date=seq(from=as.Date("1901-01-01"), to=as.Date("2009-12-31"), by="+3 month"))
d$seas <- mkseas(d,"DJF") 
d$seasyear <- paste(format(d[,1],"%Y"), d$seas ,sep="")
names(foo)<-d$seasyear  # add right order colnames
MEAN <-foo

最后,这导致了季节性手段的时间序列。好吧,我把它弄得太复杂了,我想有更简单的解决方案。

此外,这个解决方案也是冬季DJF的一个非常重要的问题:到目前为止,12月还没有选择去年。这很容易修复(我猜),但使得给定的方式前夕更复杂。

我真的希望有更好的想法!

4 个答案:

答案 0 :(得分:4)

我这就是你想要的?

# # create some data: daily values for three years
df <- data.frame(date = seq(from = as.Date("2007-01-01"),
                            to = as.Date("2009-12-31"),
                            by = "day"))
df$vals <- rnorm(nrow(df))

# add year
df$year <- format(df$date, "%Y")

# add season
df$seas <- mkseas(x = df, width = "DJF")

# calculate mean per season within each year
df2 <- aggregate(vals ~ seas + year, data = df, mean)

df2
#    seas year         vals
# 1   DJF 2007 -0.048407610
# 2   MAM 2007  0.086996842
# 3   JJA 2007  0.013864555
# 4   SON 2007 -0.081323367
# 5   DJF 2008  0.170887946
# 6   MAM 2008  0.147830260
# 7   JJA 2008  0.003008866
# 8   SON 2008 -0.057974215
# 9   DJF 2009 -0.043437437
# 10  MAM 2009 -0.048345979
# 11  JJA 2009  0.023860506
# 12  SON 2009 -0.060076870

由于mkseas将日期转换为具有所需顺序级别的季节性因素,因此订单在年度和季节的汇总后也是正确的。

答案 1 :(得分:2)

如果你在数月和季节使用数字而不是字符串,这可能会更容易,至少在开始时如此。您可以通过简单的算术操作获得您想要的季节,包括将12月作为下一年的一部分。

pdsi <- data.frame(date = seq(
            from=as.Date("1901-01-01"), 
            to=as.Date("2009-12-31"), 
            by="day"))
pdsi$scPDSI <- rnorm(nrow(pdsi),  mean=1, sd=1)
pdsi$mon<-mon(pdsi$date)+1
pdsi$seas<-floor((pdsi$mon %% 12)/3)+1
pdsi$year<-year(pdsi$date)+1900
pdsi$syear<-pdsi$year
pdsi$syear[pdsi$mon==12]<-pdsi$syear[pdsi$mon==12]+1

要计算季节性方法,您可以简单地执行此操作:

meanArray<-tapply(pdsi$scPDSI,list(year=pdsi$syear,seas=pdsi$seas),mean)

现在你有了

>head(meanArray)
      seas
year           1         2         3         4
  1901 1.0779676 1.0258306 1.1515175 0.9682434
  1902 0.9900312 0.8964994 1.1028336 1.0074296
  1903 0.9912233 0.9858088 1.1346901 1.0569518
  1904 0.7933653 1.1566892 1.1223454 0.8914211
  1905 1.1441863 1.1824074 0.9044940 0.8971485
  1906 0.9900826 0.9933909 0.9185972 0.8922987

如果你想把它作为一个扁平数组,并有适当的名字,你首先进行转置,然后展平数组,并添加名称

colnames(meanArray)<-c("DJF","MAM","JJA","SON")
meanArray<-t(meanArray)
MEAN<-array(meanArray)
names(MEAN)<-paste(colnames(meanArray)[col(meanArray)],rownames(meanArray)[row(meanArray)],sep="")

这可以让你得到你想要的结果

> head(MEAN)
  1901DJF   1901MAM   1901JJA   1901SON   1902DJF   1902MAM 
1.0779676 1.0258306 1.1515175 0.9682434 0.9900312 0.8964994  

答案 2 :(得分:1)

如上所述,可以有非常简单的解决方案(也发布here)。我会使用 zoo seas 包的组合按季节进行汇总,看起来像这样:

library(zoo); library(seas)

seasTS <- aggregate(dataTS, mkseas(x=time(dataTS),width="DJF"), sum)

要为每年执行此操作,只需按年份循环遍历mkseas()。请给我一杯含有少许语法糖的咖啡。

干杯,

亚当

答案 3 :(得分:0)

我遇到了同样的问题,但有月度数据和 aggregate 多年来不允许 DJF 拆分。为了解决这个问题,您可以添加一个合成年份列,将 12 月的值分配给下一年。

library(dplyr)
library(seas)
library(lubridate)

df <- data.frame(yearmonth = c("187601", "187602", "187603", "187604", "187605", "187606", "187607","187608", "187609", "187610", "187611", "187612", "187701", "187702", "187703", "187704", "187705", "187706", "187707", "187708", "187709", "187710", "187711", "187712", "187801", "187802", "187803", "187804", "187805", "187806", "187807", "187808", "187809", "187810", "187811", "187812", "187901", "187902", "187903", "187904", "187905", "187906", "187907", "187908", "187909", "187910", "187911", "187912"), 
                 SOI = rnorm(n = 48, mean = 0, sd = 4))


df %>% 
  mutate(yearmonth = lubridate::ymd(yearmonth, truncated = 1),
         year = year(yearmonth),
         month = month(yearmonth),
         seas = mkseas(yearmonth, width = "DJF"),
         year2 = ifelse(test = month == 12,
                        yes = year + 1,
                        no = year)) %>% 
  group_by(year2, seas) %>% 
  summarise(meanSOI = mean(SOI))