Shadrack Kibet
Shadrack Kibet

Reputation: 67

Filter by a level but retain other levels

I would like to filter by a level i.e for level D>2 and B>7 but retain the other levels in a data frame. How can achieve this using dplyr?

Here is a minimal example.

df <- data.frame(x = c("A","A","A","B","B","B","C","C","D","D","D"),
                 y = c(10,1,5,2,7,9,8,3,2,3,5) )

I tried the following but this is not what I want.

df %>% 
  dplyr::filter(x=="D" & y>2 | x=="B" & y>7)

I expect the output to be:

 x  y
 A 10
 A  1
 A  5
 B  9
 C  8
 C  3
 D  3
 D  5

Upvotes: 2

Views: 368

Answers (3)

Rui Barradas
Rui Barradas

Reputation: 76621

Just include a condition to get the rows where x is not one of those levels.

df %>%
  filter((x == "D" & y > 2) | 
           (x == "B" & y > 7) |
           (!x %in% c("B", "D")))
#  x  y
#1 A 10
#2 A  1
#3 A  5
#4 B  9
#5 C  8
#6 C  3
#7 D  3
#8 D  5

Upvotes: 2

Humpelstielzchen
Humpelstielzchen

Reputation: 6441

Just reverse the logic of your filtering.

df %>% 
  dplyr::filter(!(x =="D" & y<=2 | x=="B" & y<=7))

  x  y
1 A 10
2 A  1
3 A  5
4 B  9
5 C  8
6 C  3
7 D  3
8 D  5

Upvotes: 2

Ronak Shah
Ronak Shah

Reputation: 389175

You could filter "B" and "D" levels separately and bind the rows.

library(dplyr)
bind_rows(df %>% filter(!x %in% c("B", "D")), 
          df %>%  filter(x =="D" & y>2 | x=="B" & y>7))


#  x  y
#1 A 10
#2 A  1
#3 A  5
#4 C  8
#5 C  3
#6 B  9
#7 D  3
#8 D  5

In base R, that would be

rbind(subset(df, !x %in% c("B", "D")), subset(df, x=="D" & y>2 | x=="B" & y>7))

Upvotes: 2

Related Questions