Как подсчитать агрегированные данные и создать разные счетчики?

#r #aggregate

#r #агрегировать

Вопрос:

У меня есть фрейм данных df с разными столбцами.

 df = data.frame(c("2012","2012","2012","2013"),
                c("AAA","BBB","AAA","AAA"),
                c("X","Not-serviced","X","Y"))
colnames(df) = c("year","type","service_type")
  

Мне нужно получить следующий фрейм данных df2 :

 year    type    num_serviced   num_notserviced   num_total
2012    AAA     2              0                 2
...
  

Итак, мне нужно сгруппировать данные по type и year , а затем посчитать частоту Not-serviced и всех остальных, например X , Y и т.д. (предполагается, что обслуживается).

Это мой код, который вычисляет общее:

 temp = aggregate(df,
                 list(type = dat_human_errors$type,
                      year = dat_human_errors$year),
                 FUN = function(x){NROW(x)})
  

Однако как создать num_serviced и num_notserviced ? Должно быть какое-то правило IF-THEN, подобное if type=="Not-serviced" num_notserviced else num_serviced .

Ответ №1:

Мы можем попробовать с data.table . Преобразуйте ‘data.frame’ в ‘data.table’ ( setDT(df) ), сгруппируйте по ‘year’, ‘type’, получите sum количество логических векторов и, наконец, получите итоговое значение.

 library(data.table)
setDT(df)[, .(num_serviced = sum(service_type != "Not-serviced"), 
      num_notserviced = sum(service_type =="Not_serviced")), 
     .(year, type)][, Total := num_serviced   num_notserviced][]
  

Комментарии:

1. Это работает! Спасибо. Если бы у меня был столбец service time и я хотел вычислить среднее время обслуживания, соответствующее каждой группе (т. Е. строке), то это нужно было бы сделать следующим образом: avg_service_time = mean(service_time, service_type != "Not-serviced") ?

2. @FiofanS Возможно, вам нужно .(Mean = mean(service_time), sum(service_type != "Not-serviced"))

3. `setDT(df)[, .(num_serviced = sum(service_type != «Не обслуживаемый»), num_notserviced = sum(service_type ==»Не обслуживаемый»)), .(год, тип)][, Итого := num_serviced num_notserviced][]

4. Ups, не позволяет мне редактировать комментарий. Что ж, проигнорируйте предыдущий комментарий, пожалуйста. Я просто хотел подтвердить: setDT(df)[, .(num_serviced = sum(service_type != "Not-serviced"), num_notserviced = sum(service_type =="Not-serviced")), .(mean = mean(service_time), sum(service_type != "Not-serviced")), .(year, type)][, Total := num_serviced num_notserviced][] . Это выдает мне ошибку: Provide either "by" or "keyby" but not both .

5. еще что-то вроде этого, я думаю: setDT(df)[, .(num_serviced = sum(service_type != "Not-serviced"), num_notserviced = sum(service_type =="Not-serviced"), mean = mean(service_time)), .(year, type)][, Total := num_serviced num_notserviced][]

Ответ №2:

С dplyr вы можете сделать,

 library(dplyr)
df %>%
    group_by(year,type) %>%
    summarise(num_serviced = sum(service_type != "Not-serviced"), 
              num_notserviced = sum(service_type == "Not-serviced"),
              num_total = num_serviced   num_notserviced)

#    year   type num_serviced num_notserviced num_total
#  <fctr> <fctr>        <int>           <int>     <int>
#1   2012    AAA            2               0         2
#2   2012    BBB            0               1         1
#3   2013    AAA            1               0         1
  

Ответ №3:

самый быстрый способ свернуть данные — использовать пакет data.table

 library(data.table)

df = data.frame(year = c("2012","2012","2012","2013"),
                type = c("AAA","BBB","AAA","AAA"),
                service_type= c("X","Not-serviced","X","Y"))



dt <- data.table(df)
dt<-  dt[,list(num_serviced= sum(service_type!="Not-serviced"), num_notserviced= sum(service_type=="Not-serviced")), by=c("year", "type")]
dt$num_total <- dt$num_serviced   dt$num_notserviced

#if you need to go back to dataframe:
df <- data.frame(dt)

df

  year type num_serviced num_notserviced num_total
1 2012  AAA            2               0         2
2 2012  BBB            0               1         1
3 2013  AAA            1               0         1