我确实将 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)
我认为您可能可以在这里混合使用上面的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 创建