17

I have the following data frame lets call it df, with the following observations:

id   type   company
1    NA      NA
2    NA      ADM
3    North   Alex
4    South   NA
NA   North   BDA
6    NA      CA

I want to retain only the records which do not have NA in column "type" and "company".

id   type   company
3    North   Alex
NA   North   BDA

I tried:

 df_non_na <- df[!is.na(df$company) || !is.na(df$type), ]

But this did not work.

Thanks in advance

OTStats
  • 1,820
  • 1
  • 13
  • 22
Anubhav Dikshit
  • 1,729
  • 6
  • 25
  • 48

6 Answers6

36

Using dplyr, you can also use the filter_at function

library(dplyr)
df_non_na <- df %>% filter_at(vars(type,company),all_vars(!is.na(.)))

all_vars(!is.na(.)) means that all the variables listed need to be not NA.

If you want to keep rows that have at least one value, you could do:

df_non_na <- df %>% filter_at(vars(type,company),any_vars(!is.na(.)))
Ricecakes
  • 681
  • 1
  • 5
  • 13
  • 1
    This answer is good for cases where you want to apply this filter to all except certain columns, too. If you did `(vars(-type,-company)`, for example, you'd be exempting the type and company variables from having to not be na. – Pake Apr 11 '21 at 16:37
17

We can get the logical index for both columns, use & and subset the rows.

df1[!is.na(df1$type) & !is.na(df1$company),]
# id  type company
#3  3 North    Alex
#5 NA North     BDA

Or use rowSums on the logical matrix (is.na(df1[-1])) to subset.

df1[!rowSums(is.na(df1[-1])),]
akrun
  • 874,273
  • 37
  • 540
  • 662
14

You'll want to use drop_na()

library(dplyr)

new_df <- df %>% 
    drop_na(type, company)

gradcylinder
  • 370
  • 2
  • 6
9

The example with dplyr (version >= 1.0.4) and if_all(), since filter_at() is superseded

id <- c(1, 2, 3, 4, NA, 6)
type <- c(NA, NA, "North", "South", "North", NA)
company <- c(NA, "ADM", "Alex", NA, "BDA", "CA")

df <- tibble(id, type, company)

library(dplyr)

df_non_na <- df %>% filter(if_all(c(type,company), ~ !is.na(.)))
Markus Bauer
  • 144
  • 1
  • 9
  • 1
    `Using `across()` in `filter()` is deprecated, use `if_any()` or `if_all()`. ` but it works with one of those depending on what you're after. – william3031 Jan 23 '23 at 23:52
7

You need AND operator (&), not OR (|) I also strongly suggest the tidyverse approach by using the dplyr function filter() and the pipe operator %>%, from dplyr as well:

library(dplyr)
df_not_na <- df %>% filter(!is.na(company) & !is.na(type))
damianooldoni
  • 475
  • 5
  • 6
-5

you can use

na.omit(data_frame_name)
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • That will eliminate rows that have *any* `NA` values -- accepted answer already does the job, question has been resolved. – lefft Feb 07 '18 at 02:18