Application of a recursive function within a dplyr context in R

I think you can probably get what you need here with a mix of tidyr::fill to fill NA values from above, combined with cumprod to get the cumulative effect of multiplying by the coefficient, and ifelse to choose when to use it. There's also a "working" column named V which is created and destroyed in the process.

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

Created on 2020-06-30 by the reprex package (v0.3.0)


A fully recursive way :

calc <- function(val,coef){
  for(i in 2:length(val))
  {
    if(is.na(val[i])){
      val[i] <- val[i-1]*coef[i]
    }
  }
  return(val)
}

library(dplyr)
df %>% 
  group_by(ID) %>%
  mutate(newval = calc(VALUE, COEFF))

  ID    VALUE COEFF newval
   <chr> <dbl> <dbl>  <dbl>
 1 a         1   1      1  
 2 a         3   2      3  
 3 a        NA   1      3  
 4 a        NA   0.5    1.5
 5 a        NA 100    150  
 6 b         2   1      2  
 7 b         2   1      2  
 8 b         3   1      3  
 9 b        NA   1      3  
10 b        NA   1      3  

group_by provides to mutate a subset of the original data fields for each ID.

You can then process these vectors in a standard recursive loop and give back a result vector of equal length to the mutate statement to put the results together.

If you need speed, the for-loop can easily be accelerated with Rcpp :

library(Rcpp)
Rcpp::cppFunction('
NumericVector calc(NumericVector val, NumericVector coef) {
  int n = val.size();
  int i;
  for (i = 1;i<n;i++){
      if(R_IsNA(val[i])){
        val[i] = val[i-1]*coef[i];
      }
    }
return val;
}')

Tags:

R

Dplyr