Juan C
Juan C

Reputation: 6132

Remove completely NA rows in r

Been searching for this and even though it should be simple I only found solutions for complete cases or selecting subsets of columns to then omit their NAs. In my case I've got a data frame like this:

   vp01ob__0 vp01ob__1 vp01ob__2 vp01ob__3 vp01ob__4 vp01ob__5 vp01ob__6 vp01ob__7 vp01ob__8
   <chr>     <chr>     <chr>     <chr>     <chr>     <chr>     <chr>     <chr>     <chr>    
 1 NA        NA        NA        NA        NA        NA        NA        NA        NA       
 2 NA        NA        NA        NA        NA        NA        NA        NA        NA       
 3 a         NA        NA        NA        NA        NA        NA        NA        NA       
 4 NA        NA        NA        NA        NA        NA        NA        NA        NA 
 5 NA        NA        NA        NA        NA        NA        NA        NA        NA       
 6 NA        NA        NA        NA        NA        NA        NA        NA        NA       
 7 NA        b         NA        NA        NA        NA        NA        NA        NA  

It's a very sparse dataframe, and so I want to keep just the rows that have some information, like this:

   vp01ob__0 vp01ob__1 vp01ob__2 vp01ob__3 vp01ob__4 vp01ob__5 vp01ob__6 vp01ob__7 vp01ob__8
   <chr>     <chr>     <chr>     <chr>     <chr>     <chr>     <chr>     <chr>     <chr>          
 3 a         NA        NA        NA        NA        NA        NA        NA        NA          
 7 NA        b         NA        NA        NA        NA        NA        NA        NA  

Complete cases drops everything and I couldn't find a way to use filter_all or na.omit(). Any help would be appreciated.

Thanks!

Upvotes: 4

Views: 149

Answers (3)

VitaminB16
VitaminB16

Reputation: 1234

Using rowSums():

require(dplyr)
df %>% filter(rowSums(!is.na(df)) > 0)

Base R:

df[rowSums(!is.na(df)) > 0,]

Upvotes: 4

Anoushiravan R
Anoushiravan R

Reputation: 21908

You can also go about doing it this way, however it's not quite elegant just practical:

library(dplyr)

DF %>%
  filter(DF %>% 
           rowwise() %>% 
           summarise(any(!is.na(c_across(everything())))))

  vp01ob__0 vp01ob__1 vp01ob__2 vp01ob__3 vp01ob__4 vp01ob__5 vp01ob__6 vp01ob__7 vp01ob__8
3         a      <NA>        NA        NA        NA        NA        NA        NA        NA
7      <NA>         b        NA        NA        NA        NA        NA        NA        NA

You can also use any of these two solutions. Special thanks to dear @akrun for suggestions:

library(purrr)

DF %>%
  filter(pmap_lgl(DF, ~ any(!is.na(c(...)))))

Or this time we carry out a row-wise operation and directly use filter:

DF %>%
  rowwise() %>%
  filter(any(!is.na(c_across(everything()))))

Upvotes: 3

akrun
akrun

Reputation: 886938

We could either use if_all

library(dplyr)
df1 %>%
     filter(!if_all(everything(), is.na))

-output

#vp01ob__0 vp01ob__1 vp01ob__2 vp01ob__3 vp01ob__4 vp01ob__5 vp01ob__6 vp01ob__7 vp01ob__8
#3         a      <NA>        NA        NA        NA        NA        NA        NA        NA
#7      <NA>         b        NA        NA        NA        NA        NA        NA        NA

Or with if_any

df1 %>%
    filter(if_any(everything(), ~ !is.na(.)))

-output

#vp01ob__0 vp01ob__1 vp01ob__2 vp01ob__3 vp01ob__4 vp01ob__5 vp01ob__6 vp01ob__7 vp01ob__8
#3         a      <NA>        NA        NA        NA        NA        NA        NA        NA
#7      <NA>         b        NA        NA        NA        NA        NA        NA        NA

data

df1 <- structure(list(vp01ob__0 = c(NA, NA, "a", NA, NA, NA, NA), vp01ob__1 = c(NA, 
NA, NA, NA, NA, NA, "b"), vp01ob__2 = c(NA, NA, NA, NA, NA, NA, 
NA), vp01ob__3 = c(NA, NA, NA, NA, NA, NA, NA), vp01ob__4 = c(NA, 
NA, NA, NA, NA, NA, NA), vp01ob__5 = c(NA, NA, NA, NA, NA, NA, 
NA), vp01ob__6 = c(NA, NA, NA, NA, NA, NA, NA), vp01ob__7 = c(NA, 
NA, NA, NA, NA, NA, NA), vp01ob__8 = c(NA, NA, NA, NA, NA, NA, 
NA)), class = "data.frame", row.names = c("1", "2", "3", "4", 
"5", "6", "7"))

Upvotes: 3

Related Questions