tidyverse分组后无法获取每组内第一个TRUE位置的问题排查
分组内获取第一个TRUE位置时group_by未生效的问题
需求
在每个id分组内,保存level变量中第一个TRUE的位置。
现有代码
用户使用tidyverse编写的代码如下:
library(tidyverse) data <- data %>% group_by(id) %>% mutate(first_true = min(which(data$level == TRUE))) %>% ungroup()
问题现象
运行后first_true的结果对所有id都相同,group_by(id)没有起到分组计算的作用。
示例数据
id <- c(1,1,1,2,2,2,3,3,3) level <- c(FALSE,FALSE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,TRUE) data <- data.frame(id, level) data$level <- as.logical(data$level)
期望输出
id first_true 1 0 1 0 1 0 2 2 2 2 2 2 3 1 3 1 3 1
问题原因
核心问题是你在mutate中使用了data$level,这会直接引用整个原始数据集的level列,而不是group_by后每个分组内的level子集。因此which(data$level == TRUE)会找出全表所有TRUE的位置,取最小值后对所有分组都一致,完全忽略了分组逻辑。
另外,当分组内没有TRUE时,min(which(...))会返回Inf,不符合你期望的0值,这也是需要处理的边界情况。
修正后的代码
写法一:用ifelse处理空值
library(tidyverse) data <- data %>% group_by(id) %>% mutate( first_true = ifelse(any(level), min(which(level == TRUE)), 0) ) %>% ungroup()
写法二:用match+coalesce简化逻辑
match(TRUE, level)会返回分组内第一个TRUE的位置,找不到时返回NA,再用coalesce把NA替换成0:
data <- data %>% group_by(id) %>% mutate(first_true = coalesce(match(TRUE, level), 0)) %>% ungroup()
验证结果
运行上述修正代码后,每个id分组的first_true会正确显示该组第一个TRUE的位置,无TRUE的组返回0,与期望输出一致。
内容的提问来源于stack exchange,提问作者Dan
相关产品推荐
相关产品推荐

