在 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 中内置了一些快速累积函数(cumsum
、cumprod
、cummax
、cummin
),但我假设这些函数在后台使用 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
})
我正在使用 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 中内置了一些快速累积函数(cumsum
、cumprod
、cummax
、cummin
),但我假设这些函数在后台使用 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
})