dplyr中基于当前Year变量的条件判断失效问题求助
dplyr动态标记"断点"行的问题解决
示例数据集
df <- tibble::tribble( ~INSTRUMENT_USED, ~Year, ~UniqueCount, "QUEST_A", 2015, 1, "QUEST_A", 2016, 1, "QUEST_A", 2017, 1, "QUEST_A", 2018, 1, "QUEST_A", 2019, 1, "QUEST_A", 2020, 1, "QUEST_A", 2021, 0, "QUEST_A", 2022, 0, "QUEST_A", 2023, 0, "QUEST_B", 2015, 1, "QUEST_B", 2016, 1, "QUEST_B", 2017, 1, "QUEST_B", 2018, 1, "QUEST_B", 2019, 0, "QUEST_B", 2020, 0, "QUEST_B", 2021, 1, "QUEST_B", 2022, 0, "QUEST_B", 2023, 0 )
需求说明
生成dbreak变量,仅当某一行同时满足以下条件时标记为Yes,其余为No:
- 该行之前所有年份的
UniqueCount均为1 - 该行之后所有年份的
UniqueCount均为0
示例中仅QUEST_A 2021行符合要求。
错误代码问题分析
你手动硬编码年份时结果正确,但替换为动态Year变量后失效,核心问题是**mutate中直接使用Year向量进行筛选时,是组内向量的逐元素比较,而非针对当前行的单个年份值**:
看错误代码中的条件:
all(UniqueCount[Year <= Year-1] == 1)
这里的Year是整个分组的年份向量,Year <= Year-1会生成一组逻辑值(比如2015<=2014为FALSE,2016<=2015为FALSE...),完全不是你想要的"当前行年份之前的所有年份"。
而all(UniqueCount[Year > Year] ==0)这个条件永远为TRUE,因为Year > Year对所有元素都是FALSE,空向量的all()默认返回TRUE,导致不符合条件的行被错误标记。
正确实现方案
方法1:用累积函数预处理状态(高效简洁)
df <- df %>% group_by(INSTRUMENT_USED) %>% arrange(INSTRUMENT_USED, Year) %>% mutate( # 检查当前行及之前是否从未出现过非1值 all_prev_one = cumsum(UniqueCount != 1) == 0, # 检查当前行及之后是否从未出现过非0值(反向累积) all_next_zero = rev(cumsum(rev(UniqueCount) != 0)) == 0, # 组合所有条件:当前是0、前一行是1、前后状态都符合 dbreak = ifelse(UniqueCount == 0 & lag(UniqueCount) == 1 & all_prev_one & all_next_zero, "Yes", "No") ) %>% ungroup()
方法2:逐行判断(直观易懂)
如果更习惯逐行处理逻辑,可以用purrr::pmap:
library(purrr) df <- df %>% group_by(INSTRUMENT_USED) %>% arrange(INSTRUMENT_USED, Year) %>% mutate( dbreak = pmap_chr(list(Year, UniqueCount, lag(UniqueCount)), function(current_year, current_uc, prev_uc) { # 先排除不满足基础条件的行 if (current_uc != 0 || prev_uc != 1) return("No") # 再检查前后所有年份的状态 if (all(UniqueCount[Year < current_year] == 1) && all(UniqueCount[Year > current_year] == 0)) { "Yes" } else { "No" } }) ) %>% ungroup()
运行上述任意代码后,QUEST_A 2021的dbreak会被标记为Yes,其余行均为No,符合预期。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

