Функция, суммирующая предыдущие N наблюдений

#r

#r

Вопрос:

Я хотел бы найти эффективный способ суммирования количества очков, полученных командой в предыдущих N матчах (не включая очки в текущем матче) для каждой комбинации simulation_ID, team и season . Если команда сыграла менее N матчей, функция должна вернуть NA.

Упрощенный набор данных:

match_ID сезон simulation_ID домашняя команда Команда match_result team_points
1 2015-2016 1 ВЕРНО Манчестер Юнайтед Главная победа 3
1 2015-2016 2 ВЕРНО Манчестер Юнайтед Нарисовать 1
1 2015-2016 3 ВЕРНО Манчестер Юнайтед Главная победа 3
1 2015-2016 1 ЛОЖЬ Tottenham Главная победа 0
1 2015-2016 2 ЛОЖЬ Tottenham Главная победа 0
1 2015-2016 3 ЛОЖЬ Tottenham Победа гостей 3
2 2015-2016 1 ВЕРНО Лестер Главная победа 3
2 2015-2016 2 ВЕРНО Лестер Главная победа 3
2 2015-2016 3 ВЕРНО Лестер Победа гостей 0
2 2015-2016 1 ЛОЖЬ Сандерленд Нарисовать 1

Ожидаемый результат — это дополнительный столбец в данных, называемый ‘accumulated_team_points’, который возвращает очки в последних N матчах для этой команды, сезона и simulation_ID.

Кажется, я не могу найти способ сделать это.

Комментарии:

1. Пожалуйста, покажите ожидаемый результат

2. Я отредактировал свой вопрос, это то, что вы имели в виду?

3. Tor97, цель состоит в том, чтобы вы показали, что, по вашему мнению, подобная операция должна в конечном итоге предоставить в качестве своих результатов. Если вы видите мой ответ, я демонстрирую, что даже в таком, казалось бы, простом вопросе, как этот, есть варианты, которые дают разные результаты. В хороших вопросах по SO часто можно найти попытки написания кода, образцы данных, ожидаемый результат с учетом этих выборочных данных и часто предупреждения / ошибки, которые являются проблематичными.

Ответ №1:

Здесь вам понадобятся две операции: группировка (я продемонстрирую с dplyr помощью) и суммирование в режиме скользящего окна (я буду использовать zoo ).

Кроме того, ваши данные слишком скудны, чтобы их можно было группировать по всем трем team, season, simulation_ID , поэтому я просто покажу группировку к team этому времени. Для ваших больших данных замените group_by(team) на group_by(team, season, simulation_ID) .

 library(dplyr)
k <- 3 # window size
dat %>%
  group_by(team) %>%
  mutate(accumulated_team_points = zoo::rollapply(team_points, k, FUN = sum, align = "right", fill = NA)) %>%
  ungroup()
# # A tibble: 10 x 8
#    match_ID season    simulation_ID home_team team           match_result team_points accumulated_team_points
#       <int> <chr>             <int> <lgl>     <chr>          <chr>              <int>                   <int>
#  1        1 2015-2016             1 TRUE      Manchester Utd Home win               3                      NA
#  2        1 2015-2016             2 TRUE      Manchester Utd Draw                   1                      NA
#  3        1 2015-2016             3 TRUE      Manchester Utd Home win               3                       7
#  4        1 2015-2016             1 FALSE     Tottenham      Home win               0                      NA
#  5        1 2015-2016             2 FALSE     Tottenham      Home win               0                      NA
#  6        1 2015-2016             3 FALSE     Tottenham      Away win               3                       3
#  7        2 2015-2016             1 TRUE      Leicester      Home win               3                      NA
#  8        2 2015-2016             2 TRUE      Leicester      Home win               3                      NA
#  9        2 2015-2016             3 TRUE      Leicester      Away win               0                       6
# 10        2 2015-2016             1 FALSE     Sunderland     Draw                   1                      NA     
 

По умолчанию NA используется значение для первых k-1 экземпляров в окне, что обычно является разумным и оправданным значением по умолчанию. Однако, если вы хотите суммировать даже частичные суммы, замените fill=NA на partial=TRUE :

 dat %>%
  group_by(team) %>%
  mutate(accumulated_team_points = zoo::rollapply(team_points, k, FUN = sum, align = "right", partial = TRUE)) %>%
  ungroup()
# # A tibble: 10 x 8
#    match_ID season    simulation_ID home_team team           match_result team_points accumulated_team_points
#       <int> <chr>             <int> <lgl>     <chr>          <chr>              <int>                   <int>
#  1        1 2015-2016             1 TRUE      Manchester Utd Home win               3                       3
#  2        1 2015-2016             2 TRUE      Manchester Utd Draw                   1                       4
#  3        1 2015-2016             3 TRUE      Manchester Utd Home win               3                       7
#  4        1 2015-2016             1 FALSE     Tottenham      Home win               0                       0
#  5        1 2015-2016             2 FALSE     Tottenham      Home win               0                       0
#  6        1 2015-2016             3 FALSE     Tottenham      Away win               3                       3
#  7        2 2015-2016             1 TRUE      Leicester      Home win               3                       3
#  8        2 2015-2016             2 TRUE      Leicester      Home win               3                       6
#  9        2 2015-2016             3 TRUE      Leicester      Away win               0                       6
# 10        2 2015-2016             1 FALSE     Sunderland     Draw                   1                       1
 

К вашему сведению: я предполагаю, что данные предварительно упорядочены.


Данные

 dat <- structure(list(match_ID = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L), season = c("2015-2016", "2015-2016", "2015-2016", "2015-2016", "2015-2016", "2015-2016", "2015-2016", "2015-2016", "2015-2016", "2015-2016"), simulation_ID = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L), home_team = c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE), team = c("Manchester Utd", "Manchester Utd", "Manchester Utd", "Tottenham", "Tottenham", "Tottenham", "Leicester", "Leicester", "Leicester", "Sunderland"), match_result = c("Home win", "Draw", "Home win", "Home win", "Home win", "Away win", "Home win", "Home win", "Away win", "Draw"), team_points = c(3L, 1L, 3L, 0L, 0L, 3L, 3L, 3L, 0L, 1L)), class = "data.frame", row.names = c(NA, -10L))
 

Комментарии:

1. Невероятно, именно то, что мне было нужно! Спасибо. Я запомню ‘rollapply’.

2. Может сократить прокатную часть до: zoo::rollsumr(team_points, k, fill = NA)