3

Here is my example:

library(dplyr)
my_df <- data.frame(col_1 = c(1,2,4), col_2 = c('2017-12-1', '2015-11-2', '2011-2-5'))
my_df$col_2 <- as.POSIXct(my_df$col_2)
out <- ifelse(my_df$col_1 ==2, my_df$col_2+ as.difftime(3, units = 'days'), NA)
print(out)

It produces:

NA 1446703200         NA

So coercion happens because of different data type. What NA datatype should I use to prevent it: NA_date_ or NA_POSIX_ or ...?

Henrik
  • 61,039
  • 13
  • 131
  • 152
user1700890
  • 6,206
  • 15
  • 77
  • 160

3 Answers3

1

It may be better to do this stepwise with assignment instead of ifelse.

1) Create an index

i1 <- my_df$col_1 == 2

2) Assign values based on the index

my_df$col_2[i1] <- my_df$col_2[i1] + as.difftime(3, units = 'days')

3) Change other elements to NA

my_df$col_2[!i1] <- NA
my_df
#  col_1      col_2
#1     1       <NA>
#2     2 2015-11-05
#3     4       <NA>

The reason is that POSIXct storage mode is numeric, within ifelse it gets coerced to the numeric form


If we are using tidyverse, then

library(tidyverse)
my_df %>%
    mutate(col_2 =  col_2 + days(3), 
           col_2 = replace(col_2, col_1 != 2, NA))
akrun
  • 789,025
  • 32
  • 460
  • 575
1

data.table makes it easy to modify specific rows

require(data.table)
my_df <- data.frame(col_1 = c(1,2,4), col_2 = c('2017-12-1', '2015-11-2', '2011-2-5'))
setDT(my_df)
my_df[, col_2 := as.POSIXct(col_2)
      ][col_1 == 2, col_2 := col_2 + as.difftime(3, units = 'days')
      ][col_1 != 2, col_2 := NA]
IceCreamToucan
  • 26,789
  • 2
  • 15
  • 32
1

Because you (for some reason ;)) have loaded dplyr, you may use if_else and wrap the false NA in as.POSIXct*:

if_else(my_df$col_1 == 2, my_df$col_2 + as.difftime(3, units = 'days'), as.POSIXct(NA))
# [1] NA               "2015-11-05 CET" NA 

*See ?as.POSIXct:

Logical NAs can be converted to either of the classes [POSIXlt and POSIXct]


Related question:

How to prevent ifelse() from turning Date objects into numeric objects. See also the comment by @roarkz and my answer.

Henrik
  • 61,039
  • 13
  • 131
  • 152