Reputation: 6874
I have a dataframe with a column for the date and a text column called Rule.
If the text in the Rule Column is "Rule_1
" I want to add 3 years to the date in that row, but if "Rule_2
" then two years.
Date Rule NewDate
2010-01-01 Rule_1 2013-01-01
2012-01-01 Rule_2 2014-01-01
2015-01-01 No_Rule 2015-01-01
I seem to have a problem with adding the year using lubridate
ifelse(df$Rule=="Rule1",df$Date %m+% years(3),df$Date)
It converts the added date to a number which I think is the number of days from an origin (?1970).
However if I run the expression df$Date %m+% years(3)
without ifelse then it works fine. What to do?
Upvotes: 1
Views: 923
Reputation: 3670
Since you're already using one tidyverse
package (lubridate
) how about case_when
from dplyr
? It's a vectorized if
- and basically allows you to avoid a bunch of nested ifelse
statements if you have multiple conditions.
library(dplyr)
df %>%
mutate(NewDate_Demo = case_when(Rule == "Rule_1" ~ Date %m+% years(3),
Rule == "Rule_2" ~ Date %m+% years(2),
TRUE ~ Date))
# A tibble: 3 x 4
Date Rule NewDate NewDate_Demo
<date> <chr> <date> <date>
1 2010-01-01 Rule_1 2013-01-01 2013-01-01
2 2012-01-01 Rule_2 2014-01-01 2014-01-01
3 2015-01-01 No_Rule 2015-01-01 2015-01-01
dplyr
does also offer if_else
, which has the same general syntax as base::ifelse
but won't break with lubridate
https://github.com/tidyverse/lubridate/issues/644
Upvotes: 2
Reputation: 6954
The base ifelse function is not type stable. Rather make use if the dplyr implementation if_else()
. This automatically checks and retains the desired output type.
From its documentation:
Compared to the base ifelse(), this function is more strict. It checks that true and false are the same type. This strictness makes the output type more predictable, and makes it somewhat faster.
library(dplyr)
library(lubridate)
# never mix up tidyverse and data.table but damn, fread() is awesome :D
df <- data.table::fread("
Date Rule NewDate
2010-01-01 Rule_1 2013-01-01
2012-01-01 Rule_2 2014-01-01
2015-01-01 No_Rule 2015-01-01") %>%
as_tibble() %>%
mutate_at(.vars = c(1, 3), as_date)
# more type stable ifelse
dplyr::if_else(df$Rule=="Rule_1", df$Date %m+% years(3), df$Date)
# desired output with nested if_else
# faster than case_when()
dplyr::if_else(df$Rule=="Rule_1", df$Date %m+% years(3),
if_else(df$Rule=="Rule_2", df$Date %m+% years(2), df$Date))
# piped dplyr way
df %>%
mutate(desired_date = if_else(Rule == "Rule_1",
true = Date %m+% years(3),
false = if_else(Rule == "Rule_2",
true = Date %m+% years(2),
false = Date)))
Upvotes: 1