【问题标题】:Row-wise operation to see if any columns are in any other list逐行操作以查看是否有任何列在任何其他列表中
【发布时间】:2018-07-23 13:24:55
【问题描述】:

我有一个 tibble tib 如下:

  A     B     C     D    
  <chr> <chr> <chr> <chr>
1 X123  X456  K234  V333 
2 X456  Z000  L888  B323 
3 X789  ZZZZ  D345  O999 
4 M111  M111  M111  M111 
.
.
.
(5000 rows)

我还有一个向量如下:

> vec <- c("X123","X456")
> vec
[1] "X123" "X456"

我正在寻找一种方法来搜索并在小标题的右侧添加一个逻辑列(例如 5000 行),它是 TRUEFALSE,具体取决于是否有任何值tib 中的列中包含 vec 中的值。我的目标输出如下:

  A     B     C     D      lgl
<chr> <chr> <chr> <chr>  <lgl>
1 X123  X456  K234  V333   TRUE
2 X456  Z000  L888  B323   TRUE
3 X789  ZZZZ  D345  O999   FALSE
4 M111  M111  M111  M111   FALSE

我有以下:

> tib %>% 
+   pmap_lgl(~any(..1 %in% vec))
[1]  TRUE  TRUE FALSE FALSE

这得到了我正在寻找的结果,但我对syntax 有点困惑。

为什么上述方法有效(即使用..1),而不是必须使用..1..2..3..4?我的理解是pmap 根据输入行生成一个向量,所以我假设上面的..1 表示第1 行的向量c("X123","X456","K234","V333"),第2 行的c("X456","Z000","L888","B323") 等。

最后,我有两个问题:

  1. 如何将这个新的逻辑向量附加到上面的tib?我没有运气:

tib %&gt;% mutate(lgl = pmap_lgl(~any(..1 %in% vec)))

Error in mutate_impl(.data, dots): Evaluation error: argument ".f" is missing, with no default.

  1. 如果我要观察访问每一行中的每一列(例如,pmap 中第一行的“X123”),我将如何在purrr 的语法中做到这一点?

【问题讨论】:

    标签: r dplyr purrr


    【解决方案1】:

    您可以使用add_columnpmap_lgl 以及辅助函数来获得类似于@YOLO 的基本apply 解决方案的tidyverse 单行。

    library(tidyverse)
    
    df <- tibble(A = c('X123', 'X456','X789', 'M111'),
                 B = c('X456', 'Z000', 'ZZZZ', 'M111'),
                 C = c('K234', 'L888', 'D345', 'M111'),
                 D = c('V333', 'B323', '0999', 'M111'))
    
    
    vec <- c('V333', '0999')
    
    check <- function(...) {
    
      any(c(...) %in% vec)
    
    }
    
    add_column(df, row_check = pmap_lgl(df, check))
    
    # A tibble: 4 x 5
      A     B     C     D     row_check
      <chr> <chr> <chr> <chr> <lgl>    
    1 X123  X456  K234  V333  TRUE     
    2 X456  Z000  L888  B323  FALSE    
    3 X789  ZZZZ  D345  0999  TRUE     
    4 M111  M111  M111  M111  FALSE    
    

    在函数中使用... 的警告是它将对提供的小标题或数据框的所有列进行操作。如果您有其他列,则需要指定函数参数或限制传递给pmap_lgl的数据

    【讨论】:

      【解决方案2】:

      保持简单,您可以使用基本函数applyany 函数:

      df$lgl <- apply(df, 1, function(x) any(x %in% vec))
      

      【讨论】:

        【解决方案3】:

        ..1..2 指的是参数的数量。我们可以将它们与mutaterowwise 函数一起使用来获得我们想要的结果:

        tib %>%
            mutate(lgl = pmap(., ~c(..1, ..2, ..3, ..4) %in% vec)) %>%
            rowwise() %>%
            mutate(lgl = any(unlist(lgl)))
        
          V1    V2    V3    V4    lgl  
          <chr> <chr> <chr> <chr> <lgl>
        1 X123  X456  K234  V333  TRUE 
        2 X456  Z000  L888  B323  TRUE 
        3 X789  ZZZZ  D345  O999  FALSE
        4 M111  M111  M111  M111  FALSE
        

        pmap 的调用使用. 作为它的第一个参数,这是我们正在使用的函数。然后我们使用c(..1, ..2, ..3, ..4)为每列创建一个值向量。然后我们需要使用rowwise 来计算每一行的最终逻辑值。

        我的答案的上一个迭代将返回一个不正确的结果 vec = c('M111'),它现在正确地执行它:

        tib %>%
            mutate(lgl = pmap(., ~c(..1, ..2, ..3, ..4) %in% c('M111'))) %>%
            rowwise() %>%
            mutate(lgl = any(unlist(lgl)))
        
          V1    V2    V3    V4    lgl  
          <chr> <chr> <chr> <chr> <lgl>
        1 X123  X456  K234  V333  FALSE
        2 X456  Z000  L888  B323  FALSE
        3 X789  ZZZZ  D345  O999  FALSE
        4 M111  M111  M111  M111  TRUE 
        

        Here's a link 到函数的文档中,这可能也很有用。

        【讨论】:

        • 这不像 OP 要求的那样按行操作。如果您更改 vec,您会看到您仍在对 tibble 的列进行操作。
        • 对我的回答进行了重大修改。感谢您注意到这一点。
        • 不用担心。这仍然可以在没有rowwise 的情况下完成,并且以非常简洁的方式嵌套。
        猜你喜欢
        • 2013-03-24
        • 2012-06-21
        • 2018-01-03
        • 2022-09-30
        • 2021-11-03
        • 2022-11-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多