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

分组数据中使用rle函数时忽略NA实现滚动计数

解决按ID分组跳过NA的Value变化滚动计数问题

数据集构建

先还原你的数据集:

id <- c(1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2)
value <- c("x","x","y",NA,NA,"x",NA,"y",
           "y","y",NA,"x","x",NA,"x","x")
df <- data.frame(id, value)

解决方案

以下提供两种实现预期输出的方法:

方法一:使用zoo包辅助处理(逻辑直观)

library(dplyr)
library(zoo)

df %>%
  group_by(id) %>%
  mutate(
    # 用前一个非NA值填充当前NA位置,消除NA对value变化判断的干扰
    prev_valid = na.locf(value, na.rm = FALSE),
    # 标记非NA行是否发生value变化(第一行非NA默认标记为变化)
    is_new_group = ifelse(is.na(value), NA, 
                          value != lag(prev_valid, default = value[!is.na(value)][1])),
    # 累积变化标记得到计数,再将NA行的计数置为NA
    rolling_count = cumsum(ifelse(is_new_group, 1, 0), na.rm = TRUE),
    rolling_count = ifelse(is.na(value), NA, rolling_count)
  ) %>%
  select(-prev_valid, -is_new_group)

逻辑说明:

  • na.locf函数将NA替换为最近的前一个非NA值,让我们可以直接比较当前有效value和上一个有效value的差异
  • is_new_group仅在非NA且value发生变化时标记为TRUE,确定计数需要递增的位置
  • 最后通过cumsum累积计数,并将原value为NA的行的计数重置为NA

方法二:纯dplyr实现(无需额外依赖)

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(
    # 为连续相同的非NA value分配组号,每次value变化(非NA)时组号递增
    group_id = cumsum(!is.na(value) & (is.na(lag(value)) | value != lag(value))),
    # 将组号映射为从1开始的连续计数,NA行的计数置为NA
    rolling_count = ifelse(is.na(value), NA, match(group_id, unique(na.omit(group_id))))
  ) %>%
  select(-group_id)

逻辑说明:

  • group_id给每个连续的非NA相同value块分配唯一组号,NA会继承前一个组号但后续处理会忽略
  • match将非连续的组号重新映射为连续的1、2、3...计数,同时将NA行的计数设为NA

原方法问题说明

你之前使用rle()的方法会将NA视为独立分组,每段NA都会增加计数,但我们需要完全跳过NA的干扰,只追踪非NA值的变化,因此需要先过滤NA的影响再进行计数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:02:07