как да агрегирам рамка с данни и да добавя 0 за категории, които не са намерени

Имам рамка с данни като:

> prova
  sent weeknumber processed
1  100          1         1
2   23          1         0
3  254          1         1
4  321          2         0
5 1241          2         0
6  323          2         1
7 1221          3         1

structure(list(sent = c(100, 23, 254, 321, 1241, 323, 1221), 
weeknumber = c(1, 1, 1, 2, 2, 2, 3), processed = c(1, 0, 
1, 0, 0, 1, 1)), .Names = c("sent", "weeknumber", "processed"
), row.names = c(NA, -7L), class = "data.frame")

Ако искам да извлека броя на Изпратено от номера на седмицата за редове с обработен = 0, мога да направя:

aggregate(prova[prova$processed==0,]$sent, by=list(prova[prova$processed==0,]$weeknumber), FUN = sum)
  Group.1    x
1       1   23
2       2 1562

И ако искам да извлека сумата на Изпратено от номер на седмица при обработка = 1, правя:

aggregate(prova[prova$processed==1,]$sent, by=list(prova[prova$processed==1,]$weeknumber), FUN = sum)
  Group.1    x
1       1  354
2       2  323
3       3 1221

Бих искал обаче да намеря начин винаги да имам една и съща дължина на резултата, т.е. в случай на processed=0, нещо подобно:

  Group.1    x
1       1   23
2       2 1562
3       3    0  // this is the new row I'd like to add

Ако просто предам целия списък с възможни номера на седмици, получавам:

aggregate(prova[prova$processed==0,]$sent, by=list(prova$weeknumber), FUN = sum)
Error in aggregate.data.frame(as.data.frame(x), ...) : 
arguments must have same length

Всеки съвет/съвет е много ценен!


person user299791    schedule 01.11.2016    source източник


Отговори (1)


Можем да използваме условие if/else с data.table. Преобразувайте 'data.frame' в 'data.table' (setDT(prova)), групирани по 'weeknumber', if няма any 0 стойности в 'processed', върнете 0 или else вземете sum на 'sent', когато 'processed' е 0.

library(data.table)
setDT(prova)[, .(sent = if(!any(processed==0)) 0 
               else sum(sent[processed==0])), by = weeknumber]
#   weeknumber sent
#1:          1   23
#2:          2 1562
#3:          3    0

Но ако се нуждаем от sum на 'sent' за всяка стойност на 'processed', групирани по 'weeknumber', удобна опция е dcast

dcast(setDT(prova), weeknumber~processed, value.var="sent", sum)
#  weeknumber    0    1
#1:          1   23  354
#2:          2 1562  323
#3:          3    0 1221

Или с xtabs от base R, което също прави sum на 'sent' за всяка от комбинациите на 'weeknumber' с 'processed'.

xtabs(sent~weeknumber + processed, prova)

Ако използваме aggregate, една опция е merge изхода на aggregate с unique набор от 'номер на седмицата' и след това заменете NA елементите в 'изпратено' на 0.

res <- merge(data.frame(weeknumber = unique(prova$weeknumber)), 
      aggregate(sent~weeknumber, prova, subset = processed ==0, FUN = sum),
     all.x=TRUE)
res$sent[is.na(res$sent)] <- 0
res
#   weeknumber sent
#1          1   23
#2          2 1562
#3          3    0
person akrun    schedule 01.11.2016