条件季节平均时间序列数据

时间:2016-10-17 19:51:09

标签: r time-series

简介

要点:

  • 在满足某些条件时,尝试按季节(必要时)对数据进行平均。

大家好。

我目前正在处理多个大型数据集(大约200套,每组大于5000行)的长期时间序列数据集,用于跨不同位置的多个变量。到目前为止,我已经将数据提取到每个站点和每个站的单独CSV文件中。

在大多数情况下,每个参数报告的数据是每个季节一个实例。

这里的季节在生态上被定义为DJF,MAM,JJA,SON,分别对应于冬季,春季,夏季和秋季。

但是,在某些季节性事件中,有些情况下会有多个读数。这里,参数值和日期必须平均;这是在对这些数据集进行进一步分析之前。

为了使事情进一步复杂化,一些数据用大于或小于(GTLT)符号标记。在这些情况下,值和日期不是的平均值,除非记录的值相同。

数据示例

要点:

  • 代码和表格显示了数据集中所请求的更改

所以,对于数据驱动的例子......

这是数据集中的几行。

Data.Example<-structure(list(
    Station.ID = c(13402, 13402, 13402, 13402, 13402, 13402), 
    End.Date = structure(c(2L, 3L, 4L, 2L, 3L, 1L), .Label = c("10/13/2016", "7/13/2016", "8/13/2016", "8/15/2016"), class = "factor"), 
    Parameter.Name = structure(c(2L, 2L, 2L, 1L, 1L, 1L), .Label = c("Alkalinity", "Enterococci"), class = "factor"),
    GTLT = structure(c(2L, 2L, 2L, 1L, 1L, 1L), .Label = c("", "<"), class = "factor"), 
    Value = c(10, 10, 20, 30, 15, 10)), 
    .Names = c("Station.ID", "End.Date", "Parameter.Name","GTLT", "Value"), row.names = c(NA, -6L), class = "data.frame")

理想情况下,这是我想要的输出

Data.Example.New<-structure(list(
    Station.ID.new = c(13402, 13402, 13402, 13402), 
    End.Date.new = structure(c(2L, 3L, 2L, 1L), .Label = c("10/13/2016", "7/28/2016", "8/15/2016"), class = "factor"), 
    Parameter.Name.new = structure(c(2L, 2L, 1L, 1L), .Label = c("Alkalinity", "Enterococci"), class = "factor"), 
    GTLT.new = structure(c(2L, 2L, 1L, 1L), .Label = c("", "<"), class = "factor"), 
    Value.new = c(10, 20, 22.5, 10)), 
    .Names = c("Station.ID.new", "End.Date.new", "Parameter.Name.new", "GTLT.new", "Value.new"), row.names = c(NA, -4L), class = "data.frame")

在这里,发生了以下事情:

  • 对于在7月和8月13日测量的肠球菌,有一个GTLT符号,但两者的值== 10.所以平均日期。新行是2016年7月28日和价值10。
  • 虽然8月15日的肠球菌与其他值在同一季节,但由于GTLT值不同,它只会在同一年的同一季节平均,其他值为20.在这种情况下,因为它只有一个值== 20,该行不会改变,并在最终数据框中重复。
  • 7月和8月的碱度是同一季节,所以平均日期(7/28/16)和价值(22.5)是新的一排。
  • 十月的碱度是不同的季节,所以请保持排。
  • 所有其他数据(例如Station.ID和Parameter.Name)应该被复制,因为不应该在这里不同。

如果由于某种原因你有相同参数的GTLT和非GTLT:

End.Date    GTLT    Value    Parameter
7/13/2015     <      10         Alk
7/13/2016     <      10         Alk
8/13/2016            10         Alk
8/15/2016            20         Alk

然后最终结果将是

End.Date    GTLT    Value    Parameter
7/13/2015     <      10         Alk
7/13/2016     <      10         Alk
8/14/2016            15         Alk

方法

要点:

  • 定义季节,然后使用dplyr
  • 这样的包进行汇总
  • 创建循环函数以逐行读取(按Parameter.Name排序,然后按Date?)

正如人们所料,这就是我被困住的地方。

我知道可以在之前的Stack Q中用R定义季节:

New vector of seasons based on dates

我知道平均/聚合包,例如dplyr(可能zoo?)可以执行链接命令。

我的问题是将这个思维过程放入可以为每个数据集重复的代码中。

我不确定这是否是最好的方法(定义季节然后设置平均数据的条件),或者如果某种循环函数在这里通过参数排序后逐行遍历数据集将起作用.Name然后是End.Date。

我很快勾勒出我对某些循环函数必须包含的内容的想法:

Rough idea of flow diagram

注意,你不能只平均起始行[i]和[i + 1],因为[i + 2]等也可能需要平均。因此找到行[i + n]在最后一步之前打破循环,平均所有先前行[i + n-1],然后继续前进到下一个新行[i + n]。

此外,作为澄清,季节必须在该年度周期的季节内。所以7/13/2016 == 8/13/2016同一季节。 12/12/2015 == 01/01/2016同一季节。但是2016年4月13日! == 4/13/2015关于平均值。

结论和总结

简而言之,我需要帮助设计代码,以便按年度季节平均各个参数的时间序列值,并为多个大型数据集提供特定的例外情况。

我不确定设计代码的最佳方法,无论是大型循环函数还是代码和专用链接启用软件包的组合。

感谢您提前抽出时间。

干杯,

soccernamlak

1 个答案:

答案 0 :(得分:0)

使用dplyrlubridate我能够提出解决方案。我的输出与你的示例输出相匹配,除了我没有保留确切的日期,我认为这在最终结果中会产生误导。

Data.Example<-structure(list(
  Station.ID = c(13402, 13402, 13402, 13402, 13402, 13402), 
  End.Date = structure(c(2L, 3L, 4L, 2L, 3L, 1L), .Label = c("10/13/2016", "7/13/2016", "8/13/2016", "8/15/2016"), class = "factor"), 
  Parameter.Name = structure(c(2L, 2L, 2L, 1L, 1L, 1L), .Label = c("Alkalinity", "Enterococci"), class = "factor"),
  GTLT = structure(c(2L, 2L, 2L, 1L, 1L, 1L), .Label = c("", "<"), class = "factor"), 
  Value = c(10, 10, 20, 30, 15, 10)), 
  .Names = c("Station.ID", "End.Date", "Parameter.Name","GTLT", "Value"), row.names = c(NA, -6L), class = "data.frame")

# Create season key
seasons <- data.frame(month = 1:12, season = c(rep("DJF",2), rep("MAM", 3), rep("JJA", 3), rep("SON",3), "DJF"))

# Isolate Month and Year, create Season column
Data.Example$Month <- lubridate::month(as.Date((Data.Example$End.Date), "%m/%d/%Y"))
Data.Example$Year <- lubridate::year(as.Date((Data.Example$End.Date), "%m/%d/%Y"))
Data.Example$Season <- seasons$season[Data.Example$Month]

# Update 'year' where month = December so that it is grouped with Jan and Feb of following year
Data.Example$Year[Data.Example$Month == 12] <- Data.Example$Year[Data.Example$Month == 12]+1

# Find out which station/year/season/paramaters have at least one record with a GTLT
GTLT.Test<- Data.Example %>% 
  group_by(Station.ID, Year, Season, Parameter.Name) %>%
  summarize(has_GTLT = max(nchar(as.character(GTLT))))

# First only calculate averages for groups without any GTLT
Data.Example.New1 <- Data.Example %>% 
  anti_join(GTLT.Test[GTLT_test$has_GTLT == 1,], 
            by = c("Station.ID", "Year", "Season", "Parameter.Name")) %>%
  group_by(Station.ID, Year, Season, Parameter.Name, GTLT) %>%
  summarize(Value.new = mean(Value))

# Now do the same for groups with GTLT, only combining when values and GTLT symbols match.
Data.Example.New2 <- Data.Example %>% 
  anti_join(GTLT.Test[GTLT_test$has_GTLT == 0,], 
            by = c("Station.ID", "Year", "Season", "Parameter.Name")) %>%
  group_by(Station.ID, Year, Season, Parameter.Name, GTLT, Value) %>%
  summarize(Value.new = mean(Value)) %>%
  select(-Value)

# Combine both
Data.Example.New <- rbind(Data.Example.New1, Data.Example.New2)

编辑:我刚刚注意到您将另一个SO问题与日期转换为季节相关联。我只是按月而不是按日期转换,并且不使用实际季节。我这样做是因为在你的例子中,12月12日与1月1日比赛。12月12日在技术上下降,所以我假设你没有使用实际的季节,而是使用了四个三个月的分组。