使用ifelse条件为日期加月份时返回数值而非日期的问题
问题描述
需求是根据条件为日期添加月份:当ISO列值为ET时,为日期添加92个月。
单独运行以下代码能得到正确的日期格式结果:
ymd(paste(comb_extract_all$hv007, comb_extract_all$hv006, "01", sep = "-")) %m+% months(92)
返回示例:
[1] "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" [9] "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" [17] "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" [25] "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01" "2011-04-01"
但将逻辑放入ifelse语句赋值给date列时,返回的是数值而非日期:
comb_extract_all$date <- ifelse(comb_extract_all$ISO == "ET", ymd(paste(comb_extract_all$hv007, comb_extract_all$hv006, "01", sep="-")) %m+% months(92), ymd(paste(comb_extract_all$hv007, comb_extract_all$hv006, "01", sep="-")))
相关数据的dput输出(可见date列异常):
dput(comb_extract_all[1:5,c(1,5,6,23,24)]) structure(list(hhid = c(" 1 27", " 1 27", " 1 27", " 1 27", " 1 67"), hv006 = c(8, 8, 8, 8, 8), hv007 = c(2003, 2003, 2003, 2003, 2003), ISO = c("ET", "ET", "ET", "ET", "ET" ), date = c(15065, 15065, 15065, 15065, 15065)), row.names = c("ETPR61SV.1", "ETPR61SV.2", "ETPR61SV.3", "ETPR61SV.4", "ETPR61SV.5"), class = "data.frame")
原因分析
Base R的ifelse()函数会自动简化返回值的类型,丢失日期对象(Date类)的属性,将其转换为底层的数值表示(从1970-01-01开始的天数)。
解决方案
提供三种可行的解决方法:
方法1:使用dplyr::if_else()
dplyr包的if_else()会保留对象的类型属性,比base R的ifelse()更严格:
library(dplyr) library(lubridate) comb_extract_all$date <- if_else(comb_extract_all$ISO == "ET", ymd(paste(comb_extract_all$hv007, comb_extract_all$hv006, "01", sep="-")) %m+% months(92), ymd(paste(comb_extract_all$hv007, comb_extract_all$hv006, "01", sep="-")))
方法2:先计算基础日期,再通过索引赋值
先统一生成基础日期列,再对符合条件的行添加月份:
library(lubridate) # 先创建基础日期列 comb_extract_all$date <- ymd(paste(comb_extract_all$hv007, comb_extract_all$hv006, "01", sep="-")) # 对ISO为ET的行添加92个月 comb_extract_all$date[comb_extract_all$ISO == "ET"] <- comb_extract_all$date[comb_extract_all$ISO == "ET"] %m+% months(92)
这种方法避免了ifelse()的类型丢失问题,逻辑更清晰。
方法3:将数值转换回日期类型
如果已经用ifelse()生成了数值列,可以手动转换回Date类:
comb_extract_all$date <- as.Date(comb_extract_all$date, origin = "1970-01-01")
内容的提问来源于stack exchange,提问作者Sulz
相关产品推荐
相关产品推荐

