1

I have a data frame. Here is a sample part.

Lines <- "Category    date
desktop     2017-12-25
tablet      2016-05-13
desktop     2018-06-01
desktop     2017-08-06
tablet      2015-12-31"
DF <- read.table(text = Lines, header = TRUE)
DF$date <- as.Date(DF$date)

There are more than 1000 rows in the data frame.

What I would like to do is: if the category is desktop, how can I add 2 years to the existing date? If the category is tablet, how can I add only 1 year to the existing date? Thank you for the help!

cutebunny
  • 769
  • 2
  • 9
  • 21

5 Answers5

2

If you have big data.frames, you can do:

library(lubridate)
library(data.table)

addYear = function(date, nyear){year(date)=year(date)+nyear; date}

setDT(df)[,date:=as.Date(date)][
          Category=='desktop', date:=addYear(date,2)][
          Category=='tablet', date:=addYear(date,1)]

#   Category       date
#1:  desktop 2019-12-25
#2:   tablet 2017-05-13
#3:  desktop 2020-06-01
#4:  desktop 2019-08-06
#5:   tablet 2016-12-31
Colonel Beauvel
  • 30,423
  • 11
  • 47
  • 87
2

This does not use any packages. The input data frame is DF . The code converts the date column to "POSIXlt" class in the first line giving lt, increments the year component of lt in the second line and converts lt back to "Date" class in the third line. (Note that the second line could easily be modified if additional categories were to be implemented by simply adding on more terms.)

lt <- as.POSIXlt(DF$date)
lt$year <- lt$year + 2 * (DF$Category == "desktop") + (DF$Category == "laptop")
DF$date <- as.Date(lt)

giving:

  Category       date
1  desktop 2019-12-25
2   tablet 2016-05-13
3  desktop 2020-06-01
4  desktop 2019-08-06
5   tablet 2015-12-31
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
1

Use ifelse:

library(readr)
library(lubridate)
library(dplyr)

dfX = read_table("Category    date
desktop     2017-12-25
tablet      2016-05-13
desktop     2018-06-01
desktop     2017-08-06
tablet      2015-12-31",
                 col_types = list(col_character(), col_date()))


dfX %>%
  mutate(date_new = ifelse(Category == "desktop", date + dyears(2), 
                           ifelse(Category == "tablet", date + dyears(1), date)))
tchakravarty
  • 10,736
  • 12
  • 72
  • 116
  • What output do you get from this? I get numeric for `date_new` because of this phenomenon: http://stackoverflow.com/questions/6668963/how-to-prevent-ifelse-from-turning-date-objects-into-numeric-objects. – Sam Firke Nov 10 '15 at 16:14
  • @SamFirke Had forgotten about that. Good catch. – tchakravarty Nov 10 '15 at 16:41
1

Or using only the lubridate package for its years() function:

library(lubridate)
DF$date[DF$Category == "desktop"] <- DF$date[DF$Category == "desktop"] + years(2)
DF$date[DF$Category == "tablet"] <- DF$date[DF$Category == "tablet"] + years(1)

> DF
  Category       date
1  desktop 2019-12-25
2   tablet 2017-05-13
3  desktop 2020-06-01
4  desktop 2019-08-06
5   tablet 2016-12-31
Sam Firke
  • 21,571
  • 9
  • 87
  • 105
0

This might be best done through merging.

library(dplyr)
library(lubridate)

additions = 
  data_frame(Category = c("desktop", "tablet"), 
             interval = c(2, 1))

data %>%
  left_join(additions) %>%
  mutate(date = ymd(date),
         interval = interval %>% as.period("year"),
         next_date = date + interval )
bramtayl
  • 4,004
  • 2
  • 11
  • 18
  • why not an ifelse - the merge is surely unneeded. – jeremycg Nov 10 '15 at 15:35
  • @jeremycg could you give me a ifelse solution? Thank you! – cutebunny Nov 10 '15 at 15:38
  • @jeremycg ifelse can be a hassle when adjusting date variables, see http://stackoverflow.com/questions/6668963/how-to-prevent-ifelse-from-turning-date-objects-into-numeric-objects. I agree the merge is overly complex for this example, though if there were many more than these 2 rules it could be a viable strategy. – Sam Firke Nov 10 '15 at 16:29
  • I think that the merge is useful not only because you can add as many rules as you want, but also because you can print or export the additions table or use it in other circumstances. Agreed that merge might not be the most efficient. – bramtayl Nov 10 '15 at 16:37