Check condition row wise for a number of columns

Viewed 308

Data example:

df <- data.frame("a" = c(1,2,3,4), "b" = c(4,3,2,1), "x_ind" = c(1,0,1,1), "y_ind" = c(0,0,1,1), "z_ind" = c(0,1,1,1) )

> df
  a b x_ind y_ind z_ind
1 1 4     1     0     0
2 2 3     0     0     1
3 3 2     1     1     1
4 4 1     1     1     1

I want to add a new column which checks if the whole row for the columns which end in "_ind" has all values equal to 1. If it does then returns 1 else returns 0. So the result dataframe looks like:

  a b x_ind y_ind z_ind keep
1 1 4     1     0     0    0
2 2 3     0     0     1    0
3 3 2     1     1     1    1
4 4 1     1     1     1    1

I can select the columns by using df %>% select(contains("_ind")) however I am not sure how to do a rowwise operation which checks if every value in the row contains a 1, and then append the column back to the original dataframe.

Any help would be appreicated! Working with Dplyr but appreciate any solution

3 Answers

You can use rowwise with c_across in new dplyr :

library(dplyr)
df %>% rowwise() %>% mutate(keep = +all(c_across(ends_with('ind')) == 1))


#      a     b x_ind y_ind z_ind  keep
#  <dbl> <dbl> <dbl> <dbl> <dbl> <int>
#1     1     4     1     0     0     0
#2     2     3     0     0     1     0
#3     3     2     1     1     1     1
#4     4     1     1     1     1     1

You can use rowSums when your df is equal to 1, i.e.

rowSums(df[grepl('_ind', names(df))] == 1) == ncol(df[grepl('_ind', names(df))])
#[1] FALSE FALSE  TRUE  TRUE

Continuing your dplyr attempt you can do,

df %>% 
 select(contains("_ind")) %>% 
 mutate(new = rowSums(. == 1) == ncol(.))

#  x_ind y_ind z_ind   new
#1     1     0     0 FALSE
#2     0     0     1 FALSE
#3     1     1     1  TRUE
#4     1     1     1  TRUE

#OR you can filter directly

df %>% 
 select(contains("_ind")) %>% 
 filter(rowSums(. == 1) == ncol(.))

#  x_ind y_ind z_ind
#1     1     1     1
#2     1     1     1

If you want to also keep the origina columns, you can use,

 df %>% 
  filter_at(vars(ends_with('_ind')), all_vars(. == 1))

#  a b x_ind y_ind z_ind
#1 3 2     1     1     1
#2 4 1     1     1     1

NOTE: When we use (.), the dot refers to the resulting data frame. In this case, it refers to columns specify in the condition (i.e. to the columns that end with _ind)


Similarly in base R,

df[rowSums(df[grepl('_ind', names(df))] == 1) == ncol(df[grepl('_ind', names(df))]),]
#  a b x_ind y_ind z_ind
#3 3 2     1     1     1
#4 4 1     1     1     1

You can use apply with all, using endsWith to get the columns ending with _ind and testing if they are == 1.

df$keep <- +(apply(df[,endsWith(colnames(df), "_ind")]==1, 1, all))
df
#  a b x_ind y_ind z_ind keep
#1 1 4     1     0     0    0
#2 2 3     0     0     1    0
#3 3 2     1     1     1    1
#4 4 1     1     1     1    1

or using rowSums

df$keep <- +(rowSums(df[,endsWith(colnames(df), "_ind")]!=1) == 0)
Related