snk550
snk550

Reputation: 45

ifelse() used with all() on multiple columns

I have this data:

library(tidyverse)

data <- tribble(
  ~a, ~b , ~c , ~d,
  0, 0, 0, 0,
  1, 1, 0, 0,
  0, 1, 0, 0,
  0, 0, 0, 1
)

and would like to get this output - if there is a zero in all columns TRUE is returned:

# A tibble: 4 x 5
      a     b     c     d new  
  <dbl> <dbl> <dbl> <dbl> <lgl>
1     0     0     0     0 TRUE 
2     1     1     0     0 FALSE
3     0     1     0     0 FALSE
4     0     0     0     1 FALSE

I tried this and it works:

data %>% 
  rowwise() %>%
  mutate(new = ifelse(all(c(a,b,c,d) == 0) , TRUE, FALSE))

But what if I have many more columns? I would NOT want to write something like this:

data %>% 
  rowwise() %>%
  mutate(new = ifelse(all(c(a,b,c,d,e,f,.......z) == 0) , TRUE, FALSE))

Is there a better way of writing this?

Note: I am using dplyr 0.8.3

Upvotes: 0

Views: 377

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269644

Here are several approaches. The first two require a recent version of dplyr, the third works with older versions of dplyr too and the fourth uses only base R.

cur_data() refers to the current group. See https://dplyr.tidyverse.org/reference/context.html Three exclamation marks !!! is from rlang. It is imported by dplyr and causes the columns of its argument to be passed as separate arguments to pmax. In the last two solutions apply(data == 0, 1, all) applies all to each row of data == 0.

data %>% rowwise %>% mutate(new = all(cur_data() == 0)) %>% ungroup

data %>% mutate(new = !pmax(!!!.))

data %>% mutate(new = apply(. == 0, 1, all)) # older versions of dpylr ok

transform(data, new = apply(data == 0, 1, all))  # base R

Upvotes: 1

r2evans
r2evans

Reputation: 160447

No need for rowwise. Using @d.b's do.call suggestion:

data %>%
  mutate(new = do.call(pmax, .) == 0)
# # A tibble: 4 x 5
#       a     b     c     d new  
#   <dbl> <dbl> <dbl> <dbl> <lgl>
# 1     0     0     0     0 TRUE 
# 2     1     1     0     0 FALSE
# 3     0     1     0     0 FALSE
# 4     0     0     0     1 FALSE

That works when you need all columns. If instead you need a subset, then you can use the somewhat new across:

data %>%
  mutate(new = do.call(pmax, across(a:d)) == 0)

If you don't have across, try this base-R method for selecting a range of columns:

data %>%
  mutate(new = do.call(pmax, subset(., select = a:d)) == 0)

Upvotes: 2

ThomasIsCoding
ThomasIsCoding

Reputation: 101383

One base R option is using rowSums instead of ifelse

data$new <- rowSums(abs(data))==0

which gives

> data
# A tibble: 4 x 5
      a     b     c     d new  
  <dbl> <dbl> <dbl> <dbl> <lgl>
1     0     0     0     0 TRUE 
2     1     1     0     0 FALSE
3     0     1     0     0 FALSE
4     0     0     0     1 FALSE

Upvotes: 2

Related Questions