Within column subtraction iteratively in R

Viewed 57

I have the following data:

library tidyverse

age_grp <- c(10,9,8,7,6,5,4,3,2,1)
start <- c(0.420,0.420,0.420,0.420,0.420,0.420,0.420,0.420,0.420,0.420)
change <- c(0.020,0.033,0.029,0.031,0.027,0.032,0.032,0.030,0.027,0.034)
final_outcome <- c(0.400,0.367,0.338,0.307,0.28,0.248,0.216,0.186,0.159,0.125)
my_data <- data.frame(age_grp,start,change,final_outcome)

my_data1 <- my_data %>% 
  dplyr::arrange(age_grp)

I would like to subtract the values in the variable change from the values in the variable start such that it is an iterative decrease from the oldest age group to the youngest. The final values that I am looking to get are in the variable final_outcome. For example, starting with age_grp 10, I want to subtract 0.20 from 0.420 to get 0.400. Then, I would like to subtract 0.033 from 0.400 to get 0.367 and so forth. I am struggling with how to store those differences. I have made an attempt below, but I don't know how to store the difference to then continue the subtraction forward (or backward, depending on how you look at it). Any advice or suggestions would be appreciated.

my_data1$attempt <- NA

#calculating the decreases
for(i in 2:nrow(my_data1)) 
   my_data1$attempt[i] <- round(my_data1$start[i] - my_data1$change[i-1], 4)
3 Answers

If we need the same output as in final_outcome

library(dplyr)
my_data %>% 
   mutate(attempt = start - cumsum(change)) %>%
   arrange(age_grp)

-output

#  age_grp start change final_outcome attempt
#1        1  0.42  0.034         0.125   0.125
#2        2  0.42  0.027         0.159   0.159
#3        3  0.42  0.030         0.186   0.186
#4        4  0.42  0.032         0.216   0.216
#5        5  0.42  0.032         0.248   0.248
#6        6  0.42  0.027         0.280   0.280
#7        7  0.42  0.031         0.307   0.307
#8        8  0.42  0.029         0.338   0.338
#9        9  0.42  0.033         0.367   0.367
#10      10  0.42  0.020         0.400   0.400
my_data$final <- my_data$start - cumsum(my_data$change) 

library(tidyverse)
my_data %>% 
  mutate(attempt = accumulate(change, ~ .x - .y, .init = start[1])[-1])

Note: accumulate is from the purrr library that's part of the tidyverse. It also has a .dir argument where you can go "forward" or "backward".

Or in base R using Reduce:

within(my_data, attempt <- Reduce("-", change, init = start[1], accumulate = T)[-1])

Reduce has an argument right that can also do the computation forwards or backwards.

Output

   age_grp start change final_outcome attempt
1       10  0.42  0.020         0.400   0.400
2        9  0.42  0.033         0.367   0.367
3        8  0.42  0.029         0.338   0.338
4        7  0.42  0.031         0.307   0.307
5        6  0.42  0.027         0.280   0.280
6        5  0.42  0.032         0.248   0.248
7        4  0.42  0.032         0.216   0.216
8        3  0.42  0.030         0.186   0.186
9        2  0.42  0.027         0.159   0.159
10       1  0.42  0.034         0.125   0.125
Related