在 R Tidyverse 中使用 Mutate Verb 从滞后数据生成序列

Generating Series from Lagging Data with Mutate Verb in R Tidyverse

我正在使用 R 中的一些大型数据集,但我找不到用以前的值改变变量的方法。

在 for 循环中,它将是:

df <- tibble(x=c(1:10),y=c(1:10))

for(i in c(2:nrow(df))) {
    df$x[i] = df$x[i-1] * 1.05
}

我尝试了以下方法,但没有用。它只落后于系列一次。我需要它在遍历数据时滞后。

df %>% mutate(x=ifelse(x==1,1,lag(x)*1.05))

我的方法在前三行返回 1、1.05、2.10,我希望它返回 1、1.05、1.10。

lag 函数作用于前一行,因为它存在于函数被调用之前,而不是因为它存在于当前行之前。为了获得矢量化计算的好处并在没有循环的情况下获得它,您可以对滞后值使用 cumprod

df %>%
  mutate(xrate = 1.05,  # make a helper column to hold the growth rate
         # method 1, using cumprod on the helper column
         x  = cumprod(lag(xrate, default = 1)),
         # method 2, using algebra
         x2 = 1.05 ^ (y-1)) %>%
  select(-xrate)

# A tibble: 10 x 3
       x     y    x2
   <dbl> <int> <dbl>
 1  1        1  1   
 2  1.05     2  1.05
 3  1.10     3  1.10
 4  1.16     4  1.16
 5  1.22     5  1.22
 6  1.28     6  1.28
 7  1.34     7  1.34
 8  1.41     8  1.41
 9  1.48     9  1.48
10  1.55    10  1.55

我认为你的问题的核心是如何向量化计算,但如果一行是前一行结果的函数,你最终不能。 base 中内置了一些快速累积函数(cumsumcumprodcummaxcummin),但我假设这些函数在后台使用 C 或 C++ 循环。如果有机会您可以将计算转换为仅包含 x 初始值的函数,那么您就可以对该函数进行向量化。例如,在您提供的虚拟数据中,它实际上只是指数增长,可以表示为

tibble(x=c(1:10),y=c(1.05)) %>%
  mutate(x = 1*y^(x-1))

如前一个答案所建议的那样

如果您的问题只是如何将此计算放入管道式脚本中,那么提供给 mutate 的表达式的唯一要求是 return 长度为 1 或组中行数的相同长度。所以你可以这样做:

tibble(x=c(1:10),y=c(1.05)) %>%
  mutate(x = {
    out <- x[1]
    for(i in seq(2, NROW(x))) {
      out[i] = out[i-1] * 1.05
    }
    out
  })