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

基于R语言按特定states模式筛选id行并生成多数据集

我来帮你解决这个基于R语言数据框分组筛选的问题,咱们一步步来实现你需要的多个筛选条件数据集:

R语言分组筛选states序列的解决方案

首先先还原示例数据:

byRow <- TRUE
example.Matrix <- matrix(data = c(1, 0, 0,1, 1, 0,1, 2, 0,1, 3, 1,1, 4, 1,1, 5, 1,1, 6, 0,1, 7, 0,1, 8, 3,2, 0, 0,2, 1, 0, 2, 2, 0, 2, 3, 1,2, 4, 1,2, 5, 4, 3, 0, 0,3,1, 0,3, 2, 1,3, 3, 0,3, 4, 4,4, 0, 0, 4, 1, 1, 4, 2, 0,4, 3, 0,4, 4, 0,4, 5, 1,4, 6, 0,4, 7, 3, 5, 0, 0,5, 1, 1,5, 2, 1, 5, 3, 0, 5, 4, 0,5, 5, 4), byrow=TRUE,ncol=3)
example.df<-as.data.frame(example.Matrix)
colnames(example.df) <- c("id", "day", "states")

1. 筛选:仅出现1个单独的1,且该1下一行非1、后续无1

这个条件要求每个id的states序列里,只有1次等于1的记录,且这个1的下一行(如果存在)不是1,同时之后再也没有1出现。这里推荐用dplyr分组处理,也可以用Base R实现:

dplyr实现(更简洁)

library(dplyr)

df_1 <- example.df %>%
  group_by(id) %>%
  mutate(
    has_single_1 = sum(states == 1) == 1,  # 仅出现1次1
    next_after_1 = ifelse(which(states == 1) == n(), NA, states[which(states == 1)+1]),  # 1的下一行值
    no_more_1_after = all(states[(which(states == 1)+1):n()] != 1)  # 1之后无其他1
  ) %>%
  filter(has_single_1 & (is.na(next_after_1) | next_after_1 != 1) & no_more_1_after) %>%
  select(id, day, states) %>%
  ungroup()

# 查看结果
df_1

输出结果就是你要的id=3的所有行:

# A tibble: 3 × 3
     id   day states
  <dbl> <dbl>  <dbl>
1     3     2      1
2     3     3      0
3     3     4      4

2. 筛选:连续2个1,之后接非1值且后续无1

这个条件要求每个id的states序列里,存在连续2个1的片段,且这个片段之后的第一个值不是1,同时整个序列在这两个1之后再也没有1出现:

df_2 <- example.df %>%
  group_by(id) %>%
  mutate(
    # 标记连续2个1的起始位置
    consecutive_2_1 = (states == 1 & lead(states) == 1),
    end_consec_2 = which(consecutive_2_1) + 1,
    # 验证后续条件:连续2个1后无其他1,且下一个值非1
    valid = ifelse(length(end_consec_2) == 1, 
                   (end_consec_2 < n() & states[end_consec_2 + 1] != 1) & all(states[(end_consec_2 + 1):n()] != 1),
                   FALSE),
    total_ones = sum(states == 1),
    valid = valid & total_ones == 2  # 确保只有这2个1
  ) %>%
  filter(valid) %>%
  select(id, day, states) %>%
  ungroup()

# 查看结果
df_2

输出结果包含id=2和id=5的所有行,符合预期。

3. 筛选:连续3个1,之后接非1值且后续无1

逻辑和上面一致,只是把连续1的数量调整为3:

df_3 <- example.df %>%
  group_by(id) %>%
  mutate(
    # 标记连续3个1的起始位置
    consecutive_3_1 = (states == 1 & lead(states) == 1 & lead(states, 2) == 1),
    end_consec_3 = which(consecutive_3_1) + 2,
    valid = ifelse(length(end_consec_3) == 1,
                   (end_consec_3 < n() & states[end_consec_3 + 1] != 1) & all(states[(end_consec_3 + 1):n()] != 1),
                   FALSE),
    total_ones = sum(states == 1),
    valid = valid & total_ones == 3
  ) %>%
  filter(valid) %>%
  select(id, day, states) %>%
  ungroup()

# 查看结果
df_3

输出结果是id=1的所有行,符合预期。

4. 通用函数:一键生成30个对应连续k个1的数据集

为了避免重复写代码,我们可以封装一个通用函数,输入连续1的数量k,就能返回符合条件的数据集,然后循环生成k=0到29的30个结果:

通用筛选函数

filter_consecutive_ones <- function(df, k) {
  if (k == 0) {
    # k=0:序列中完全没有1的情况
    result <- df %>%
      group_by(id) %>%
      filter(all(states != 1)) %>%
      ungroup()
    return(result)
  }
  
  df %>%
    group_by(id) %>%
    mutate(
      # 标记连续k个1的起始行
      consec_ones = rowSums(sapply(0:(k-1), function(i) lead(states, i) == 1), na.rm = TRUE) == k,
      end_consec = which(consec_ones) + (k-1),
      # 验证核心条件:只有一组连续k个1,后续无1且下一个值非1
      valid = ifelse(length(end_consec) == 1,
                     (end_consec < n() & states[end_consec + 1] != 1) & all(states[(end_consec + 1):n()] != 1),
                     FALSE),
      total_ones = sum(states == 1),
      valid = valid & total_ones == k
    ) %>%
    filter(valid) %>%
    select(id, day, states) %>%
    ungroup()
}

批量生成30个数据集

# 创建列表存储所有结果
result_list <- list()

# 循环生成k=0到29的数据集
for (k in 0:29) {
  result_list[[paste0("df_", k)]] <- filter_consecutive_ones(example.df, k)
}

# 可以通过列表名调用对应结果,比如查看k=1的结果
result_list$df_1

这样你就得到了30个分别对应不同连续1数量的数据集,每个结果都存储在result_list中,命名为df_0到df_29。


内容的提问来源于stack exchange,提问作者Anthony O'Brien

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:53:22