如何为每个ID标记当日最后报告(含午夜后提交的记录)
问题描述
我有如下结构的tibble数据:
# 数据预览 A tibble: 30 x 4 id index day time <dbl> <int> <int> <chr> 1 238686 1 1 11:53:33 2 238686 2 1 17:45:27 3 238686 3 1 21:12:36 4 238686 4 2 00:32:36 5 238686 5 2 11:07:08 6 238686 6 2 14:43:41 7 238686 7 2 20:50:29 8 238686 8 2 23:22:33 9 238686 9 3 12:05:53 10 238686 10 3 14:48:50
字段说明:
id:参与者ID,每位参与者在10天研究期内每日提交多份报告index:参与者在整个研究中的报告连续编号day:研究天数time:报告提交时间
我需要新增last变量,标记每个参与者当日的最后一份报告。之前用以下代码实现:
ex_data <- ex_data |> mutate(last=as.integer(max(index) == index), .by = c(id, day))
但发现部分参与者的当日最后报告是在午夜后提交的(比如研究day2的00:32:36实际属于研究day1的最后报告)。我已经用以下代码标记了午夜时段(00:00:00-03:00:00)的记录:
ex_data$time2<-as.hms(ex_data$time) ex_data <- ex_data |> mutate(nighttime = if_else(time2 >= parse_hms("00:00:00") & time2 < parse_hms("03:00:01"), 1, 0))
现在需要调整逻辑,创建last变量,同时覆盖午夜前和午夜后提交的当日最后报告,期望结果示例如下:
id index day time last 238686 1 1 11:53:33 0 238686 2 1 17:45:27 0 238686 3 1 21:12:36 0 238686 4 2 00:32:36 1 238686 5 2 11:07:08 0 238686 6 2 14:43:41 0 238686 7 2 20:50:29 0 238686 8 2 23:22:33 1 238686 9 3 12:05:53 0
完整数据结构:
ex_data<- structure(list(id = c(238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 238686, 239297, 239297, 239297), index = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 33L, 34L, 35L, 36L, 37L, 1L, 2L, 3L), day = c(1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 10L, 10L, 1L, 1L, 1L), time = c("11:53:33", "17:45:27", "21:12:36", "00:32:36", "11:07:08", "14:43:41", "20:50:29", "23:22:33", "12:05:53", "14:48:50", "21:15:33", "12:09:46", "14:27:06", "18:01:24", "20:56:40", "23:17:18", "11:19:02", "17:32:18", "00:05:52", "11:45:11", "18:10:10", "20:08:09", "00:30:00", "11:17:36", "14:29:43", "18:12:06", "20:54:48", "23:20:32", "11:16:00", "17:26:45", "11:45:13", "14:30:26", "18:31:49", "20:31:42", "23:47:41", "14:16:07", "23:55:13", "11:16:34", "12:01:56", "14:33:38")), row.names = c(NA, -40L), class = c("tbl_df", "tbl", "data.frame"))
解决方案
核心思路是:先构建逻辑日期(把00:00-03:00的报告归为前一个研究日),再基于逻辑日期标记每个参与者的当日最后报告。
完整代码
library(dplyr) library(hms) ex_data <- ex_data |> # 转换时间为hms格式 mutate(time2 = as.hms(time)) |> # 构建逻辑日:00:00-03:00的报告归为前一天 mutate(logic_day = if_else(time2 < parse_hms("03:00:00"), day - 1, day), .by = id) |> # 标记每个逻辑日的最后报告 mutate(last = as.integer(index == max(index)), .by = c(id, logic_day)) |> # 可选:移除中间变量 select(-time2, -logic_day)
验证结果
运行代码后,查看目标片段:
ex_data |> slice(1:9)
输出结果与期望一致:
# A tibble: 9 × 5 id index day time last <dbl> <int> <int> <chr> <int> 1 238686 1 1 11:53:33 0 2 238686 2 1 17:45:27 0 3 238686 3 1 21:12:36 0 4 238686 4 2 00:32:36 1 5 238686 5 2 11:07:08 0 6 238686 6 2 14:43:41 0 7 238686 7 2 20:50:29 0 8 238686 8 2 23:22:33 1 9 238686 9 3 12:05:53 0
补充说明
- 如果研究日起始时间不是00:00,只需调整
logic_day的判断条件即可。 - 代码中使用的
.by参数需要dplyr 1.1.0及以上版本支持,若版本较低,可替换为group_by(id, logic_day)后执行mutate,最后调用ungroup()取消分组。
内容的提问来源于stack exchange,提问作者Sointu
相关产品推荐
相关产品推荐

