基于变量顺序的条件标记:R语言实现A-B-C序列识别
问题描述
给定由事件A、B、C组成的序列(每个事件至少出现一次,可重复),需要为每个序列生成0/1标记向量,规则如下:
- 每个序列中仅存在一个有效A和一个有效C,且有效A必须在有效C之前
- 有效A和有效C之间可以包含任意数量的B
- 属于这个有效A-B-C区间的事件标记为1,其余标记为0
- 若序列中不存在符合A在C之前的情况(如B-A-C、C-B-A),则所有位置标记为0
示例序列与预期输出:
- 序列1:
c("A", "B", "C")→ 输出c(1,1,1) - 序列2:
c("A", "A", "B", "B", "C")→ 输出c(0,1,1,1,1)(取最后一个在C之前的A作为有效A) - 序列3:
c("B", "A", "C")→ 输出c(0,0,0)(A之前有B,不符合规则) - 序列4:
c("C", "B", "A")→ 输出c(0,0,0)(C在A之前,无有效A-C对) - 序列5:
c("A", "B", "B", "C", "A")→ 输出c(1,1,1,1,0)(C之后的A标记为0)
解决方案
Base R 实现(使用lapply)
核心逻辑:对每个序列,先定位第一个出现的C,再找到该C之前最后一个A;若该A之前存在非A元素,则全标记为0,否则标记A到C区间为1。
# 定义单序列处理函数 mark_valid_sequence <- function(seq) { # 定位第一个C的位置 c_pos <- which(seq == "C") if (length(c_pos) == 0) return(rep(0, length(seq))) first_c <- c_pos[1] # 定位第一个C之前最后一个A的位置 a_pos <- which(seq[1:first_c] == "A") if (length(a_pos) == 0) return(rep(0, length(seq))) last_a <- a_pos[length(a_pos)] # 检查有效A之前是否有非A元素 if (any(seq[1:(last_a - 1)] != "A")) { return(rep(0, length(seq))) } # 生成标记向量 result <- rep(0, length(seq)) result[last_a:first_c] <- 1 return(result) } # 应用到序列列表 s.indexed_base <- lapply(s.list, mark_valid_sequence) s.indexed_base
Tidyverse 实现
通过分组处理数据框,结合位置判断完成标记:
library(tidyverse) s.df_marked <- s.df %>% group_by(group) %>% mutate( pos = row_number(), # 找到本组第一个C的位置 first_c = min(pos[value == "C"]), # 找到第一个C之前最后一个A的位置 last_a_before_c = max(pos[value == "A" & pos <= first_c]), # 判断是否符合有效区间条件 valid = ifelse( is.finite(last_a_before_c) & all(value[1:(last_a_before_c - 1)] == "A"), pos >= last_a_before_c & pos <= first_c, FALSE ), # 转换为0/1标记 index = as.integer(valid) ) %>% ungroup() %>% select(-pos, -first_c, -last_a_before_c, -valid) s.df_marked
内容的提问来源于stack exchange,提问作者gregor-fausto
相关产品推荐
相关产品推荐

