superponer - Agrupando y contando para obtener un cierre
superponer graficas en r (5)
Quiero contar por country
la cantidad de veces que el status
está open
y el número de veces que se closed
el status
. Luego calcule el closerate
por country
.
Datos:
customer <- c(1,2,3,4,5,6,7,8,9)
country <- c(''BE'', ''NL'', ''NL'',''NL'',''BE'',''NL'',''BE'',''BE'',''NL'')
closeday <- c(''2017-08-23'', ''2017-08-05'', ''2017-08-22'', ''2017-08-26'',
''2017-08-25'', ''2017-08-13'', ''2017-08-30'', ''2017-08-05'', ''2017-08-23'')
closeday <- as.Date(closeday)
df <- data.frame(customer,country,closeday)
Agregar status
:
df$status <- ifelse(df$closeday < ''2017-08-20'', ''open'', ''closed'')
customer country closeday status
1 1 BE 2017-08-23 closed
2 2 NL 2017-08-05 open
3 3 NL 2017-08-22 closed
4 4 NL 2017-08-26 closed
5 5 BE 2017-08-25 closed
6 6 NL 2017-08-13 open
7 7 BE 2017-08-30 closed
8 8 BE 2017-08-05 open
9 9 NL 2017-08-23 closed
Cálculo de closerate
closerate <- length(which(df$status == ''closed'')) /
(length(which(df$status == ''closed'')) + length(which(df$status == ''open'')))
[1] 0.6666667
Obviamente, este es el closerate
del total. El desafío es obtener el closerate
por country
. Traté de agregar el cálculo closerate
a df
por:
df$closerate <- length(which(df$status == ''closed'')) /
(length(which(df$status == ''closed'')) + length(which(df$status == ''open'')))
Pero le da a todas las líneas un closerate
de 0.66 porque no estoy agrupando. Creo que no debería usar la función de longitud porque el conteo se puede hacer agrupando. Leí información sobre el uso de dplyr
para contar las salidas lógicas por grupo, pero esto no funcionó.
Este es el resultado deseado:
Aquí hay una solución dplyr
.
output <- df %>%
count(country, status) %>%
group_by(country) %>%
mutate(total = sum(n)) %>%
mutate(percent = n/total)
Devoluciones...
output
country status n total percent
BE closed 3 4 0.75
BE open 1 4 0.25
NL closed 3 5 0.60
NL open 2 5 0.40
Aquí hay una solución rápida con tidyverse
:
library(dplyr)
df %>% group_by(country) %>%
mutate(status =ifelse(closeday < ''2017-08-20'', ''open'', ''closed''),
closerate=mean(status=="closed"))
De vuelta:
# A tibble: 9 x 5
# Groups: country [2]
customer country closeday status closerate
<dbl> <fctr> <date> <chr> <dbl>
1 1 BE 2017-08-23 closed 0.75
2 2 NL 2017-08-05 open 0.60
3 3 NL 2017-08-22 closed 0.60
4 4 NL 2017-08-26 closed 0.60
5 5 BE 2017-08-25 closed 0.75
6 6 NL 2017-08-13 open 0.60
7 7 BE 2017-08-30 closed 0.75
8 8 BE 2017-08-05 open 0.75
9 9 NL 2017-08-23 closed 0.60
Aquí estoy utilizando la coerción de lógicos en números enteros cuando el vector de TRUE / FALSE se pone en la función mean()
.
Alternativamente, con data.table
:
library(data.table)
setDT(df)[,status:=ifelse(closeday < ''2017-08-20'', ''open'', ''closed'')]
df[, .(closerate=mean(status=="closed")), by=country]
Puedes usar tapply
:
data.frame(open=tapply(df$status=="open", df$country, sum),
closed=tapply(df$status=="closed", df$country, sum)
closerate=tapply(df$status=="closed", df$country, mean))`
Un método data.table
sería.
library(data.table)
setDT(df)[, {temp <- status=="closed"; # store temporary logical variable
.(closed=sum(temp), open=sum(!temp), closeRate=mean(temp))}, # calculate stuff
by=country] # by country
que devuelve
country closed open closeRate
1: BE 3 1 0.75
2: NL 3 2 0.60
aggregate(list(output = df$status == "closed"),
list(country = df$country),
function(x)
c(close = sum(x),
open = length(x) - sum(x),
rate = mean(x)))
# country output.close output.open output.rate
#1 BE 3.00 1.00 0.75
#2 NL 3.00 2.00 0.60
Hubo una solución que utilizaba la table
en los comentarios que parece haber sido eliminada. De todos modos, también podrías usar la table
output = as.data.frame.matrix(table(df$country, df$status))
output$closerate = output$closed/(output$closed + output$open)
output
# closed open closerate
#BE 3 1 0.75
#NL 3 2 0.60