Подсчет количества ненулевых наблюдений по группам - PullRequest
1 голос
/ 25 июня 2019

Для следующих данных - я бы хотел посчитать количество учеников в классе каждый год.

   Class  Students Gender Height Year_1999  Year_2000 Year_2001 Year_2002
     1      Mark     M     180      80        54         22       12
     2      John     M     234      0         59         32       62
     1      Tom      M     124      0         53         26       12
     2      Jane     F     180      80        54         22       0
     3      Kim      F     140      0         2           3       32

Вывод должен быть

    Class  Year_1999   Year_2000   Year_2001  Year_2002
     1       1            2            2         2
     2       1            2            2         1
     3       0            1            1         1

Я попробовал следующее, но мне не очень повезло

Number_obs = df %>% 
    group_by(class) %>% 
    summarise(count=n())

Ответы [ 3 ]

1 голос
/ 25 июня 2019

Аналогично решению @ akrun * colSums с использованием by.

do.call(rbind, by(df[5:8] > 0, df[1], colSums))
#   Year_1999 Year_2000 Year_2001 Year_2002
# 1         1         2         2         2
# 2         1         2         2         1
# 3         0         1         1         1

или

Reduce(rbind, by(df[5:8] > 0, df[1], colSums))
#      Year_1999 Year_2000 Year_2001 Year_2002
# init         1         2         2         2
#              1         2         2         1
#              0         1         1         1

do.call быстрее.

1 голос
/ 25 июня 2019

Мы можем использовать summarise_at в dplyr.После группировки по классу выполните цикл по столбцам, у которых в именах столбцов в summarise_at указан год matches, и получите значения sum, которые не равны 0

library(dplyr)
df1 %>% 
   group_by(Class) %>%
   summarise_at(vars(matches("Year")), list(~ sum(as.logical(.))))
# A tibble: 3 x 5
#  Class Year_1999 Year_2000 Year_2001 Year_2002
#  <int>     <int>     <int>     <int>     <int>
#1     1         1         2         2         2
#2     2         1         2         2         1
#3     3         0         1         1         1

Или мы можем gather в «длинный» формат, выполнить операцию group_by для одного столбца и spread в «широкий» формат

library(tidyr)
df1 %>% 
    gather(key, val, matches("Year")) %>%
    group_by(Class, key) %>%
    summarise(val = sum(val  != 0)) %>% 
    spread(key, val)

Или с помощью data.table

library(data.table)
setDT(df1)[, lapply(.SD, function(x) sum(as.logical(x))), .(Class), .SDcols = 5:8]

Или используя base R с aggregate

aggregate(.~ Class, df1[-(2:4)], function(x) sum(x != 0))
#    Class Year_1999 Year_2000 Year_2001 Year_2002
#1     1         1         2         2         2
#2     2         1         2         2         1
#3     3         0         1         1         1

Или используя rowsum

rowsum(+(!!df1[5:8]), df1$Class)
#    Year_1999 Year_2000 Year_2001 Year_2002
#1         1         2         2         2
#2         1         2         2         1
#3         0         1         1         1

или используя colSums

t(sapply(split(as.data.frame(df1[5:8] != 0), df1$Class), colSums))

data

df1 <- structure(list(Class = c(1L, 2L, 1L, 2L, 3L), Students = c("Mark", 
"John", "Tom", "Jane", "Kim"), Gender = c("M", "M", "M", "F", 
"F"), Height = c(180L, 234L, 124L, 180L, 140L), Year_1999 = c(80L, 
0L, 0L, 80L, 0L), Year_2000 = c(54L, 59L, 53L, 54L, 2L), Year_2001 = c(22L, 
32L, 26L, 22L, 3L), 
Year_2002 = c(12L, 62L, 12L, 0L, 32L)), class = "data.frame", 
  row.names = c(NA, 
-5L))
0 голосов
/ 25 июня 2019

Используя dplyr, мы можем использовать summarise_at

library(dplyr)

df %>%
  group_by(Class) %>%
  summarise_at(vars(starts_with("Year")), ~sum(. != 0))

#  Class Year_1999 Year_2000 Year_2001 Year_2002
#  <int>     <int>     <int>     <int>     <int>
#1     1         1         2         2         2
#2     2         1         2         2         1
#3     3         0         1         1         1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...