递归函数在 R 中的 dplyr 上下文中的应用

yea*_*269 6 r dplyr

我确实将 dplyr 用于几乎(如果不是全部)我的数据处理,但我总是在 R 中遇到一件事:递归计算。

上下文:我有一个已排序的数据框ID,其中包含一些VALUES. 其中一些缺失,但可以使用系数迭代计算COEFF。我正在寻找一种简单而优雅的方式来做到这一点(没有循环)。有什么线索吗?

注意:我们假设每个 总是有第一个非 NA 值ID

下面是具有预期解决方案的可重现示例:

df <- data.frame(ID = rep(letters[1:2], each = 5),
                 VALUE = c(1, 3, NA, NA, NA, 2, 2, 3, NA, NA),
                 COEFF = c(1, 2, 1, .5, 100, 1, 1, 1, 1, 1)
)

df_full <- df
# SOLUTION 1: Loop
for(i in 1:nrow(df_full))
{
  if(is.na(df_full$VALUE[i])){
    df_full$VALUE[i] <- df_full$VALUE[i-1]*df_full$COEFF[i]
  }
}
df_full
#   ID VALUE COEFF
#1   a   1.0   1.0
#2   a   3.0   2.0
#3   a   3.0   1.0
#4   a   1.5   0.5
#5   a 150.0 100.0
#6   b   2.0   1.0
#7   b   2.0   1.0
#8   b   3.0   1.0
#9   b   3.0   1.0
#10  b   3.0   1.0

# PSEUDO-SOLUTION 2: using Reduce()
# I struggle to apply this approach for each "ID", like we could do in dplyr using dplyr::group_by()
# Exemple for the first ID:
Reduce(function(v, x) x*v, x = df$COEFF[3:5], init = df$VALUE[2], accumulate = TRUE)

# PSEUDO-SOLUTION 3: dplyr::lag()
# We could think that we just have to use the lag() function to get the previous value, like such:
df %>% 
  mutate(VALUE = ifelse(is.na(VALUE), lag(VALUE) * COEFF, VALUE))
# but lag() is not "refreshed" after each calculation, it basically takes a copy of the VALUE column at the begining and adjust indexes.
Run Code Online (Sandbox Code Playgroud)

All*_*ron 3

我认为您可能可以在这里混合使用上面的tidyr::fill填充值,结合获得乘以系数的累积效果,并选择何时使用它,从而获得所需的内容。还有一个名为 V 的“工作”列,它在此过程中创建和销毁。NAcumprodifelse

library(dplyr)

df %>% 
  mutate(V = tidyr::fill(df, VALUE)$VALUE) %>% 
  group_by(ID) %>% 
  mutate(VALUE = ifelse(is.na(VALUE), 
                        V * cumprod(ifelse(is.na(VALUE), COEFF, 1)), 
                        VALUE)) %>% select(-V)
#> # A tibble: 10 x 3
#> # Groups:   ID [2]
#>    ID    VALUE COEFF
#>    <fct> <dbl> <dbl>
#>  1 a       1     1  
#>  2 a       3     2  
#>  3 a       3     1  
#>  4 a       1.5   0.5
#>  5 a     150   100  
#>  6 b       2     1  
#>  7 b       2     1  
#>  8 b       3     1  
#>  9 b       3     1  
#> 10 b       3     1
Run Code Online (Sandbox Code Playgroud)

由reprex 包(v0.3.0)于 2020-06-30 创建