使用tidyverse风格调用自定义日期函数后日期格式异常如何解决?
问题原因
你的fix_date_all函数用lapply处理日期向量后,返回的是列表类型。而mutate(across(...))期望接收向量类型的数据,当列表传入时,Date对象会被强制转换为底层的整数(即从1970-01-01开始计算的天数),这就是你看到那些奇怪数字的原因。
解决方案
方法1:修改原函数,返回向量而非列表
把函数里的lapply替换成能返回向量的函数,比如sapply或者purrr::map_vec:
# 修改后的fix_date_all fix_date_all <- function(date){ fix_date <- function(d) { if (nchar(d) != 8) d <- paste0("0", d) dd <- substr(d, 1,2) mm <- substr(d, 3,4) yyyy <- substr(d, 5,8) as.Date(paste0(dd, ".", mm, ".", yyyy), "%d.%m.%Y") } # 用sapply替换lapply,自动简化为向量 sapply(date, fix_date) } # 现在用across调用就正常了 df %>% mutate(across(date, fix_date_all))
方法2:重写为向量化函数(更符合tidyverse风格)
直接写向量化的逻辑,避免嵌套循环,效率更高:
fix_date_vec <- function(date) { # 给不足8位的日期补前导0 date_padded <- if_else(nchar(date) != 8, paste0("0", date), date) # 拆分日、月、年 dd <- substr(date_padded, 1, 2) mm <- substr(date_padded, 3, 4) yyyy <- substr(date_padded, 5, 8) # 转换为Date类型 as.Date(paste(dd, mm, yyyy, sep = "."), "%d.%m.%Y") } # 调用方式 df %>% mutate(across(date, fix_date_vec))
方法3:直接在mutate里写逻辑(更简洁)
如果不需要复用函数,也可以直接在mutate里完成转换:
df %>% mutate( date = if_else(nchar(date) != 8, paste0("0", date), date) %>% {paste(substr(.,1,2), substr(.,3,4), substr(.,5,8), sep=".")} %>% as.Date("%d.%m.%Y") )
验证结果
以上三种方法运行后,都会得到正确的Date格式列:
date x1 x2 1 2016-10-18 1 1 2 2017-10-11 2 1 3 2017-05-04 3 1 4 2018-10-18 4 1 5 2018-10-03 5 1
内容的提问来源于stack exchange,提问作者DuesserBaest
相关产品推荐
相关产品推荐

