Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change the value in a row if condition met in the previous row under dplyr

Tags:

r

dplyr

Is there any alternative way to replace the following codes under dplyr to avoid explicit loop and data name to achieve the following?

This is to create an adjusted date, if the condition of the current supp_date less than the previous supp_date + tablet is met.

Sample data: (This is the new sample data with else case in it.)

test <- read.table(text =
    "supp_date    tablet
2017-07-19    30
2017-08-07    30
2017-09-08    30
2017-10-30    30
2017-11-08    30
2017-12-07    30", header = T)

R code:

test$supp_date <- as.Date(test$supp_date, "%Y-%m-%d")
test$adj_fill_dt <- as.Date(NA, "%Y-%m-%d")
test$adj_fill_dt[1] <- test$supp_date[1]
for(i in 2:6) {
  if (test[i, "supp_date"] < test[i-1, "adj_fill_dt"] + test[i-1, "tablet"]) {
      test[i, "adj_fill_dt"] <- test[i-1, "adj_fill_dt"] + test[i-1, "tablet"]
  } else {
    test[i, "adj_fill_dt"] <- test[i, "supp_date"]
  }
}

From:

supp_date    tablet
2017-07-19    30
2017-08-07    30
2017-09-08    30
2017-10-30    30
2017-11-08    30
2017-12-07    30

To:

supp_date    tablet   adj_fill_dt
2017-07-19    30       2017-07-19
2017-08-07    30       2017-08-18
2017-09-08    30       2017-09-17
2017-10-30    30       2017-10-30
2017-11-08    30       2017-11-29
2017-12-07    30       2017-12-29
like image 306
Fred Avatar asked Oct 14 '25 09:10

Fred


1 Answers

We can do this recursively with accumulate

library(tidyverse)
df %>% 
  mutate(tmp = as.numeric(supp_date),
        adj_fill_dt = as.Date(accumulate(tmp[-1], ~
             pmax(.x + tablet[1], .y), .init = tmp[1]), 
                           origin = '1970-01-01'),
        tmp = NULL)
#   supp_date tablet adj_fill_dt
#1 2017-07-19     30  2017-07-19
#2 2017-08-07     30  2017-08-18
#3 2017-09-08     30  2017-09-17
#4 2017-10-30     30  2017-10-30
#5 2017-11-08     30  2017-11-29
#6 2017-12-07     30  2017-12-29

Or with base R using Reduce

v1 <- as.numeric(df$supp_date)
as.Date(Reduce(function(u, v)  pmax(u + 30, v), v1[-1], 
      init = v1[1], accumulate = TRUE), origin = '1970-01-01')
#[1] "2017-07-19" "2017-08-18" "2017-09-17" "2017-10-30" "2017-11-29"
#[6] "2017-12-29"

data

df <- structure(list(supp_date = structure(c(17366, 17385, 17417, 17469, 
17478, 17507), class = "Date"), tablet = c(30L, 30L, 30L, 30L, 
30L, 30L)), .Names = c("supp_date", "tablet"), row.names = c(NA, 
 -6L), class = "data.frame")
like image 173
akrun Avatar answered Oct 17 '25 01:10

akrun