查找当前行上方满足条件的最接近的值并对每个组应用函数

And*_*own 4 r data.table tidyverse

我想按组对每一行进行简单的计算,但我需要引用满足某些条件的前一行。我想创建一个新变量,results. 对于每组中的每一行,我想找到上面最接近的行 wheretag == "Y"codeis not NA。然后,我想使用value该行中的 ,并乘以当前行中的值。

最小的例子

df <- structure(list(name = c("apples", "apples", "apples", "apples", 
                              "oranges", "oranges", "oranges", "oranges"), 
               id = 1:8, 
               tag = c("X", "Y", "Y", "X", "X", "Y", "X", "X"), 
               code = c(1, 1, NA, 1, NA, 1, NA, NA),
               value = c(1, 11, 4, 3, 9, 5, 7, 8)), 
          class = "data.frame", row.names = c(NA, -8L))

     name id tag code value
1  apples  1   X    1     1
2  apples  2   Y    1    11
3  apples  3   Y   NA     4
4  apples  4   X    1     3
5 oranges  5   X   NA     9
6 oranges  6   Y    1     5
7 oranges  7   X   NA     7
8 oranges  8   X   NA     8
Run Code Online (Sandbox Code Playgroud)

预期输出

例如,对于第 3 行,第 2 行将是最接近满足条件的行,因此将 4 乘以 11(得到 44)。对于第 4 行,第 3 行不满足条件,因此我们转到第 2 行,并将 3 乘以 11(得到 33)。等等。

     name id tag code value results
1  apples  1   X    1     1      NA
2  apples  2   Y    1    11      NA
3  apples  3   Y   NA     4      44
4  apples  4   X    1     3      33
5 oranges  5   X   NA     9      NA
6 oranges  6   Y    1     5      NA
7 oranges  7   X   NA     7      35
8 oranges  8   X   NA     8      40
Run Code Online (Sandbox Code Playgroud)

我猜我需要使用cumsumand/or fill,但不确定如何在这里使用它。我知道,如果我对前一行执行计算,那么我可以使用lag,但不确定如何搜索上面的多个值。我对基础 R、data.tabletidyverse或其他解决方案持开放态度。

Ony*_*mbu 5

df %>% 
  group_by(name) %>%
  mutate(t = na_if(lag(value * (tag == 'Y' & !is.na(code))), 0)) %>%
  fill(t) %>%
  mutate(results = t * value)

# A tibble: 8 x 7
# Groups:   name [2]
  name       id tag    code value     t results
  <chr>   <int> <chr> <dbl> <dbl> <dbl>   <dbl>
1 apples      1 X         1     1    NA      NA
2 apples      2 Y         1    11    NA      NA
3 apples      3 Y        NA     4    11      44
4 apples      4 X         1     3    11      33
5 oranges     5 X        NA     9    NA      NA
6 oranges     6 Y         1     5    NA      NA
7 oranges     7 X        NA     7     5      35
8 oranges     8 X        NA     8     5      40
Run Code Online (Sandbox Code Playgroud)