R传递函数累加
R pass function to accumulate
我想使用这个累积示例来更改数据场中变量的固定“增长”。原始示例:https://community.rstudio.com/t/row-wise-iteration-in-a-dataframe-where-each-row-depends-on-previous-values/38725/2
library(dplyr)
library(purrr)
x <- tibble(a = c(1:10),
b = c(seq(100, 140, 10), rep(NA_real_, 5)) )
x$growth = runif(10, 0.001, 0.09)
fill_in <- function(prev, new, growth = 0.03) {
if_else(!is.na(new), new, prev * (1 + growth))
}
x <- x %>%
mutate(b = accumulate(b, fill_in))
这可行,但我不能用 x$growth 替换 0.03。有帮助吗?
由于 accumulate
(和 accumulate2
)的结构,我们不能只迭代 b
,我们需要为每个点包含类似 c(b, growth)
的内容。为此,我们将传递一个 list
向量,而不是传递 b
,它可以通过以下方式生成:
with(x, pmap(list(b, growth), c))
# [[1]]
# [1] 100.0000000 0.0265944
# [[2]]
# [1] 110.00000000 0.07115916
# [[3]]
# [1] 120.00000000 0.03739895
# [[4]]
# [1] 130.00000000 0.07958855
# [[5]]
# [1] 140.00000000 0.08470159
# [[6]]
# [1] NA 0.005054528
# [[7]]
# [1] NA 0.04800139
# [[8]]
# [1] NA 0.08042529
# [[9]]
# [1] NA 0.05007772
# [[10]]
# [1] NA 0.04163871
有了这个,我们现在可以积累:
fill_in2 <- function(prev, new) if (is.na(new[1])) prev[1]*(1+new[2]) else new[1]
options(pillar.sigfig = 5)
x %>%
mutate(b = accumulate(pmap(list(b, growth), c)[-1], .init = b[1], fill_in2))
# # A tibble: 10 x 3
# a b growth
# <int> <dbl> <dbl>
# 1 1 100 0.026594
# 2 2 110 0.071159
# 3 3 120 0.037399
# 4 4 130 0.079589
# 5 5 140 0.084702
# 6 6 140.71 0.0050545
# 7 7 147.46 0.048001
# 8 8 159.32 0.080425
# 9 9 167.30 0.050078
# 10 10 174.27 0.041639
我同时执行 pmap(..)[-1]
和 .init=b[1]
的原因是因为 accumulate
的默认行为,.x
的第一个元素按原样传递;在这种情况下,这会将 c(100, 0.0266)
作为第一个 return 值传递,这不是我们想要的。为了解决这个问题,我们将其从 pmap
列表中删除并添加 b[1]
作为 accumulate
.
的初始化值 (.init=
)
顺便说一句:这是使用 growth
的 当前 值应用于 b
的 先前 值.
另一个顺便说一句:您对 fill_in
的使用使用了 if_else
。虽然它有效,但它是不必要和不合适的。如果正在寻找 if
一个长度始终为 1 的对象,则使用 if
(以及可选的 else
);如果有人希望以 向量 为条件,则使用 ifelse
/if_else
。当你知道 if_else
总是长度为 1 时可以使用 if_else
,但是有开销并且可能发生其他完全不必要的事情(并且在基础 R 中, ifelse
有后果和副作用-对非平凡 class 数据的影响,因此应对其使用进行管理)。
由于 accumulate
一次仅使用一行数据调用您的函数,因此使用 if
更为合适。
数据
set.seed(123)
x <- tibble(a = c(1:10),
b = c(seq(100, 140, 10), rep(NA_real_, 5)),
growth = runif(10, 0.001, 0.09))
我想使用这个累积示例来更改数据场中变量的固定“增长”。原始示例:https://community.rstudio.com/t/row-wise-iteration-in-a-dataframe-where-each-row-depends-on-previous-values/38725/2
library(dplyr)
library(purrr)
x <- tibble(a = c(1:10),
b = c(seq(100, 140, 10), rep(NA_real_, 5)) )
x$growth = runif(10, 0.001, 0.09)
fill_in <- function(prev, new, growth = 0.03) {
if_else(!is.na(new), new, prev * (1 + growth))
}
x <- x %>%
mutate(b = accumulate(b, fill_in))
这可行,但我不能用 x$growth 替换 0.03。有帮助吗?
由于 accumulate
(和 accumulate2
)的结构,我们不能只迭代 b
,我们需要为每个点包含类似 c(b, growth)
的内容。为此,我们将传递一个 list
向量,而不是传递 b
,它可以通过以下方式生成:
with(x, pmap(list(b, growth), c))
# [[1]]
# [1] 100.0000000 0.0265944
# [[2]]
# [1] 110.00000000 0.07115916
# [[3]]
# [1] 120.00000000 0.03739895
# [[4]]
# [1] 130.00000000 0.07958855
# [[5]]
# [1] 140.00000000 0.08470159
# [[6]]
# [1] NA 0.005054528
# [[7]]
# [1] NA 0.04800139
# [[8]]
# [1] NA 0.08042529
# [[9]]
# [1] NA 0.05007772
# [[10]]
# [1] NA 0.04163871
有了这个,我们现在可以积累:
fill_in2 <- function(prev, new) if (is.na(new[1])) prev[1]*(1+new[2]) else new[1]
options(pillar.sigfig = 5)
x %>%
mutate(b = accumulate(pmap(list(b, growth), c)[-1], .init = b[1], fill_in2))
# # A tibble: 10 x 3
# a b growth
# <int> <dbl> <dbl>
# 1 1 100 0.026594
# 2 2 110 0.071159
# 3 3 120 0.037399
# 4 4 130 0.079589
# 5 5 140 0.084702
# 6 6 140.71 0.0050545
# 7 7 147.46 0.048001
# 8 8 159.32 0.080425
# 9 9 167.30 0.050078
# 10 10 174.27 0.041639
我同时执行 pmap(..)[-1]
和 .init=b[1]
的原因是因为 accumulate
的默认行为,.x
的第一个元素按原样传递;在这种情况下,这会将 c(100, 0.0266)
作为第一个 return 值传递,这不是我们想要的。为了解决这个问题,我们将其从 pmap
列表中删除并添加 b[1]
作为 accumulate
.
.init=
)
顺便说一句:这是使用 growth
的 当前 值应用于 b
的 先前 值.
另一个顺便说一句:您对 fill_in
的使用使用了 if_else
。虽然它有效,但它是不必要和不合适的。如果正在寻找 if
一个长度始终为 1 的对象,则使用 if
(以及可选的 else
);如果有人希望以 向量 为条件,则使用 ifelse
/if_else
。当你知道 if_else
总是长度为 1 时可以使用 if_else
,但是有开销并且可能发生其他完全不必要的事情(并且在基础 R 中, ifelse
有后果和副作用-对非平凡 class 数据的影响,因此应对其使用进行管理)。
由于 accumulate
一次仅使用一行数据调用您的函数,因此使用 if
更为合适。
数据
set.seed(123)
x <- tibble(a = c(1:10),
b = c(seq(100, 140, 10), rep(NA_real_, 5)),
growth = runif(10, 0.001, 0.09))