过滤掉 R/Python 中的记录序列

Filter out sequences of records in R/Python

我有一个 table 不同个体的顺序记录,看起来像这样:

(在 R 中设置,尽管 Python 解决方案也可以。)

set.seed(22)

df <- data.frame(
  score = c(1, 4, 15, 12, 6,  7, 12, 7, 8, 5,  12, 19, 1, 4, 7, 12, 3, 5, 9, 4),
  info = sample(1:100, 20)
)
score info
1 9
4 88
15 74
12 94
6 44
7 59
12 81
7 67
8 48
5 16
12 58
19 72
1 62
4 31
7 65
12 49
3 21
5 68
9 33
4 32

目标是根据分数序列过滤掉 table 的某些行。这是人类逻辑中的规则。以分数为榜单:

1, 4, 15, 12, 6, 7, 12, 7, 8, 5 12, 19, 1, 4, 7 12, 3, 5, 9, 4

第 1 步:根据分数 == 12 的实例将列表分成子列表。

(无论最后一个子列表是否以 score == 12 结尾,它都会被包括在内。如果列表不包含任何 score == 12 的实例,则将有一个子列表,即:整个列表。)

[1, 4, 15, 12], [6, 7, 12], [7, 8, 5, 12], [19, 1, 4, 7, 12], [3, 5, 9, 4]

第 2 步:过滤掉所有不包含一个或多个 scores == 4 实例的子列表。

[1, 4, 15, 12], [19, 1, 4, 7, 12], [3, 5, 9, 4]

第 3 步:然后过滤数据框以仅包含与这些分数对应的行。

score info
1 9
4 88
15 74
12 94
19 72
1 62
4 31
7 65
12 49
3 21
5 68
9 33
4 32

请注意,分数既不唯一也不是有序的。

在 R 或 Python 中实现此例程的最佳方法是什么,最好不要使用循环?

使用base R,我们可以在逻辑向量(score == 12)上使用cumsum来创建分组列,然后filter如果有4 %in% 分数只保留那些组,最后删除创建的 grp 列 - dplyr 用于管道,lag

library(dplyr)
df %>%
   group_by(grp = lag(cumsum(score == 12), default = 0)) %>% 
   filter(4 %in% score) %>%
   ungroup %>%
   select(-grp)

-输出

# A tibble: 13 × 2
   score  info
   <dbl> <int>
 1     1     9
 2     4    88
 3    15    74
 4    12    94
 5    19    72
 6     1    62
 7     4    31
 8     7    65
 9    12    49
10     3    21
11     5    68
12     9    33
13     4    32

这是一个基本的 R 方法。

  1. 首先创建一个vec向量,其中包含索引位置df$score == 12。还包括 0 和 now(df) 到它,稍后将在 lapply
  2. 中使用
  3. 创建以 score == 12 结尾的子列表 mylistdeframe 用于使用 lapply
  4. 从 two-column 数据帧创建命名向量
  5. 使用%in%运算符查看子列表中是否包含4,去掉不包含4的子列表
  6. 并使用 enframe 从命名向量创建 two-column 数据框。
vec <- sort(c(0, which(df$score == 12), nrow(df)))
mylist <- lapply(1:(length(vec) - 1), function(x) deframe(df[2:1])[(vec[x]+1):vec[x+1]])
enframe(mylist[sapply(mylist, function(x) 4 %in% x)] %>% unlist(), value = "score", name = "info")[2:1]

# A tibble: 13 × 2
   score info 
   <int> <chr>
 1     1 9    
 2     4 88   
 3    15 74   
 4    12 94   
 5    19 72   
 6     1 62   
 7     4 31   
 8     7 65   
 9    12 49   
10     3 21   
11     5 68   
12     9 33   
13     4 32