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

R语言:高效计算DataFrame连续零值段的累计时间差

高效处理大规模时序数据的时间差计算需求

原始数据

拥有包含就诊ID、时间戳及对应数值的DataFrame:

df <- data.frame(encounterId = c(1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026, 1026),
chartTime = c("2015-09-16 14:11:00 CEST", "2015-09-16 14:13:00 CEST", "2015-09-16 15:00:00 CEST", "2015-09-16 15:08:00 CEST", "2015-09-16 16:00:00 CEST", "2015-09-16 16:22:00 CEST", "2015-09-16 17:00:00 CEST", "2015-09-16 17:41:00 CEST", "2015-09-16 18:00:00 CEST", "2015-09-16 18:01:00 CEST", "2015-09-16 19:00:00 CEST", "2015-09-16 19:53:00 CEST"),
value = c(2.0, 2.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 2.0))

当前已实现代码

已编写计算每行与下一行时间差的代码,但未满足最终需求:

df <- df %>%
  group_by(encounterId) %>%
  mutate(time_diff = as.numeric(difftime(lead(chartTime), chartTime), units = 'mins'))

核心需求

  • 计算每行与下一行的时间差(分钟为单位)
  • 当连续出现多个value=0的行时,仅在该连续段的第一个0行显示该段的累计时间差(即从该0行到下一个非0行的总时间差),后续0行的time_diff设为NA
  • 最后一行的time_diff为空(或NA)

预期结果

encounterIdchartTimevaluetime_diff
10262015-09-16 14:11:00 CEST22
10262015-09-16 14:13:00 CEST247
10262015-09-16 15:00:00 CEST08
10262015-09-16 15:08:00 CEST252
10262015-09-16 16:00:00 CEST222
10262015-09-16 16:22:00 CEST099
10262015-09-16 17:00:00 CEST0NA
10262015-09-16 17:41:00 CEST0NA
10262015-09-16 18:00:00 CEST0NA
10262015-09-16 18:01:00 CEST259
10262015-09-16 19:00:00 CEST253
10262015-09-16 19:53:00 CEST2

高效解决方案

针对10亿行级别的大规模数据,必须使用向量化操作避免循环,以下提供两种高效实现方案:

方案1:dplyr + data.table 混合实现

library(dplyr)
library(data.table)

# 转换时间类型,确保时区正确
df <- df %>%
  mutate(chartTime = as.POSIXct(chartTime, tz = "Europe/Paris")) %>%
  group_by(encounterId) %>%
  # 生成连续相同value的分组ID
  mutate(grp = rleid(value)) %>%
  # 计算每个分组的结束时间:0分组取下一个非0行的时间,非0分组取下一行时间
  mutate(end_time = case_when(
    value == 0 ~ {
      next_non_zero_pos <- which(lead(value) != 0)[1]
      if (is.na(next_non_zero_pos)) last(chartTime) else lead(chartTime, n = next_non_zero_pos)
    },
    TRUE ~ lead(chartTime)
  )) %>%
  # 计算时间差
  mutate(time_diff = as.numeric(difftime(end_time, chartTime, units = "mins"))) %>%
  # 连续0分组的非第一行设为NA
  mutate(time_diff = ifelse(value == 0 & row_number() != first(row_number()), NA, time_diff)) %>%
  # 最后一行设为NA
  mutate(time_diff = ifelse(row_number() == n(), NA, time_diff)) %>%
  # 移除辅助列
  select(-grp, -end_time) %>%
  ungroup()

方案2:data.table 纯实现(性能更优)

data.table的内存管理和运算效率更适合超大规模数据:

library(data.table)

setDT(df)
# 转换时间类型
df[, chartTime := as.POSIXct(chartTime, tz = "Europe/Paris")]
# 按encounterId分组,生成连续相同value的分组ID
df[, grp := rleid(value), by = encounterId]

# 计算每个分组的结束时间
df[, end_time := {
  if (value[1] == 0) {
    next_non_zero <- which(shift(value, type = "lead") != 0)[1]
    if (is.na(next_non_zero)) last(chartTime) else chartTime[next_non_zero]
  } else {
    shift(chartTime, type = "lead")
  }
}, by = .(encounterId, grp)]

# 计算时间差
df[, time_diff := as.numeric(difftime(end_time, chartTime, units = "mins"))]
# 连续0分组的非第一行设为NA
df[value == 0 & seq_len(.N) != 1, time_diff := NA, by = .(encounterId, grp)]
# 每个encounterId的最后一行设为NA
df[.N, time_diff := NA, by = encounterId]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 05:17:10