Скользящий средний 182-дневный - PullRequest
0 голосов
/ 08 января 2020

У меня есть набор данных с несколькими сайтами и годами выборки, с оценкой за каждый день года. Например, у 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 

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

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

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

Ответы [ 2 ]

2 голосов
/ 08 января 2020

Если вы хотите использовать внешние библиотеки, вы можете использовать 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 НС до вашего первого полного среднего значения.

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

1 голос
/ 08 января 2020

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

library(dplyr)

DailyScore %>% 
  group_by(SITENAME, Sampling.Year) %>% 
  summarise(max_average = max(zoo::rollmean(Score, 182)))
...