【问题标题】:Filter rows that contain a certain string across all columns (with dplyr)过滤所有列中包含特定字符串的行(使用 dplyr)
【发布时间】:2020-11-15 13:17:11
【问题描述】:

我有以下数据:

data <- data.frame(name1 =c("John Smith", "A A", "A B", "A C", "John Donovan", "A F", "A D", "A F", "A D", "A C"),
      name2 = c("A V", "John Smith", "A D", "A R", "A O", "John Smith", "A M", "A V", "A L", "A Q"),
      name3 = c("John Donovan", "A R", "John Donovan", "A L", "A V", "A Q", "A T", "A N", "A L", "A X"))
> data
          name1      name2        name3
1    John Smith        A V John Donovan
2           A A John Smith          A R
3           A B        A D John Donovan
4           A C        A R          A L
5  John Donovan        A O          A V
6           A F John Smith          A Q
7           A D        A M          A T
8           A F        A V          A N
9           A D        A L          A L
10          A C        A Q          A X

我想过滤所有列中包含字符串“John”的所有行(列数可以大于 3)。

我尝试以下方法

data %>%
  filter(across(everything()), !str.detect("John"))

但是它不起作用并产生:

Error: Problem with `filter()` input `..1`.
x Input `..1$name1` must be a logical vector, not a character.
i Input `..1` is `across(everything())`.

你有什么想法,尤其是使用cross函数的想法。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    filter 采用逻辑向量,因此在使用 cross 时,您需要将函数传递给 cross 调用,以便将该函数应用于所有选定的列:

    df %>% filter(across(everything(), ~ !str_detect(., "John")))
    
       V1  V2  V3
    1 A C A R A L
    2 A D A M A T
    3 A F A V A N
    4 A D A L A L
    5 A C A Q A X
    

    使用 @ekoam 评论中提出的解决方案:

    df %>% filter(rowSums(across(everything(), ~ str_detect(., "John"))) > 0)
    
                V1         V2           V3
    1   John Smith        A V John Donovan
    2          A A John Smith          A R
    3          A B        A D John Donovan
    4 John Donovan        A O          A V
    5          A F John Smith          A Q
    

    只是为了让图片更清晰一点:

    df %>% filter(print(across(everything(), ~ !str_detect(., "John"))))
    # A tibble: 10 x 3
       V1    V2    V3   
       <lgl> <lgl> <lgl>
     1 FALSE TRUE  FALSE
     2 TRUE  FALSE TRUE 
     3 TRUE  TRUE  FALSE
     4 TRUE  TRUE  TRUE 
     5 FALSE TRUE  TRUE 
     6 TRUE  FALSE TRUE 
     7 TRUE  TRUE  TRUE 
     8 TRUE  TRUE  TRUE 
     9 TRUE  TRUE  TRUE 
    10 TRUE  TRUE  TRUE 
       V1  V2  V3
    1 A C A R A L
    2 A D A M A T
    3 A F A V A N
    4 A D A L A L
    5 A C A Q A X
    

    注意过滤器是&amp;(和)逐行处理布尔值,即只选择具有所有TRUE 值的行,至少有一个FALSE 的行不会被选中。现在让我们看一下您在评论中提供的代码:

     df %>% filter(print(across(everything(), ~ str_detect(., "John"))))
    # A tibble: 10 x 3
       V1    V2    V3   
       <lgl> <lgl> <lgl>
     1 TRUE  FALSE TRUE 
     2 FALSE TRUE  FALSE
     3 FALSE FALSE TRUE 
     4 FALSE FALSE FALSE
     5 TRUE  FALSE FALSE
     6 FALSE TRUE  FALSE
     7 FALSE FALSE FALSE
     8 FALSE FALSE FALSE
     9 FALSE FALSE FALSE
    10 FALSE FALSE FALSE
    [1] V1 V2 V3
    <0 rows> (or 0-length row.names)
    

    所有行至少有一个FALSE,因此没有选择行。

    【讨论】:

    • 如果我想查找包含字符串 John 的行怎么办?这不起作用:df %>% filter(across(everything(), ~ str_detect(., "John"))) 你知道为什么吗?
    • 要过滤包含“John”的任何列,请执行此操作data %&gt;% filter(rowSums(across(everything(), ~str_detect(., "John"))) &gt; 0)。 @senad
    • @senad 你的代码基本上是检查所有列中是否有John @ekoam 的评论是正确的,因为它会检查至少一列中是否有John
    【解决方案2】:

    这里有几个基本的 R 方法。

    使用sapply

    df[rowSums(sapply(df, grepl, pattern = 'John')) == 0, ]
    
    #   name1 name2 name3
    #4    A C   A R   A L
    #7    A D   A M   A T
    #8    A F   A V   A N
    #9    A D   A L   A L
    #10   A C   A Q   A X
    

    lapply

    df[!Reduce(`|`, lapply(df, grepl, pattern = 'John')), ]
    

    【讨论】:

    • 谢谢罗纳克。您对 Abdessabour 解决方案的评论有什么想法吗?
    • 你可以使用df[rowSums(sapply(df, grepl, pattern = 'John')) &gt; 0, ]
    【解决方案3】:

    我们也可以用矢量化的方式做到这一点

    data[!rowSums(`dim<-`(grepl('John', as.matrix(data)), dim(data))),]
    

    -输出

    #     name1 name2 name3
    #4    A C   A R   A L
    #7    A D   A M   A T
    #8    A F   A V   A N
    #9    A D   A L   A L
    #10   A C   A Q   A X
    

    【讨论】:

      猜你喜欢
      • 2023-04-10
      • 2014-05-16
      • 1970-01-01
      • 2021-12-31
      • 2022-09-28
      • 1970-01-01
      • 1970-01-01
      • 2021-01-27
      相关资源
      最近更新 更多