R语言中基于条件对指定列前3个非零值求和的优化实现问询
简洁实现R语言分组后取前3个非零历史值求和与计数
你要按a1分组、event_id降序排列后,对var1_stat和var2_stat的前3个非零历史值求和并统计数量,当前逐个定义滞后变量的写法太繁琐,下面给你两种更简洁的实现方式:
方案1:用dplyr+purrr(无需额外安装包)
library(dplyr) library(purrr) # 原始数据 a1 <- c('adam', 'adam', 'adam', 'adam', 'megan', 'megan', 'megan','jen', 'jen', 'jen', 'jen') event_id <- as.numeric(c('1', '2', '3', '6', '2', '4', '5', '1', '2', '4', '6')) var1_stat <- as.numeric(c('3.2', '2.1', '2.7', '0','2','3.3', '1.1', '0', '4.1', '2.2','3.1')) var2_stat <- as.numeric(c('3.4', '3', '0','1.7', '1.2', '3', '0','3.3', '2.1', '3.2', '0')) test_ex <- data.frame(a1, event_id, var1_stat, var2_stat) # 简洁实现 result <- test_ex %>% group_by(a1) %>% arrange(event_id, .by_group = TRUE) %>% # 先按event_id升序,让历史值排在当前行前面 mutate( # 处理var1:收集所有历史非零值,取前3个求和、计数 var1_sum3 = map_dbl(accumulate(var1_stat, ~c(.x, .y), .init = numeric(0)), ~sum(tail(.x, -1)[tail(.x, -1) != 0][1:3], na.rm = TRUE)), var1_count3 = map_dbl(accumulate(var1_stat, ~c(.x, .y), .init = numeric(0)), ~length(tail(.x, -1)[tail(.x, -1) != 0][1:3])), # 处理var2 var2_sum3 = map_dbl(accumulate(var2_stat, ~c(.x, .y), .init = numeric(0)), ~sum(tail(.x, -1)[tail(.x, -1) != 0][1:3], na.rm = TRUE)), var2_count3 = map_dbl(accumulate(var2_stat, ~c(.x, .y), .init = numeric(0)), ~length(tail(.x, -1)[tail(.x, -1) != 0][1:3])) ) %>% arrange(desc(event_id), .by_group = TRUE) %>% # 还原成event_id降序 ungroup() print(result)
方案2:用slider包(滑动窗口更直观)
如果习惯用滑动窗口逻辑,可以用slider包,代码更易懂:
library(dplyr) library(slider) result <- test_ex %>% group_by(a1) %>% arrange(event_id, .by_group = TRUE) %>% mutate( # .before = Inf 表示取当前行之前的所有历史数据 var1_sum3 = slide_dbl(var1_stat, ~sum(.[. != 0][1:3], na.rm = TRUE), .before = Inf, .complete = FALSE), var1_count3 = slide_dbl(var1_stat, ~length(.[. != 0][1:3]), .before = Inf, .complete = FALSE), var2_sum3 = slide_dbl(var2_stat, ~sum(.[. != 0][1:3], na.rm = TRUE), .before = Inf, .complete = FALSE), var2_count3 = slide_dbl(var2_stat, ~length(.[. != 0][1:3]), .before = Inf, .complete = FALSE) ) %>% arrange(desc(event_id), .by_group = TRUE) %>% ungroup() print(result)
关键说明
- 两种方案都先按
a1分组,再升序排列event_id,保证当前行的所有历史值(event_id更小的)都在上方,处理完再还原降序,完全符合你的需求。 - 如果要取最近的3个非零历史值(而不是最早的3个),把代码里的
[1:3]改成tail(., 3)就行。 - 不用手动定义一堆滞后变量,要改取前N个值的话,直接改数字就行,扩展性拉满。
内容的提问来源于stack exchange,提问作者DonnyDolio
相关产品推荐
相关产品推荐

