Удалить именованный столбец тогда и только тогда, когда все значения равны NA - PullRequest
1 голос
/ 06 февраля 2020

Я занимаюсь разработкой пакета, и у меня возникают проблемы, когда я хочу удалить именованный столбец all-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>

Создано в 2020-02-06 пакетом prex (v0.3.0 )

Однако предположим, что я фильтрую столбец 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>

Создано в 2020-02-06 пакетом представ. (v0.3.0)

В функции, которую я разрабатываю, я хочу, чтобы в вышеописанном случае, когда 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 <- NULL

РЕДАКТИРОВАТЬ:

Ожидаемый результат - функция, которая, когда я запускаю ее в оригинальном 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 - все-NA, я ожидаю получить в ответ следующее:

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> 

Ответы [ 2 ]

3 голосов
/ 06 февраля 2020

Мы можем обернуть select с select_if

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

Или как вдохновлено @ H1 комментариями

library(purrr)
df %>% 
  filter(b == 'animal') %>%
  select_if(names(.) != 'd'| summarise_all(., ~ any(!is.na(.))) %>% flatten_lgl)
2 голосов
/ 06 февраля 2020

Вы можете использовать select_if() и проверить условия с помощью %in% (в случае нескольких переменных) для имен столбцов и colSums() для подсчета не-значений.

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   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...