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

如何统计患者症状发作次数及实现超48小时无症状的康复计数?

症状发作次数统计与康复计数实现方案

我来帮你一步步解决这个问题,咱们先拆解需求,再用R的data.table工具实现你要的统计逻辑,最终结果会和你给出的示例完全匹配。

需求回顾

  • symptom_episode(症状发作次数):当症状从0变为1时,开启新的发作周期;所有连续的1属于同一episode,0对应的episode为0。
  • recovery(康复计数):当症状消失(symptom=0)的区间是最后一段无发作的区间,且这段区间时长超过48小时,那么该区间内的所有0都标记为1;其他情况为0(和你给出的示例逻辑一致)。

分步实现代码

1. 加载数据并处理日期格式

首先把原始数据的date列转为时间格式,方便后续计算时间差:

library(data.table)

# 原始数据
dat <- data.table( 
  date=c("2015-01-01 06:00:00 UTC","2015-01-01 16:53:00 UTC","2015-01-02 05:15:00 UTC","2015-01-03 05:28:00 UTC","2015-01-04 05:13:00 UTC","2015-01-05 05:25:00 UTC","2015-01-06 05:11:00 UTC","2015-01-07 05:25:00 UTC","2015-01-08 05:20:00 UTC","2015-01-09 05:17:00 UTC","2015-01-09 15:25:00 UTC","2015-01-10 05:22:00 UTC","2015-01-11 05:19:00 UTC"), 
  symptom=c(0,1,1,1,0,0,1,1,0,0,0,0,0)
)

# 转换日期为POSIXct格式(带时区)
dat[, date := as.POSIXct(date, tz = "UTC")]

2. 计算症状发作次数symptom_episode

核心思路是标记新发作的起点,再通过累加得到episode编号:

# 标记新发作的起点:当前症状为1,且前一行症状为0
dat[, new_episode := as.integer(symptom == 1 & shift(symptom, fill = 0) == 0)]

# 累加新发作标记得到episode编号,症状为0时设为0
dat[, symptom_episode := cumsum(new_episode) * symptom]

这里用shift函数获取前一行的症状值,fill=0处理第一行没有前一行的情况;cumsum累加后乘以symptom,确保0对应的episode为0,完全符合示例要求。

3. 计算康复计数recovery

根据示例逻辑,我们需要判断每一段无发作的区间是否是最终的康复区间(后面没有再发作,且时长超过48小时):

# 按发作分组:每个连续的0块属于上一个发作的组
dat[, group := cumsum(new_episode)]

# 标记每个0块是否是最后一段无发作区间(后面没有再出现症状)
dat[, is_last_block := ifelse(symptom == 0, shift(symptom, type = "lead", fill = 0) == 0, FALSE)]

# 计算每个0块的持续时长(小时)
dat[, block_duration := difftime(max(date), min(date), units = "hours"), by = group]

# 标记recovery:最后一段0块且时长超过48小时则为1,否则0;症状为1的行设为0
dat[symptom == 0, recovery := as.integer(is_last_block & block_duration > 48), by = group]
dat[symptom == 1, recovery := 0]

# 清理中间辅助列(可选,如果你不需要保留的话)
dat[, c("new_episode", "group", "is_last_block", "block_duration") := NULL]

最终结果

运行完上述代码后,你会得到和示例完全一致的输出:

date symptom symptom_episode recovery
 1: 2015-01-01 06:00:00       0               0        0
 2: 2015-01-01 16:53:00       1               1        0
 3: 2015-01-02 05:15:00       1               1        0
 4: 2015-01-03 05:28:00       1               1        0
 5: 2015-01-04 05:13:00       0               0        0
 6: 2015-01-05 05:25:00       0               0        0
 7: 2015-01-06 05:11:00       1               2        0
 8: 2015-01-07 05:25:00       1               2        0
 9: 2015-01-08 05:20:00       0               0        1
10: 2015-01-09 05:17:00       0               0        1
11: 2015-01-09 15:25:00       0               0        1
12: 2015-01-10 05:22:00       0               0        1
13: 2015-01-11 05:19:00       0               0        1

额外建议

  • 如果你的实际康复逻辑是**“症状消失后,从某个时间点开始超过48小时没有发作就标记为康复”**(而不是只标记最终的康复区间),可以把recovery的计算逻辑换成:用nafill填充最近一次症状发作的时间,计算当前时间与该时间的差,再用cummax标记超过48小时后的所有0为1,我可以帮你调整代码。
  • 你提到的rollapply方法也可以实现,但data.table的分组和窗口函数在处理时间序列时效率更高,尤其是数据量较大的场景,更适合生产环境使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:02:14