如何在data.table中按条件生成含最早日期的新列
问题:基于data.table实现分组标记与最小日期计算
数据
library(data.table) ALPHA_DEF <- c("ABCD","EFGH") DT <- data.table( ID = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L), C_OPR = c("ABCD01", "ABCD11", NA, "EFGH", NA, NA, "KLMN", NA), D_OPR = c(NA, NA, "PQRST", NA, "EFGHIJ", NA, NA, NA), DATE = c("2002-02-02","2005-05-05","2001-01-01", "2003-03-03","2004-04-04",NA,"2001-01-01",NA)) DT
输出结果:
ID C_OPR D_OPR DATE 1: 1 ABCD01 <NA> 2002-02-02 2: 1 ABCD11 <NA> 2005-05-05 3: 1 <NA> PQRST 2001-01-01 4: 2 EFGH <NA> 2003-03-03 5: 2 <NA> EFGHIJ 2004-04-04 6: 2 <NA> <NA> <NA> 7: 3 KLMN <NA> 2001-01-01 8: 3 <NA> <NA> <NA>
期望输出
ID C_OPR D_OPR DATE ALPHA ALPHA_MIN_DATE 1: 1 ABCD01 <NA> 2002-02-02 1 2002-02-02 2: 1 ABCD11 <NA> 2005-05-05 1 2002-02-02 3: 1 <NA> PQRST 2001-01-01 1 2002-02-02 4: 2 EFGH <NA> 2003-03-03 1 2003-03-03 5: 2 <NA> EFGHIJ 2004-04-04 1 2003-03-03 6: 2 <NA> <NA> <NA> 1 2003-03-03 7: 3 KLMN <NA> 2001-01-01 0 <NA> 8: 3 <NA> <NA> <NA> 0 <NA>
逻辑规则
- 按ID分组,若该ID下任意
C_OPR或D_OPR包含ALPHA_DEF中的元素,ALPHA列值为1,否则为0; ALPHA_MIN_DATE为该ID下满足ALPHA条件的记录中的最小DATE值,不满足则为NA。
已有尝试(未实现ALPHA_MIN_DATE)
DT[, ALPHA := +any( grepl(paste0(ALPHA_DEF, collapse="|"),c(D_OPR, C_OPR)), by=ID]
解决方案
library(data.table) ALPHA_DEF <- c("ABCD","EFGH") # 构建正则模式,匹配以ALPHA_DEF元素开头的字符串 pattern <- paste0("^(", paste(ALPHA_DEF, collapse = "|"), ")") DT[, c("ALPHA", "ALPHA_MIN_DATE") := { # 标记每条记录是否匹配ALPHA_DEF,NA值视为不匹配 match_flag <- grepl(pattern, C_OPR, na.rm = TRUE) | grepl(pattern, D_OPR, na.rm = TRUE) # 分组判断是否存在匹配项,将逻辑值转为0/1 alpha_val <- +any(match_flag) # 计算匹配记录中的最小日期,无匹配则设为NA min_date <- if (alpha_val) { min(DATE[match_flag & !is.na(DATE)], na.rm = TRUE) } else { NA_character_ } # 返回两列结果 list(alpha_val, min_date) }, by = ID] # 查看最终结果 DT
代码说明
- 正则模式构建:用
^限定匹配开头,避免误匹配包含但不以ALPHA_DEF元素开头的内容; - 匹配标记:逐行判断
C_OPR或D_OPR是否符合规则,na.rm = TRUE处理NA值,避免判断出错; - 分组计算:
alpha_val通过+any(match_flag)将逻辑值转换为0/1格式;min_date仅在存在匹配项时,提取对应非空DATE的最小值,否则设为NA_character_,保持与原DATE列类型一致。
内容的提问来源于stack exchange,提问作者hklovs
相关产品推荐
相关产品推荐

