【问题标题】:Drop a named column if and only if all values are NA当且仅当所有值都是 NA 时删除命名列
【发布时间】:2020-02-06 18:57:03
【问题描述】:

我正在开发一个包,但当我希望删除一个命名的全 NA 列而不删除其他也是全 NA 的列时,我遇到了麻烦。

这里是一个数据框的例子。在此示例中,我们有两个全 NA 列,这是预期且正确的。

library(tidyverse)

df <- tribble(
  ~a,       ~b,    ~c,         ~d, ~AR, ~BR,
  1L, "animal", "dog",         NA,  NA,  NA,
  2L, "animal", "cat",         NA,  NA,  NA,
  3L, "animal", "rat",         NA,  NA,  NA,
  4L,  "plant", "oak", "carvalho",  NA,  NA
) %>% 
  mutate_if(is.logical, as.character)

df
#> # A tibble: 4 x 6
#>       a b      c     d        AR    BR   
#>   <int> <chr>  <chr> <chr>    <chr> <chr>
#> 1     1 animal dog   <NA>     <NA>  <NA> 
#> 2     2 animal cat   <NA>     <NA>  <NA> 
#> 3     3 animal rat   <NA>     <NA>  <NA> 
#> 4     4 plant  oak   carvalho <NA>  <NA>

由reprex package (v0.3.0) 于 2020-02-06 创建

但是,假设我过滤了 b 列以仅显示动物。在这种情况下,我们将拥有三个全 NA 列:d、AR 和 BR。

df %>% 
  filter(b == "animal")

df
#> # A tibble: 3 x 6
#>       a b      c     d     AR    BR   
#>   <int> <chr>  <chr> <chr> <chr> <chr>
#> 1     1 animal dog   <NA>  <NA>  <NA> 
#> 2     2 animal cat   <NA>  <NA>  <NA> 
#> 3     3 animal rat   <NA>  <NA>  <NA>

由reprex package (v0.3.0) 于 2020-02-06 创建

在我正在开发的函数中,我希望在上述情况下,当 d 为全 NA 时,它会被删除,但不会删除任何其他全 NA 列。因此,仅select(-d) 不起作用,因为它会完全删除列 d,即使它有内容。

我已经尝试了 tidyr::drop_na、purrr::discard 和 dplyr::select_if - 与 all(is.na()) 结合使用,但只删除了 d 列没有成功。我正在寻找一种最好与管道一起使用的方法。我必须这样做的唯一方法不是管道友好:if(all(is.na(df$d))) df$d &lt;- NULL

编辑:

我期望的结果是一个函数,当我在原始 df 中运行它时,它会返回与原始 df 完全相同的 df:

df
#> # A tibble: 4 x 6
#>       a b      c     d        AR    BR   
#>   <int> <chr>  <chr> <chr>    <chr> <chr>
#> 1     1 animal dog   <NA>     <NA>  <NA> 
#> 2     2 animal cat   <NA>     <NA>  <NA> 
#> 3     3 animal rat   <NA>     <NA>  <NA> 
#> 4     4 plant  oak   carvalho <NA>  <NA>

但在d 列全不适用的情况下,我期望得到以下回报:

df
#> # A tibble: 3 x 5
#>       a b      c     AR    BR   
#>   <int> <chr>  <chr> <chr> <chr>
#> 1     1 animal dog   <NA>  <NA> 
#> 2     2 animal cat   <NA>  <NA> 
#> 3     3 animal rat   <NA>  <NA> 

【问题讨论】:

    标签: r dplyr tidyr purrr


    【解决方案1】:

    我们可以用select_if包裹select

    df %>% 
       filter(b == 'animal') %>% 
       select(select_if(., ~ any(is.na(.))) %>% names %>% setdiff('d'), setdiff(names(.), 'd'))
    

    或受@H1 cmets 启发

    library(purrr)
    df %>% 
      filter(b == 'animal') %>%
      select_if(names(.) != 'd'| summarise_all(., ~ any(!is.na(.))) %>% flatten_lgl)
    

    【讨论】:

    • @RubemDornas 任何机会你从另一个掩盖dplyr::select的包中加载select
    • @RubemDornas 可能是软件包版本,因为我使用的是 dplyr 的开发版本。让我测试一下 CRAN 版本
    • 太好了,@akrun,最后一个似乎工作正常。谢谢!我们是否应该删除以前不起作用的答案和 cmets 以避免其他人混淆,还是保留它们更好?第一次提问,不知道具体是怎么做的。
    【解决方案2】:

    您可以使用select_if() 并使用%in%(在多个变量的情况下)作为列名和colSums() 计算非na 值来测试条件。

    df %>%
      filter(b == 'animal') %>%
      select_if(!names(.) %in% "d" | colSums(!is.na(.)) > 0)
    
    # A tibble: 3 x 5
          a b      c     AR    BR   
      <int> <chr>  <chr> <chr> <chr>
    1     1 animal dog   NA    NA   
    2     2 animal cat   NA    NA   
    3     3 animal rat   NA    NA  
    
    
    df %>%
      select_if(!names(.) %in% "d" | colSums(!is.na(.)) > 0)
    
    # A tibble: 4 x 6
          a b      c     d        AR    BR   
      <int> <chr>  <chr> <chr>    <chr> <chr>
    1     1 animal dog   NA       NA    NA   
    2     2 animal cat   NA       NA    NA   
    3     3 animal rat   NA       NA    NA   
    4     4 plant  oak   carvalho NA    NA   
    

    【讨论】:

      猜你喜欢
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-21
      • 2022-01-16
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多