首页 > 解决方案 > 当起始值在不同的列中时,tidyverse 中的滞后函数

问题描述

我正在尝试对某些商店商品的价值进行指数加权移动平均值 (EWMA)。对于 EWMA 列中的第一个值,我要求它是第 1 天的项目的第一个值,然后我希望 EWMA 最初使用该值,然后从那里开始。但是,我一直被卡住并获得了一堆 NA。在 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,我使用的是 equation lamda * value + (1 - lamda) * lag(EWMA),再次需要注意的是,我希望每个项目的 EWMA 行成为第 1 天的起始值。

这是我尝试过的:

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

标签: rlag

解决方案


的每次计算都ewma将成为下一次计算的输入。reduce()这是or accumulate()in的典型案例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. 

推荐阅读