Скользящее 182-дневное среднее

У меня есть набор данных с несколькими сайтами и годами выборки с оценкой за каждый день года. Например, SiteA содержит данные за 40 лет со значением для каждого дня, а год выборки определяется как Sampling.Year. Чтобы сбить с толку, наш год выборки - июль-июнь, поэтому мы принимаем форму 2016-2017. Например:

SiteName Sampling.Year   Date    Score 
A        2015-2016               1  
A        2015-2016               5  
A        2015-2016               2 
A        2016-2017               3 
A        2016-2017               12 
A        2016-2017               6 
B        2015-2016               9 
B        2015-2016               2 
B        2015-2016               1 
B        2016-2017               4 
B        2016-2017               1 
B        2016-2017               7

Я хочу применить скользящее 182-дневное среднее к этим данным, чтобы найти максимальную (182-дневную среднюю) оценку для каждой комбинации сайт / выборка.Год. Результат будет, например:

Site Sampling.Year   MaxAve StartDate
A    2016-2017       7.5    01/10/2016 
A    2017-2018       6.0    12/12/2017 
B    2016-2017       2.3    13/11/2016
B    2017-2018       4.2    09/09/2017 

Я сохранил здесь образец набора данных: Образец данных. Я хочу использовать код цикла (потому что я новичок и не уверен в лучшем способе) в соответствии с этим, но это группировка сайтов и лет, которые я нахожу сложными. В идеале я бы хотел, чтобы скользящее среднее можно было экспортировать как новый фрейм данных с датой начала и окончания (или, по крайней мере, датой начала) для каждого окна, чтобы мы могли проверить ее на соответствие погодным условиям в то время.

Moving_Average_Function <- function(arr, n=182){
  res = arr
  for(i in n:length(arr)){
    res[i] = mean(arr[(i-n+1):i])
  }
  res
}

заранее спасибо


person CatN    schedule 08.01.2020    source источник


Ответы (2)


Если вы хотите использовать внешние библиотеки, вы можете использовать group_by() из пакета dplyr и функцию roll_mean() из пакета RcppRoll. RcppRoll имеет набор быстрых гибких функций для расчета скользящих средних.

Я также хотел бы преобразовать ваш столбец DATE в класс даты, чтобы он располагался плавно.

library(dplyr)  # I would typically use library(tidyverse) to load both dplyr and tidyr (among other related packages)
library(tidyr)
library(lubridate)
library(RcppRoll)

my_data <- data.table::fread("DailyScore.csv")  # easy way to load a data frame from file

my_data2 <- my_data %>%
      mutate(DATE = dmy(DATE)) %>% # Converting to Date format
      pivot_longer(H1:T2, 
                   names_to = "Sensor",
                   values_to = "data"
                   )  %>% # convert column names to data
      group_by(STATION, Sensor) %>%  # so you don't average by site.
      arrange(STATION, DATE) %>%  # to be sure you are in order for the rolling mean 
                                  #  The STATION argument isn't necessary, but helps for display
      mutate(Mean_182 = roll_meanr(data, 182)) %>%  # New column with your rolling mean
      pivot_wider(names_from = Sensor, values_from = c(data, Mean_182))  # converts back to original "wide" format

my_data2[180:195,]

# # A tibble: 16 x 14
# # Groups:   STATION [1]
# STATION SITENAME Sampling.Year DATE       data_H1  data_I1 data_H2 data_P2 data_T2 Mean_182_H1
# <chr>   <chr>    <chr>         <date>       <dbl>    <dbl>   <dbl>   <dbl>   <dbl>       <dbl>
#       1 Site A  Site A   1979-1980     1980-06-28    2.85 1.06e- 9    2.10   0.762    2.85       NA   
# 2 Site A  Site A   1979-1980     1980-06-29    2.79 1.62e-12    2.06   0.744    2.79       NA   
# 3 Site A  Site A   1979-1980     1980-06-30    2.75 1.00e-11    2.04   0.732    2.75        2.70
# 4 Site A  Site A   1980-1981     1980-07-01    2.72 1.00e-11    2.01   0.724    2.72        2.71
# 5 Site A  Site A   1980-1981     1980-07-02    2.70 1.00e-11    2.00   0.720    2.70        2.73
# 6 Site A  Site A   1980-1981     1980-07-03    2.68 1.00e-11    1.98   0.718    2.68        2.74
# 7 Site A  Site A   1980-1981     1980-07-04    2.67 1.00e-11    1.97   0.719    2.67        2.75
# 8 Site A  Site A   1980-1981     1980-07-05    2.65 1.11e- 9    1.95   0.708    2.65        2.76
# 9 Site A  Site A   1980-1981     1980-07-06    2.62 2.77e-10    1.93   0.703    2.62        2.76
# 10 Site A  Site A   1980-1981     1980-07-07    2.60 3.18e-12    1.92   0.700    2.60        2.77
# 11 Site A  Site A   1980-1981     1980-07-08    2.59 1.00e-11    1.90   0.701    2.59        2.79
# 12 Site A  Site A   1980-1981     1980-07-09    2.59 1.00e-11    1.89   0.706    2.59        2.80
# 13 Site A  Site A   1980-1981     1980-07-10    2.59 1.00e-11    1.89   0.713    2.59        2.81
# 14 Site A  Site A   1980-1981     1980-07-11    2.59 1.00e-11    1.88   0.722    2.59        2.82
# 15 Site A  Site A   1980-1981     1980-07-12    2.60 1.00e-11    1.88   0.731    2.60        2.83
# 16 Site A  Site A   1980-1981     1980-07-13    2.60 1.00e-11    1.87   0.741    2.60        2.84
# # ... with 4 more variables: Mean_182_I1 <dbl>, Mean_182_H2 <dbl>, Mean_182_P2 <dbl>, Mean_182_T2 <dbl>

Следует иметь в виду пару вещей, которые повлияют на то, как вы это настроите.

  1. Обычно скользящие средние возвращают NA, если у них нет полного набора данных. Таким образом, при 182-дневном среднем вы получите серию из 181 NA до вашего первого полного среднего.

  2. Вы захотите выяснить, как вы хотите справиться с перебазированием деталей - особенно с длительным периодом скользящего среднего, если вы не хотите смешивать годы выборки, у вас будет около полугода без данных.

person Brian Fisher    schedule 08.01.2020
comment
как мне сделать одно и то же скользящее среднее для всех категорий (H1, I1, H2, P2, T2) одновременно? Затем я хотел бы выбрать наивысший балл для T1 для каждой выборки.Год и экспортировать в новый фрейм данных со связанным средним для каждой из других категорий на эту дату (не имеет значения, не является ли это максимумом каждой из те). - person CatN; 09.01.2020
comment
Если вам нужна новая таблица без оригинала, вы можете использовать summarize_all() вместо mutate() для скользящего среднего, в этом случае вам не понадобятся сводные функции. Оба взяты из пакета dplyr. - person Brian Fisher; 09.01.2020
comment
Ах, это очень круто, спасибо !! Я многому научился из ваших ответов, большое спасибо за то, что нашли время. У меня есть еще один вопрос, основанный на тех же данных, но я могу сделать новый пост, чтобы он не сбивал с толку. - person CatN; 09.01.2020

Использование циклов для таких операций было бы очень неэффективным. Вы можете использовать некоторые специальные функции, которые позволяют выполнять это по группам, и использовать zoo::rollmean для получения скользящего среднего.

library(dplyr)

DailyScore %>% 
  group_by(SITENAME, Sampling.Year) %>% 
  summarise(max_average = max(zoo::rollmean(Score, 182)))
person Ronak Shah    schedule 08.01.2020
comment
Спасибо, Ронак! Еще один глупый вопрос (извините), но как мне ограничить его уникальной переменной, например. столбец I (переменная T2) в наборе данных выборки? - person CatN; 08.01.2020
comment
@CatN Вы хотите сказать, что хотите применить его только к T2 переменной? Вы можете использовать T2 вместо Score, summarise(max_average = max(zoo::rollmean(T2, 182))) - person Ronak Shah; 08.01.2020