#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