ifelse 和 POSIXct:NA 的强制和默认 class

ifelse and POSIXct: coercion and default class of NA

这是我的例子:

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)

它产生:

NA 1446703200         NA

所以强制转换是由于不同的数据类型而发生的。我应该使用什么 NA 数据类型来防止它:NA_date_NA_POSIX_ 或...?

使用赋值逐步执行此操作可能比 ifelse 更好。

1) 创建索引

i1 <- my_df$col_1 == 2

2) 根据索引赋值

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

3) 将其他元素改为NA

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

原因是 POSIXct 存储模式是 numeric,在 ifelse 中它被强制转换为 numeric 形式


如果我们使用 tidyverse,那么

library(tidyverse)
my_df %>%
    mutate(col_2 =  col_2 + days(3), 
           col_2 = replace(col_2, col_1 != 2, NA))

data.table 可以轻松修改特定行

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]

因为您(出于某种原因 ;))已经加载了 dplyr,您可以使用 if_else 并将 false NA 包装在 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 

*参见?as.POSIXct:

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


相关问题:

How to prevent ifelse() from turning Date objects into numeric objects. See also the comment by @roarkz 和我的回答。