as.Date使用ifelse覆盖旧日期时返回数字的原因及解决方法
问题成因与解决方案
嘿,这个坑我之前踩过!咱们一步步拆解:
为什么会出现数字而不是日期?
核心问题出在基础R的ifelse()函数的类型转换特性:
- Date类型在R底层其实是存储为整数的(以
1970-01-01为原点的天数,正数是该日期之后,负数是之前)。 ifelse()会自动把输出转换成所有分支里「最通用」的数据类型,这里它直接把Date对象的底层整数暴露出来了——你看到的18241就是2019-12-11距离1970年元旦的天数,-25222则是1900-12-12对应的负数天数。- 更糟的是,这会把整个
datum列的Date属性完全丢掉,变成纯整数列。
正确的修改方法
推荐用dplyr提供的类型安全函数,避免这种意外:
方法1:用dplyr::if_else()(最推荐)
if_else()会严格检查两个分支的类型一致性,保留Date属性,不会偷偷转换:
tel <- data.frame(s = c(1,2,3)) tel <- tel %>% mutate(datum = as.Date("19001212", "%Y%m%d")) tel <- tel %>% mutate(datum = if_else(s == 1, as.Date("20191211", "%Y%m%d"), datum))
运行后你会发现datum还是Date类型,s=1的行正确显示2019-12-11,其他行保留1900-12-12。
方法2:用case_when()(适合多条件场景)
如果之后需要添加更多条件,case_when()更灵活,同样保留Date类型:
tel <- tel %>% mutate(datum = case_when( s == 1 ~ as.Date("20191211", "%Y%m%d"), # 可以在这里加更多条件 TRUE ~ datum # 其他情况保留原日期 ))
方法3:用基础R的ifelse()但手动转类型(不推荐)
如果一定要用基础R的ifelse(),需要把结果重新转回Date类型,记得指定原点:
tel <- tel %>% mutate(datum = as.Date(ifelse(s == 1, as.Date("20191211", "%Y%m%d"), datum), origin = "1970-01-01"))
这种方式容易出错(比如忘记写origin),所以优先推荐前两种dplyr的方法。
内容的提问来源于stack exchange,提问作者SecretIndividual
相关产品推荐
相关产品推荐

