функция запаздывания в Tidyverse, когда начальное значение находится в другом столбце - PullRequest
1 голос
/ 04 марта 2020

Я пытаюсь сделать экспоненциально взвешенное скользящее среднее (EWMA) для стоимости некоторых товаров в магазине. Для первого значения в столбце EWMA я требую, чтобы оно было первым значением элемента в первый день, а затем я хочу, чтобы EWMA сначала использовало это значение, а затем go оттуда. Тем не менее, я продолжаю застрять и получаю кучу АН. В Excel я обычно просто устанавливаю первую ячейку столбца EWMA равной первой ячейке значения для каждого элемента, а затем начинаю с уравнения во второй строке.

Вот пример того, что мой данные выглядят так:

библиотека (tidyverse)

## simulate data
set.seed(1)
item <- rep(LETTERS[1:3], each = 50)
day <- rep(1:50, times = 3)
value <- c(
  round(rnorm(n = 20, mean = 120, sd = 40), 2),
  round(rnorm(n = 10, mean = 150, sd = 20), 2),
  round(rnorm(n = 20, mean = 110, sd = 30), 2),
  round(rnorm(n = 20, mean = 120, sd = 40), 2),
  round(rnorm(n = 10, mean = 150, sd = 20), 2),
  round(rnorm(n = 20, mean = 110, sd = 30), 2),
  round(rnorm(n = 20, mean = 120, sd = 40), 2),
  round(rnorm(n = 10, mean = 150, sd = 20), 2),
  round(rnorm(n = 20, mean = 110, sd = 30), 2))


df <- data.frame(item, day, value)
df %>% head()

  item day  value
1    A   1  94.94
2    A   2 127.35
3    A   3  86.57
4    A   4 183.81
5    A   5 133.18
6    A   6  87.18

Для EWMA я использую уравнение lamda * value + (1 - lamda) * lag(EWMA), опять же, предостережение о том, что я хочу строку EWMA для каждого элемента быть начальным значением в первый день.

Вот что я пробовал:

lamda <- 0.3


df <- df %>%
  group_by(item) %>%
  mutate(ewma = ifelse(day == 1, value, NA),
         ewma = lamda*value + ((1 - lamda) * lag(ewma)))

И вот что он произвел:

# A tibble: 150 x 4
# Groups:   item [3]
   item    day value  ewma
   <fct> <int> <dbl> <dbl>
 1 A         1  94.9  NA  
 2 A         2 127.   105.
 3 A         3  86.6  NA  
 4 A         4 184.   NA  
 5 A         5 133.   NA  
 6 A         6  87.2  NA  
 7 A         7 140.   NA  
 8 A         8 150.   NA  
 9 A         9 143.   NA  
10 A        10 108.   NA  

Если Например, я запускаю это в Excel, я ожидаю, что эти первые 10 строк будут выглядеть так:

   item day  value  ewma
1     A   1  94.94  94.9
2     A   2 127.35 104.5
3     A   3  86.57  99.2
4     A   4 183.81 124.6
5     A   5 133.18 127.1
6     A   6  87.18 115.1
7     A   7 139.50 122.6
8     A   8 149.53 130.8
9     A   9 143.03 134.5
10    A  10 107.78 126.5

Есть ли эффективный способ создать это в tidyverse?

1 Ответ

1 голос
/ 04 марта 2020

Каждое вычисление ewma станет входом следующего вычисления. Это типичный случай reduce() или accumulate() в purrr.

library(dplyr)
library(purrr)

df %>%
  group_by(item) %>%
  mutate(ewma = accumulate(value, ~ lamda * .y + (1 - lamda) * .x))

# # A tibble: 150 x 4
# # Groups:   item [3]
#    item    day value  ewma
#    <fct> <int> <dbl> <dbl>
#  1 A         1  94.9  94.9
#  2 A         2 127.  105. 
#  3 A         3  86.6  99.2
#  4 A         4 184.  125. 
#  5 A         5 133.  127. 
#  6 A         6  87.2 115. 
#  7 A         7 140.  122. 
#  8 A         8 150.  131. 
#  9 A         9 143.  134. 
# 10 A        10 108.  126. 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...