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

如何结合purrr::map与dplyr::mutate处理嵌套与非嵌套列

问题:基于嵌套数据框查找date之后的首个event_date

背景与需求

我正在推进一个双数据集结合的计算项目,df中的每个id在event数据集中对应0到3行记录。要求保留df的原始行数,找出每个id对应date之后的第一个event_date,同时要保留嵌套数据用于后续计算,希望通过purrr系列函数实现这个逻辑。

示例数据

df <- tibble::tribble(
  ~id,        ~date,
  1L, "2010-01-01", 
  2L, "2010-01-02",
  3L, "2010-01-03",
  4L, "2010-01-04",
  5L, "2010-01-05",
  6L, "2010-01-06",
  7L, "2010-01-07",
  8L, "2010-01-08",
  9L, "2010-01-09",
  10L, "2010-01-10"
) %>% dplyr::mutate(date = as.Date(date))

event <- tibble::tribble(
~id, ~event,  ~event_date,
1L,    "A", "2009-01-01",
1L,    "B", "2009-06-30",
2L,    "A", "2011-01-01",
4L,    "A", "2006-01-01",
4L,    "B", "2008-02-15",
4L,    "B", "2012-12-15",
8L,    "A", "2010-01-08",
9L,    "B", "2010-03-30"
) %>% dplyr::mutate(event_date = as.Date(event_date))

当前尝试与问题

为了保留df的行数,我用dplyr::nest_join生成了嵌套数据框:

df_nest <- dplyr::nest_join(df, event)

之后尝试用purrr::map2计算目标日期,但当所有event_date都小于等于date时,min()会因为没有有效输入而报错:

df_nest %>% 
  dplyr::mutate(
    first_event_after = purrr::map2(
      .x = event,
      .y = date,
      ~ if(length(.x$event_date) > 0){
        .x %>% filter(event_date > .y) %>% pull(event_date) %>% min()
      } else {NA}
    )
  ) -> df_nest_dates

我试过dplyr::rowwise()但没能写出对比event[["event_date"]]和date的逻辑。另外我有一个能得到结果的方案,但无法保留嵌套数据用于后续计算:

left_join(event, df) %>% filter(event_date > date) %>% arrange(date) %>% distinct(id, .keep_all = T) %>% left_join(df, .)

解决方案

方法1:优化map2逻辑,判断过滤后的数据长度

修改原代码,先提取过滤后的日期,判断是否有有效数据,再返回对应结果(用NA_Date_作为日期型空值,比普通NA更规范):

df_nest %>% 
  dplyr::mutate(
    first_event_after = purrr::map2(
      .x = event,
      .y = date,
      ~ {
        # 筛选当前date之后的event_date
        filtered_dates <- .x %>% dplyr::filter(event_date > .y) %>% dplyr::pull(event_date)
        # 根据筛选结果返回值
        if (length(filtered_dates) > 0) min(filtered_dates) else NA_Date_
      }
    )
  ) -> df_nest_dates

方法2:用slice_min简化逻辑

利用dplyr::slice_min直接选出最小的符合条件的日期,再用first()处理空结果(空时自动返回NA),代码更简洁:

df_nest %>% 
  dplyr::mutate(
    first_event_after = purrr::map2(
      .x = event,
      .y = date,
      ~ .x %>% 
        dplyr::filter(event_date > .y) %>% 
        # 选出最小的1个event_date,避免多值
        dplyr::slice_min(event_date, n = 1, with_ties = FALSE) %>% 
        dplyr::pull(event_date) %>% 
        # 空结果时返回NA
        dplyr::first()
    )
  )

方法3:结合rowwise与map

如果习惯按行处理的思路,可以用rowwise拆分后逐行计算:

df_nest %>% 
  dplyr::rowwise() %>% 
  dplyr::mutate(
    first_event_after = {
      filtered <- event %>% dplyr::filter(event_date > date) %>% dplyr::pull(event_date)
      if (length(filtered) > 0) min(filtered) else NA_Date_
    }
  ) %>% 
  dplyr::ungroup()

以上三种方法都能保留嵌套的event数据框,满足后续计算需求,同时解决了空输入导致的报错问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:40:40