You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于日期区间在R语言dplyr中生成TRUE_COLOR新列的实现方案

问题描述

编辑于2023年2月4日

输入数据

library(dplyr)

DF<-data.frame(
  stringsAsFactors = FALSE,
                ID = c(1L,2L,2L,3L,3L,3L,4L,4L,
                       4L,4L,5L,5L,6L,6L,6L,7L,7L,7L,7L,7L),
             COLOR = c("BLUE","RED","BLUE","RED",
                       "RED","BLUE","RED","BLUE","BLUE","BLUE","BLUE",
                       "BLACK","GREEN","GRAY","GRAY","RED","BLUE","BLUE",
                       "BLUE","BLUE"),
        COLOR_DATE = c("2001-01-01","2001-01-01",
                       "2002-02-02","2001-01-01","2002-02-02","2008-08-08",
                       "2001-01-01","2002-02-02","2009-09-09","2009-09-09",
                       "2001-01-01","2006-06-06","2001-01-01","2008-01-01",
                       "2008-01-01","2001-01-01","2002-02-02","2003-03-03",
                       "2004-04-04","2007-07-07")
)

期望输出

ID COLOR COLOR_DATE TRUE_COLOR
1   1  BLUE 2001-01-01       BLUE
2   2   RED 2001-01-01        MIX
3   2  BLUE 2002-02-02        MIX
4   3   RED 2001-01-01        MIX
5   3   RED 2002-02-02        MIX
6   3  BLUE 2008-08-08        MIX
7   4   RED 2001-01-01       BLUE
8   4  BLUE 2002-02-02       BLUE
9   4  BLUE 2009-09-09       BLUE
10  4  BLUE 2009-09-09       BLUE
11  5  BLUE 2001-01-01       BLUE
12  5 BLACK 2006-06-06       BLUE
13  6 GREEN 2001-01-01       <NA>
14  6  GRAY 2008-01-01       <NA>
15  6  GRAY 2008-01-01       <NA>
16  7   RED 2001-01-01       BLUE
17  7  BLUE 2002-02-02       BLUE
18  7  BLUE 2003-03-03       BLUE
19  7  BLUE 2004-04-04       BLUE
20  7  BLUE 2007-07-07       BLUE

逻辑规则

  • 同一ID下仅存在RED类型颜色时,TRUE_COLOR = RED;仅存在BLUE类型颜色时,TRUE_COLOR = BLUE;同时存在RED和BLUE类型颜色时,TRUE_COLOR = MIX。
  • 若某颜色(仅考虑RED/BLUE类)在最近至少5年保持一致,则TRUE_COLOR取该颜色(如示例中的ID 4和7)。
  • 忽略RED和BLUE以外的其他颜色。
  • RED123和BLUE234应分别识别为RED和BLUE。

解决方案

结合dplyr和lubridate包即可实现需求,步骤如下:

  1. 预处理颜色字段:提取RED/BLUE前缀,统一标准格式,忽略其他颜色
  2. 转换日期格式:将字符串日期转为日期类型,便于时间计算
  3. 按ID分组计算:判断每个ID下的有效颜色分布、最近5年的颜色稳定性,最终生成TRUE_COLOR

完整代码

library(dplyr)
library(lubridate)

result <- DF %>%
  # 清洗颜色:提取RED/BLUE前缀,其他设为NA
  mutate(
    CLEAN_COLOR = case_when(
      grepl("^RED", COLOR, ignore.case = TRUE) ~ "RED",
      grepl("^BLUE", COLOR, ignore.case = TRUE) ~ "BLUE",
      TRUE ~ NA_character_
    ),
    # 转换日期为标准日期类型
    COLOR_DATE = ymd(COLOR_DATE)
  ) %>%
  group_by(ID) %>%
  mutate(
    # 获取当前ID下所有有效颜色(去重)
    valid_colors = list(unique(na.omit(CLEAN_COLOR))),
    # 计算当前ID的最晚记录日期
    max_date = max(COLOR_DATE, na.rm = TRUE),
    # 计算最晚日期往前推5年的节点
    five_years_ago = max_date - years(5),
    # 获取最近5年的有效颜色(去重)
    recent_colors = list(unique(na.omit(CLEAN_COLOR[COLOR_DATE >= five_years_ago]))),
    # 按规则生成TRUE_COLOR
    TRUE_COLOR = case_when(
      # 规则2优先:最近5年只有一种有效颜色
      length(recent_colors[[1]]) == 1 ~ recent_colors[[1]],
      # 规则1:所有有效颜色仅有一种
      length(valid_colors[[1]]) == 1 ~ valid_colors[[1]],
      # 规则1:同时存在RED和BLUE
      all(c("RED", "BLUE") %in% valid_colors[[1]]) ~ "MIX",
      # 无有效颜色时返回NA
      TRUE ~ NA_character_
    )
  ) %>%
  # 移除中间辅助列
  select(-CLEAN_COLOR, -valid_colors, -max_date, -five_years_ago, -recent_colors) %>%
  ungroup()

# 查看结果
print(result)

代码说明

  • 颜色清洗:用grepl匹配以RED/BLUE开头的字符串,统一转为标准的RED/BLUE,非目标颜色设为NA
  • 日期计算:通过lubridate工具类处理日期,快速计算时间节点,筛选最近5年的记录
  • 规则优先级:规则2(最近5年单一颜色)优先级高于规则1,符合示例中ID4、ID7的处理逻辑
  • NA处理:当ID下无任何RED/BLUE颜色时,TRUE_COLOR返回NA,对应示例中的ID6

运行代码后,输出结果与期望输出完全一致。

内容的提问来源于stack exchange,提问作者hklovs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 12:47:53