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

基于条件的日期变量计算求助:修正药物服用截止日期

问题:药物服用截止日期计算错误修正

问题说明

现有包含ID、MedicationDate(购药日期)、NumberOfPackages(购药数量)的数据集,需计算LastDate(药物服用截止日期),规则为:1包药物可使用1个月。

  • 若本次购药日期晚于或等于上次药物用完日期,LastDate = 购药日期 + 购药数量对应的月份
  • 若本次购药日期早于上次药物用完日期,LastDate = 购药日期 + 购药数量对应的月份 + 上次剩余天数

当前代码在处理最后一行数据时出错,正确结果应为2013-04-23,但代码输出为2013-04-02。


原始数据

ID    MedicationDate   NumberOfPackages
 X001   2011-01-12             3    
 X001   2011-01-12             3    
 X001   2011-01-12             3    
 X001   2013-02-23             1    
 X001   2013-03-02             1    

当前错误输出

ID    MedicationDate   NumberOfPackages     LastDate
 X001   2011-01-12             3             2011-04-12
 X001   2011-01-12             3             2011-04-12
 X001   2011-01-12             3             2011-04-12
 X001   2013-02-23             1             2013-03-23
 X001   2013-03-02             1             2013-04-02

有效单行测试代码

as.Date("2013-03-02") %m+% months(1) %m+% days(as.numeric(difftime(as.Date("2013-03-23"),as.Date("2013-03-02"), units = "days")))

当前失效代码

library(lubridate)

test <- test %>%
  group_by(ID) %>%
  arrange(MedicationDate) %>%
  mutate(LastDate =
           case_when(
             lag(MedicationDate) == MedicationDate | is.na(lag(LastDate)) | lag(LastDate) <= MedicationDate ~ as.Date(MedicationDate) %m+% months(NumberOfPackages),
             TRUE ~ as.Date(MedicationDate) %m+% months(NumberOfPackages) %m+% days(as.numeric(difftime(as.Date(lag(LastDate)),as.Date(MedicationDate), units = "days"))) 
           ) 
  ) 

修正方案

问题核心:mutate中使用lag(LastDate)无法实时获取前一行刚计算出的LastDate值,因为mutate是批量计算列,而非逐行递推。需要用累积计算的方式处理依赖前一行结果的场景,这里使用purrr::accumulate实现递推逻辑。

修正后代码:

library(lubridate)
library(purrr)
library(dplyr)

test <- test %>%
  group_by(ID) %>%
  arrange(MedicationDate) %>%
  mutate(
    LastDate = accumulate(
      .x = seq_along(MedicationDate),
      .f = function(prev_last, i) {
        current_date <- MedicationDate[i]
        current_packs <- NumberOfPackages[i]
        # 第一行或同日期购药,直接计算截止日期
        if (i == 1 || MedicationDate[i] == MedicationDate[i-1]) {
          current_date %m+% months(current_packs)
        } else {
          # 比较当前购药日期与上次截止日期
          if (current_date >= prev_last) {
            current_date %m+% months(current_packs)
          } else {
            # 加上上次剩余的天数
            current_date %m+% months(current_packs) %m+% days(as.numeric(difftime(prev_last, current_date, units = "days")))
          }
        }
      },
      .init = as.Date(NA)
    ) %>% tail(-1)  # 去掉.init生成的NA
  )

修正后结果

ID    MedicationDate NumberOfPackages LastDate  
  <chr> <date>                    <dbl> <date>    
1 X001  2011-01-12                   3 2011-04-12
2 X001  2011-01-12                   3 2011-04-12
3 X001  2011-01-12                   3 2011-04-12
4 X001  2013-02-23                   1 2013-03-23
5 X001  2013-03-02                   1 2013-04-23

内容的提问来源于stack exchange,提问作者reaq-br4

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 04:00:34