subset rows in dataframe using combinations of conditions

Viewed 45

I have a data frame:

table = structure(list(Plot = 1:10, Sp1 = c(0L, 0L, 1L, 1L, 0L, 1L, 0L, 
                                    0L, 1L, 0L), Sp2 = c(1L, 0L, 1L, 0L, 0L, 0L, 1L, 0L, 0L, 0L), 
               Sp3 = c(1L, 1L, 1L, 1L, 1L, 0L, 1L, 1L, 0L, 0L), Sp4 = c(0L, 
                                                                        1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L)), class = "data.frame", row.names = c(NA, 
                                                                                                                                                  -10L))

0 represents a species (Sp) being absent from a plot. 1 represents a species being present.

First, I want to subset my data frame so that only plots with Sp1 or Sp3 or Sp4 remain. This can be done easily with filter from :

reduced_table <- table %>% filter(table$Sp1 == 1 |table$Sp3 == 1 | table$Sp4 == 1)

But, what if I want to reduce the table so that only plots that have any combination of two of these species is present. For example plots with Sp1 & Sp3, or Sp1 and Sp4, or Sp3 and Sp4 would remain.

Can this be done eloquently like using filter? My real situation has many more species and therefore many more combinations so explicitly writing out the combinations is not ideal.

1 Answers

We can use if_any with filter

library(dplyr)
table %>%
   filter(if_any(c(Sp1, Sp3, Sp4), ~ .== 1))

-output

#   Plot Sp1 Sp2 Sp3 Sp4
#1    1   0   1   1   0
#2    2   0   0   1   1
#3    3   1   1   1   1
#4    4   1   0   1   0
#5    5   0   0   1   1
#6    6   1   0   0   0
#7    7   0   1   1   0
#8    8   0   0   1   1
#9    9   1   0   0   1

Or using a combnation of columns

library(purrr)
combn(c("Sp1", "Sp3", "Sp4"), 2, simplify = FALSE) %>%
  map_dfr( ~ table %>%
         filter(if_all(.x, ~ . == 1))) %>%
  distinct

If the intention is to do filtering on pairwise column checks, use combn from base R

subset(table, Reduce(`|`, combn(c("Sp1", "Sp3", "Sp4"), 2, 
  FUN = function(x) rowSums(table[x] == 1) == 2, simplify = FALSE)))
Related