data.frame 中的序列检测

Sequence detection in data.frame

提问人:wacekk 提问时间:7/17/2023 最后编辑:Markwacekk 更新时间:7/18/2023 访问量:37

问:

我有一个数据帧(tibble)。我正在寻找一种方法来检测数据中特定变量序列。reprex 中有 3 个变量,但可以有几十个。我展示了 70 行数据,可能有几十万行。我有一个序列来检测命名列表中的数据帧。在 reprex 中,有 2 个标记为 A 和 B 的序列,但实际上大约有 100 个,所以我选择了这种结构来存储它们。

数据:

library(tidyverse)
data1 <- structure(list(ID = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
                               13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 
                               29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 
                               45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 
                               61, 62, 63, 64, 65, 66, 67, 68, 69, 70), x1 = c("z", "z", "z", 
                                                                               "z", "z", "z", "z", "y", "y", "y", "c", "c", "c", "c", "c", "c", 
                                                                               "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", 
                                                                               "a", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", 
                                                                               "z", "z", "y", "y", "y", "c", "c", "c", "c", "c", "c", "c", "c", 
                                                                               "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "a", "z", 
                                                                               "z", "z"), x2 = c("z", "z", "z", "z", "z", "z", "z", "y", "y", 
                                                                                                 "y", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", 
                                                                                                 "c", "c", "c", "c", "c", "c", "c", "a", "z", "z", "z", "z", "z", 
                                                                                                 "z", "z", "z", "z", "z", "z", "z", "z", "z", "y", "y", "y", "c", 
                                                                                                 "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", 
                                                                                                 "c", "c", "c", "c", "c", "a", "z", "z", "z"), x3 = c("c", "c", 
                                                                                                                                                      "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "z", "z", "z", 
                                                                                                                                                      "z", "z", "z", "z", "z", "z", "z", "f", "f", "f", "f", "c", "c", 
                                                                                                                                                      "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", 
                                                                                                                                                      "c", "c", "c", "c", "c", "c", "c", "c", "z", "z", "z", "z", "z", 
                                                                                                                                                      "z", "z", "z", "z", "z", "f", "f", "f", "f", "c", "c", "c", "c", 
                                                                                                                                                      "c", "c", "c")), row.names = c(NA, -70L), class = c("tbl_df", 
                                                                                                                                                                                                          "tbl", "data.frame"))

创建于 2023-07-17 使用 reprex v2.0.2

要检测的序列:

seqs <- list(A = structure(list(ID = c(1, 2, 3, 4, 5),
                        x1 = c("y", "y", "y", "c", "c"),
                        x2 = c("y", "y", "y", "c", "c"),
                        x3 = c("c", "c", "c", "c", "c")),
                   class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -5L)),
     B = structure(list(ID = c(1, 2, 3, 4, 5, 6, 7, 8),
                        x1 = c("c", "c", "c", "c", "c", "c", "c", "a"),
                        x2 = c("c", "c", "c", "c", "c", "c", "c", "a"),
                        x3 = c("f", "f", "f", "f", "c", "c", "c", "c")),
                   class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, -8L)))

创建于 2023-07-17 使用 reprex v2.0.2

我想得到这样的结果,在列中,我得到序列在哪一秒开始的信息。reprex 中搜索的序列由与我无关的其他序列分隔。重要的是,序列的检测是所有变量的序列检测(序列可能略有不同,只有一个变量的一个值)。我只需要找到序列的开头,因为它的持续时间是已知的(数据框的行数与序列的模式)。

      ID x1    x2    x3    det_seq
   <dbl> <chr> <chr> <chr> <chr>  
 1     1 z     z     c     NA     
 2     2 z     z     c     NA     
 3     3 z     z     c     NA     
 4     4 z     z     c     NA     
 5     5 z     z     c     NA     
 6     6 z     z     c     NA     
 7     7 z     z     c     NA     
 8     8 y     y     c     A      
 9     9 y     y     c     NA     
10    10 y     y     c     NA     
11    11 c     c     c     NA     
12    12 c     c     c     NA     
13    13 c     c     z     NA     
14    14 c     c     z     NA     
15    15 c     c     z     NA     
16    16 c     c     z     NA     
17    17 c     c     z     NA     
18    18 c     c     z     NA     
19    19 c     c     z     NA     
20    20 c     c     z     NA     
21    21 c     c     z     NA     
22    22 c     c     z     NA     
23    23 c     c     f     B      
24    24 c     c     f     NA     
25    25 c     c     f     NA     
26    26 c     c     f     NA     
27    27 c     c     c     NA     
28    28 c     c     c     NA     
29    29 c     c     c     NA     
30    30 a     a     c     NA     
31    31 z     z     c     NA     
32    32 z     z     c     NA     
33    33 z     z     c     NA     
34    34 z     z     c     NA     
35    35 z     z     c     NA     
36    36 z     z     c     NA     
37    37 z     z     c     NA     
38    38 z     z     c     NA     
39    39 z     z     c     NA     
40    40 z     z     c     NA     
41    41 z     z     c     NA     
42    42 z     z     c     NA     
43    43 z     z     c     NA     
44    44 z     z     c     NA     
45    45 y     y     c     A      
46    46 y     y     c     NA     
47    47 y     y     c     NA     
48    48 c     c     c     NA     
49    49 c     c     c     NA     
50    50 c     c     z     NA     
51    51 c     c     z     NA     
52    52 c     c     z     NA     
53    53 c     c     z     NA     
54    54 c     c     z     NA     
55    55 c     c     z     NA     
56    56 c     c     z     NA     
57    57 c     c     z     NA     
58    58 c     c     z     NA     
59    59 c     c     z     NA     
60    60 c     c     f     B      
61    61 c     c     f     NA     
62    62 c     c     f     NA     
63    63 c     c     f     NA     
64    64 c     c     c     NA     
65    65 c     c     c     NA     
66    66 c     c     c     NA     
67    67 a     a     c     NA     
68    68 z     z     c     NA     
69    69 z     z     c     NA     
70    70 z     z     c     NA  
R 数据帧 序列

评论

0赞 PGSA 7/17/2023
这里要考虑的一些方法: stackoverflow.com/a/16537008/16730940

答:

0赞 Mark 7/17/2023 #1

这里有一种方法:

data1 %>% 
  mutate(det_seq = map_chr(seq_along(1:nrow(data1)), 
                             ~ case_when(identical(data1[.x:(.x+4), 2:4], seqs$A[,2:4]) ~ "A",
                                   identical(data1[.x:(.x+7), 2:4], seqs$B[,2:4]) ~ "B",
                                   TRUE ~ "NA")))

更新:若要使其能够匹配任何大小的数据帧列表,请改用以下代码块:seqs

data1 %>% 
  mutate(det_seq = map_chr(seq_along(1:nrow(data1)), 
                    \(x)  first(names(seqs)[map_lgl(seqs,
                     \(s) identical(data1[x:(x+nrow(s)-1), 2:4], s[,2:4]))])))

评论

0赞 wacekk 7/18/2023
这就是我一直在寻找的。我只想自动输入序列的长度及其名称。我可能有大约 100 个序列。你可以从我的数据中获取长度和名称seqs %>% map(nrow) %>% flatten_int()names(seqs)
0赞 wacekk 7/18/2023
一种解决方案是自动生成条件的代码(我正在使用包),但我更喜欢用作普通 r 代码的东西,以便它可以在循环或函数中使用,例如。stringicat(stri_join("identical(data1[.x:(.x+", seqs %>% map_int(nrow)-1, "), 2:4], seqs$", names(seqs), "[,2:4]) ~ \"", names(seqs), "\",\n"))
0赞 Mark 7/18/2023
@wacekk谁告诉你地图调用不能在函数中工作,那是在骗你。循环在 R 中很慢,但由于请求的复杂性,它们可能是必需的
0赞 Mark 7/18/2023
@wacekk更新!
1赞 wacekk 7/18/2023
谢谢你@Mark。这正是我一直在寻找的。