如何在R语言中筛选事件前后行子集并处理重叠事件
筛选事件前后行并处理重叠与完整性问题
需求说明
给定包含参与者id、事件标记event(1表示事件发生)、关注变量x的数据框,需要:
- 提取每个
event对应的前后2行(含事件本身)共5行的数据 - 处理两个问题:部分事件的筛选行存在重叠,首尾事件的行集不完整
- 优先实现:移除重叠事件,仅保留无重叠的完整行集(优先保留先发生的事件);若无法实现则保留所有行,优先给先发生的事件标记
cum_id,后续重叠事件保留不完整行
示例数据
df <- structure(list(id = c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2), event = c(1L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 1L, 0L), x = c(-0.524745604197535, 0.56664753932467, 1.06326937193775, -1.74261927944691, -1.70220588525303, 0.788056468394497, -0.315524780669081, -1.09956621127396, 0.725332798657826, -0.821455118910762, -0.305075137324048, 0.0975277444454113, -1.37607536240115, -1.1749745326815, -0.0254452552627888, 0.0291714672416614, -0.560221734093268, -0.832517971223058, 1.01067311827293, -0.0101155699102594, -2.211772959964, -0.324879965548731, 0.189774016276101, -0.124110438315279, 0.87450859784393, 0.534102255268043, 0.483572995043595, 0.717566852172195, 0.62058456685663, 0.100291898582953, -1.97147667641014, 0.390331677978558, -2.44481260988607, -1.08221493718706, 1.282044558805, 1.46339582810391, -0.388529539761603, -1.0347479743086, -0.244983560420757, -0.745529649917578, -0.581202927866314, -0.0468146194831979, 0.353756786882484, 0.726051987010529, 0.785563528600549, 0.234591665330184, 0.661859569057452, 0.718155884148953, 1.02606212190121, 0.35208377496606 )), row.names = c(NA, -50L), class = "data.frame")
方案一:移除重叠事件,保留无重叠的完整行集
实现思路
- 为数据添加行号,定位每个事件的位置
- 计算每个事件的行范围(事件行号±2),并标记是否为完整的5行集(即范围不超出当前参与者的行边界)
- 按参与者分组,优先保留先发生的、无重叠的完整事件
- 提取对应行并添加
cum_id
代码实现
library(dplyr) library(purrr) # 添加行号 df <- df %>% mutate(row_num = row_number()) # 提取事件的行范围及完整性标记 event_ranges <- df %>% filter(event == 1) %>% group_by(id) %>% mutate( start = row_num - 2, end = row_num + 2, is_complete = start >= min(row_num) & end <= max(row_num) ) %>% ungroup() # 筛选无重叠的完整事件 selected_events <- event_ranges %>% group_by(id) %>% arrange(row_num) %>% mutate( # 检查当前事件与已保留事件是否重叠 overlap = map_lgl(row_number(), function(i) { if (i == 1) return(FALSE) any((start <= lag(end, n = i-1)) & (end >= lag(start, n = i-1))) }) ) %>% filter(is_complete & !overlap) %>% ungroup() # 提取最终结果并添加cum_id result1 <- df %>% inner_join(selected_events %>% select(id, start, end), by = "id") %>% filter(row_num >= start & row_num <= end) %>% group_by(id) %>% mutate(cum_id = cumsum(event == 1)) %>% ungroup() %>% select(id, cum_id, event, x) # 查看结果 print(result1)
方案二:保留所有行,优先标记先发生事件
实现思路
- 为数据添加行号,标记每个事件的
cum_id - 按事件发生顺序,为每个事件的行范围分配
cum_id,重叠行优先归属到先发生的事件 - 保留所有行,最终按参与者和行号排序
代码实现
library(dplyr) library(data.table) # 转换为data.table方便批量处理 setDT(df) df[, row_num := .I] # 标记每个事件的cum_id events <- df[event == 1, .(id, event_row = row_num, cum_id = seq_len(.N)), by = id] # 为行分配cum_id,优先覆盖未标记的行 df[, cum_id := NA_integer_] for (i in seq(nrow(events))) { id_i <- events$id[i] start <- events$event_row[i] - 2 end <- events$event_row[i] + 2 df[id == id_i & row_num >= start & row_num <= end & is.na(cum_id), cum_id := events$cum_id[i]] } # 整理结果并排序 result2 <- df[order(id, row_num), .(id, cum_id, event, x)] # 查看结果 print(result2)
内容的提问来源于stack exchange,提问作者socialresearcher
相关产品推荐
相关产品推荐

