3

I have a data frame and want to count the number of zeros in each row using dplyr's rowwise. What am I doing wrong?

dt2 = data.frame(A = c(8, 6), B = c(0, 0), C = c(0, 5))
dt2
zerocount <- function(x) {sum(x == 0)}
library(dplyr)
dt2 %>% rowwise() %>% mutate(nr_of_0s = zerocount(A, B, C))

The code above works if I replace zerocount(A, B, C) in the line above with, for example, max(A, B, C). What is wrong? Thank you!

JJJ
  • 1,009
  • 6
  • 19
  • 31
user3245256
  • 1,842
  • 4
  • 24
  • 51
  • Possible duplicate of [Applying a function to every row of a table using dplyr?](https://stackoverflow.com/questions/21818181/applying-a-function-to-every-row-of-a-table-using-dplyr) – Cristian E. Nuno Oct 15 '18 at 17:16
  • I've read that link but didn't see a direct application to my question. – user3245256 Oct 15 '18 at 17:27
  • I don't think your problem is with rowwise. The way your function is written, it's expecting a single object. Try adding a c(): `dt2 %>% rowwise() %>% mutate(nr_of_0s = zerocount(c(A, B, C)))` – benc Oct 15 '18 at 23:03
  • unfortunate that you specified `rowwise`. This is pretty effective too `dt2 %>% mutate(zero.count = rowSums(.==0) )` – Nettle Oct 16 '18 at 02:25
  • @benc - thank you very much for your comment. Would you please provide it as a response so that I could upvote you? – user3245256 Oct 16 '18 at 19:31
  • @Nettle - Thank you very much, indeed, it works well too! – user3245256 Oct 16 '18 at 19:31

3 Answers3

4

I don't think your problem is with rowwise. The way your function is written, it's expecting a single object. Try adding a c():

dt2 %>% rowwise() %>% mutate(nr_of_0s = zerocount(c(A, B, C)))

Note that, if you aren't committed to using your own function, you can skip rowwise entirely, as Nettle also notes. rowSums already treats data frames in a rowwise fashion, which is why this works:

dt2 %>% mutate(nr_of_0s = rowSums(. == 0))
benc
  • 376
  • 1
  • 6
2

A logical test for the presence of zeros would look like:

 dt2==0
         A    B     C
[1,] FALSE TRUE  TRUE
[2,] FALSE TRUE FALSE

Sum the number of Trues by row

rowSums(dt2==0)
[1] 2 1

With this in mind, here's a tidyverse solution:

dt2 %>% 
  mutate(zero.count = rowSums(.==0) ) #<The dot is shorthand for dt2 

  A B C zero.count
1 8 0 0          2
2 6 0 5          1
Nettle
  • 3,193
  • 2
  • 22
  • 26
2

Another method without using rowwise():

mutate(dt2, zero_count = pmap_int(dt2, function(...) sum(c(...) == 0)))

>   A B C zero_count
> 1 8 0 0          2
> 2 6 0 5          1

pmap() is a purrr function that takes takes elements from a list (which in this case is the data frame) and applies a function. In this case, I'm just applying your function on the fly. By default, pmap() returns a list, but using the _int suffix makes it return an integer vector.

Phil
  • 7,287
  • 3
  • 36
  • 66