0
votes

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

3
!do.call(pmax, data)d.b
(1) all returns length 1, so ifelse is a waste here; just do new = +all(...). (2), as @d.b just said, you can expand with do.call for varying number of columns (and likely without rowwise, which can be horrible performance).r2evans
You can also use c_across : data %>% rowwise() %>% mutate(new = all(c_across() == 0))Ronak Shah

3 Answers

2
votes

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)
4
votes

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
1
votes

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