如何用tidyverse更高效地为连续非NA值创建游程ID?
为连续非NA值创建游程ID的简洁tidyverse实现
给定如下数据:
df <- data.frame( ID = 1:10, Q_segment = c(NA, "tcu_pol","frg", NA, NA, "tcu_wh","tcu_wh", NA, "xy","m,n") )
需求是为Q_segment中的连续非NA值生成游程ID,NA对应的位置保留NA。现有dplyr实现逻辑复杂,以下是几种更简洁高效的tidyverse方案:
方案一:consecutive_id直接处理
library(dplyr) df %>% mutate(Q_sequence = if_else(is.na(Q_segment), NA_integer_, consecutive_id(is.na(Q_segment))))
核心逻辑:is.na(Q_segment)生成一组布尔值,连续非NA对应连续的FALSE,consecutive_id为这组连续相同的布尔值分配统一ID,最后通过if_else将NA位置的结果设为NA,非NA位置保留游程ID。
方案二:cumsum标记非NA段起始
df %>% mutate(Q_sequence = if_else(is.na(Q_segment), NA_integer_, cumsum(!is.na(Q_segment) & lag(is.na(Q_segment), default = TRUE))))
核心逻辑:通过!is.na(Q_segment) & lag(is.na(Q_segment), default = TRUE)判断当前非NA行是否是一段连续非NA的起始(前一行是NA或为第一行),用cumsum对这些起始点计数,连续非NA行自然共享同一个计数。
方案三:结合data.table的rleid(更直观)
如果允许引入data.table包,rleid函数专门用于生成游程ID,实现更简洁:
library(dplyr) library(data.table) df %>% mutate(Q_sequence = if_else(is.na(Q_segment), NA_integer_, rleid(is.na(Q_segment))))
rleid的作用和consecutive_id类似,直接为连续相同的布尔值分配ID,后续逻辑和方案一一致。
以上三种方案都能得到目标输出:
ID Q_segment Q_sequence 1 1 <NA> NA 2 2 tcu_pol 1 3 3 frg 1 4 4 <NA> NA 5 5 <NA> NA 6 6 tcu_wh 2 7 7 tcu_wh 2 8 8 <NA> NA 9 9 xy 3 10 10 m,n 3
内容的提问来源于stack exchange,提问作者Chris Ruehlemann
相关产品推荐
相关产品推荐

