【问题标题】:R dplyr filter direct and indirect sequences of stringR dplyr过滤字符串的直接和间接序列
【发布时间】:2022-01-16 18:21:27
【问题描述】:

假设我有下表。我想找到所有id,其中A直接或间接跟在B之后。

A->Bid 1 的直接序列,而A->B 是 id 2、id 3 和 id 4 的间接序列。

have <- tibble(id=c(rep(1,2),rep(2,4),rep(3,3),rep(4,4))
               ,sequence=c('A','B','A','D','C','B','D','A','C','B','D','A','B'))

have
# A tibble: 13 × 2
      id sequence
   <dbl> <chr>   
 1     1 A       
 2     1 B       
 3     2 A       
 4     2 D       
 5     2 C       
 6     2 B       
 7     3 D       
 8     3 A       
 9     3 C       
10     4 B       
11     4 D       
12     4 A       
13     4 B  

对于A-&gt;B direct sequences,我执行以下操作。但我不认为相同的逻辑适用于间接序列,除非我在连接上使用正则表达式。

have %>% group_by(id) %>% 
  dplyr::mutate(process_seq = paste(lag(sequence), '->', sequence)) %>% 
  dplyr::filter(process_seq == 'A -> B')
want
# A tibble: 13 × 2
      id sequence-type
   <dbl> <chr>   
 1     1 direct       
 2     2 indirect       
 3     3 indirect       
 4     4 indirect       

【问题讨论】:

  • 请详细说明“间接”的确切含义。请在您的问题中添加所需输出的表格。
  • 你想达到什么目的?您是否想要指示 ID 在 A 和 B 之间是否有直接/间接/无链接?还是你想要别的?
  • @djas,是的,正确,对于每个ID,我想知道它是否有从AB 的字符串转换,直接(如A 后紧跟@987654336 @) 或间接 (A followed by some other strings and eventually B)。反向转换 (B-&gt;A) 不感兴趣。但我想如果我能解决这部分,我更容易过滤直接循环转换,如(A-&gt;B-&gt;A) 或间接循环(A-&gt;...-&gt;B-&gt;...-&gt;A)

标签: r dplyr


【解决方案1】:
ABs = have %>% 
    group_by(id) %>% 
    mutate(rownum = row_number(),
           letternum = match(sequence, LETTERS[1:26])) %>% 
    filter(sequence == "A" | sequence == "B") %>% 
    mutate(dif_row = rownum - lag(rownum),
           dif_let = letternum - lag(letternum)) %>% 
    filter(!is.na(dif_row)) %>% 
    mutate(has_direct_link   = max(dif_row==1),
           has_indirect_link = max(dif_row >1 & dif_let == 1),
           has_reverse_link  = max(dif_row >1 & dif_let < 0)) %>% 
    select(id, starts_with("has_")) %>% 
    distinct()
    

res = have %>% left_join(ABs) %>% 
        mutate(has_no_link = as.integer(is.na(has_direct_link))) %>% 
        mutate_if(is.numeric,coalesce,0)

> res
# A tibble: 13 x 6
      id sequence has_direct_link has_indirect_link has_reverse_link has_no_link
   <dbl> <chr>              <dbl>             <dbl>            <dbl>       <dbl>
 1     1 A                      1                 0                0           0
 2     1 B                      1                 0                0           0
 3     2 A                      0                 1                0           0
 4     2 D                      0                 1                0           0
 5     2 C                      0                 1                0           0
 6     2 B                      0                 1                0           0
 7     3 D                      0                 0                0           1
 8     3 A                      0                 0                0           1
 9     3 C                      0                 0                0           1
10     4 B                      1                 0                1           0
11     4 D                      1                 0                1           0
12     4 A                      1                 0                1           0
13     4 B                      1                 0                1           0

@deschen 上面的回答很优雅,但有些不完整:我认为间接链接的“定义”不正确(每个直接链接也是间接链接)。但是我的答案可能会被deschen改进。

【讨论】:

  • 过滤数据集的目的无关紧要。我可以添加另一个条件来表示“如果直接为 1,则间接为 FALSE”,但这不是必需的。
  • 这是假设一个 ID 将只有一个间接或直接链接(这在 OP 的小例子中是正确的,但在大型数据集中不一定是正确的)。如果两者都可能发生,那么您需要格外小心,因为您所做的所有操作都在group_by() 之下。另外,您对间接链接的定义还将捕获我所说的“反向链接”——即 B 在 A 之前的出现。
【解决方案2】:

这是一种方法:

library(tidyverse)
have %>%
  group_by(id) %>%
  mutate(direct = if_else(sequence == 'A' & lead(sequence) == 'B', 1, 0)) %>%
  mutate(indirect = any(sequence == 'A') & any(sequence == 'B')) %>%
  filter(any(direct == 1) | indirect == TRUE) %>%
  ungroup()

给出:

# A tibble: 10 x 4
      id sequence direct indirect
   <dbl> <chr>     <dbl> <lgl>   
 1     1 A             1 TRUE    
 2     1 B             0 TRUE    
 3     2 A             0 TRUE    
 4     2 D             0 TRUE    
 5     2 C             0 TRUE    
 6     2 B             0 TRUE    
 7     4 B             0 TRUE    
 8     4 D             0 TRUE    
 9     4 A             1 TRUE    
10     4 B             0 TRUE    

您当然可以取消选择创建的直接/间接列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    • 2020-01-25
    相关资源
    最近更新 更多