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

如何在R中高效灵活地判断分组变量多期滞后是否满足条件?

高效灵活地创建“X年内首次发生”的指示器变量

我正在分析不同地区多年间的特定天气事件,使用的数据框如下:

library(tidyverse)

df <- tibble(region = c(rep("A", 10), rep("B", 10)),
             event = c(rep("storm", 5), rep("rain", 5), rep("storm", 5), rep("rain", 5)),
             year = c(rep(1:5, 4)),
             occured = c("n", "n", "y", "n", "y",
                         "y", "n", "n", "n", "y",
                         "n", "y", "y", "y", "y",
                         "n", "n", "n", "n", "y")
             )

我需要创建一个指示器变量,用于判断某一地区的特定天气事件是否为X年内首次发生。目前针对过去2年的场景,我通过手动添加lag()语句实现:

df %>% 
   group_by(region, event) %>% 
   mutate(ind = case_when(
     occured == "y" &
       lag(occured, 1, default = "n") == "n" &
       lag(occured, 2, default = "n") == "n" ~ 1,
     .default = 0
     )
     )

输出结果:

# A tibble: 20 × 5
# Groups:   region, event [4]
   region event  year occured   ind
   <chr>  <chr> <int> <chr>   <dbl>
 1 A      storm     1 n           0
 2 A      storm     2 n           0
 3 A      storm     3 y           1
 4 A      storm     4 n           0
 5 A      storm     5 y           0
 6 A      rain      1 y           1
 7 A      rain      2 n           0
 8 A      rain      3 n           0
 9 A      rain      4 n           0
10 A      rain      5 y           1
11 B      storm     1 n           0
12 B      storm     2 y           1
13 B      storm     3 y           0
14 B      storm     4 y           0
15 B      storm     5 y           0
16 B      rain      1 n           0
17 B      rain      2 n           0
18 B      rain      3 n           0
19 B      rain      4 n           0
20 B      rain      5 y           1

我的问题是:有没有更高效、灵活的方法实现这个需求?不用每次根据关注的年数手动增减lag()语句。


解决方案1:使用slider包实现滑动窗口检查

slider包提供了简洁的滑动窗口操作函数,只需修改x_years变量即可切换关注的年数:

library(tidyverse)
library(slider)

# 设置需要关注的年数
x_years <- 2

# 定义判断逻辑:当前事件发生,且过去x年都未发生
is_first_occurrence <- function(window_vals) {
  current_val <- last(window_vals)
  current_val == "y" && all(head(window_vals, -1) == "n")
}

df %>%
  group_by(region, event) %>%
  # 滑动窗口包含当前行 + 过去x年的行
  mutate(ind = as.integer(slide_lgl(occured, is_first_occurrence, .before = x_years))) %>%
  ungroup()

解决方案2:使用zoo包的rollapply函数

如果你习惯用zoo包的滚动计算功能,也可以这样实现:

library(tidyverse)
library(zoo)

x_years <- 2

df %>%
  group_by(region, event) %>%
  mutate(
    # 检查过去x年是否都未发生,不足年份用"n"填充
    past_x_no_event = rollapply(occured, width = x_years, 
                                FUN = function(x) all(x == "n"),
                                align = "right", fill = TRUE),
    # 当前发生且过去x年未发生则标记为1
    ind = as.integer(occured == "y" & past_x_no_event)
  ) %>%
  select(-past_x_no_event) %>%
  ungroup()

方案优势

两种方法都只需修改x_years变量即可适配不同的时间窗口,无需手动添加或删除lag()语句,灵活性和可维护性更强。运行结果和你手动写lag()的逻辑完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 10:24:53