在R中合并连续action为"o"的重复记录并保留指定时间值
在R中合并用户连续的
action="o"记录 针对你提出的需求——合并同一user_id下连续的action="o"记录(保留第一条的start_time和最后一条的end_time,其他action保持原状),以下是两种高效的实现方案:
准备示例数据
首先把你提供的示例数据转换成R可处理的数据结构:
# 先安装需要的包:install.packages("tidyverse") 或 install.packages("data.table") library(tidyverse) # 或者用data.table:library(data.table) # 构建示例数据集 df <- tibble( user_id = c("11", "11", "11", "11", "11", "11", "11", "22", "22", "22", "22", "22"), action = c("o", "o", "o", "v", "v", "o", "o", "o", "o", "v", "o", "z"), start_time = c("23:25:27", "23:25:28", "23:25:48", "23:25:49", "23:25:49", "23:28:24", "00:10:48", "00:11:52", "00:22:32", "00:22:42", "00:22:42", "00:22:42"), end_time = c("23:25:49", "23:25:28", "23:26:50", "23:25:49", "23:25:50", "00:22:33", "00:23:44", "00:22:33", "00:27:44", "00:22:42", "00:22:42", "00:22:43") )
方案一:使用dplyr(tidyverse生态)
核心思路是给连续的action="o"记录打上同一分组标签,再按标签聚合:
df_merged <- df %>% # 按user_id分组,确保只处理同一用户内的连续记录 group_by(user_id) %>% # 创建分组标识:当当前行不是"o",或者当前是"o"但前一行不是"o"时,开启新分组 mutate( group_tag = cumsum( action != "o" | (action == "o" & lag(action, default = "") != "o") ) ) %>% # 按user_id、group_tag、action分组,聚合时间字段 group_by(user_id, group_tag, action) %>% summarise( start_time = first(start_time), # 取分组内第一条的start_time end_time = last(end_time), # 取分组内最后一条的end_time .groups = "drop" # 取消分组,返回普通数据框 ) %>% select(-group_tag) # 移除临时分组标签列 # 查看结果 print(df_merged, n = Inf)
执行后会得到你期望的输出:
# A tibble: 8 × 4 user_id action start_time end_time <chr> <chr> <chr> <chr> 1 11 o 23:25:27 23:26:50 2 11 v 23:25:49 23:25:49 3 11 v 23:25:49 23:25:50 4 11 o 23:28:24 00:23:44 5 22 o 00:11:52 00:27:44 6 22 v 00:22:42 00:22:42 7 22 o 00:22:42 00:22:42 8 22 z 00:22:42 00:22:43
方案二:使用data.table(适合大型数据集)
如果你的数据集非常大,data.table的处理速度会更有优势,它的rleid函数可以快速生成连续分组的标识:
library(data.table) # 转换为data.table格式 setDT(df) # 分组聚合 df_merged <- df[, # 对每个分组,取第一条start_time和最后一条end_time .(start_time = first(start_time), end_time = last(end_time)), # 分组依据:user_id、action,以及连续"o"的分组标识 by = .(user_id, action, grp = rleid(action == "o")) ][, grp := NULL] # 删除临时分组列 # 查看结果 print(df_merged)
这个方案的输出和上面完全一致,而且对于百万级以上的大型数据集,性能会显著优于dplyr。
注意事项
- 如果你的
start_time和end_time是时间类型(比如POSIXct),上述代码不需要任何修改,first()和last()函数依然有效。 - 如果数据原本没有按时间排序,建议先在分组前添加
arrange(start_time)确保记录是按时间顺序处理的。
内容的提问来源于stack exchange,提问作者Cina
相关产品推荐
相关产品推荐

