Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

COUNTIF equivalent in dplyr summarise

Tags:

r

dplyr

I have a data frame listing total students (Stu) and number of students per group (ID) who are taking part in an activity (Sub):

     ID   Stu   Sub
  (int) (int) (int)
1   101    80    NA
2   102   130    NA
3   103    10    NA
4   104   210    20
5   105   180    NA
6   106   150    NA

I would like to know the number of groups in size bands (>400, >200, >100, >0) who are either involved in an activity (Sub > 0), or not (Sub is.na)

output <- structure(list(ID = c(101L, 102L, 103L, 104L, 105L, 106L), 
                       Stu = c(80L, 130L, 10L, 210L, 180L, 150L), 
                       Sub = c(NA,NA, NA, 20L, NA, NA)), 
                  .Names = c("ID", "Stu", "Sub"), 
                  class = c("tbl_df", "data.frame"), 
                  row.names = c(NA, -6L))

temp <- output %>% 
mutate(Stu = ifelse(Stu >= 400, 400,
         ifelse(Stu >= 200, 200,
             ifelse(Stu >= 100, 100, 0
                 )))) %>%
group_by(Stu) %>%
summarise(entries = length(!is.na(Sub)),
          noentries = length(is.na(Sub)))

The results should be:

    Stu entries noentries
  (dbl)   (int)     (int)
1     0       0         2
2   100       0         3
3   200       1         0

But I get:

    Stu entries noentries
  (dbl)   (int)     (int)
1     0       2         2
2   100       3         3
3   200       1         1

How can I make the length function in the summarise act like a countif?

like image 951
16 revs, 12 users 31% Avatar asked Dec 10 '22 16:12

16 revs, 12 users 31%


2 Answers

summarise expects a single value, so sum instead of length does the job:

output %>% 
  mutate(Stu = ifelse(Stu >= 400, 400,
                      ifelse(Stu >= 200, 200,
                             ifelse(Stu >= 100, 100, 0
                             )))) %>%
  group_by(Stu) %>% 
  summarise(entries = sum(!is.na(Sub)),
            noentries = sum(is.na(Sub)))

Source: local data frame [3 x 3]

Stu entries noentries
(dbl)   (int)     (int)
1     0       0         2
2   100       0         3
3   200       1         0
like image 159
Vincent Bonhomme Avatar answered Dec 13 '22 05:12

Vincent Bonhomme


Following the same idea provided by @eipi10, but cutting to the chase with count() instead of group_by() %>% tally() and showing that tidyr::spread can mimic reshape2::dcast:

output %>%
  count(Sub = ifelse(is.na(Sub), 'No Entries', 'Entires'),
        Stu = cut(Stu, c(0, 100, 200, 400, +Inf), labels = c(0, 100, 200, 400))) %>%
  tidyr::spread(Sub, n, fill = 0)
like image 43
JasonAizkalns Avatar answered Dec 13 '22 05:12

JasonAizkalns