2017-09-06 77 views
11

Chcę liczyć za country liczbę razy status jest open i liczba razy status jest closed. Następnie obliczyć closerate na country.Grupowanie i liczenie, aby się zbliżyć

danych:

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) 

Dodawanie 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 

Obliczanie closerate

closerate <- length(which(df$status == 'closed'))/
(length(which(df$status == 'closed')) + length(which(df$status == 'open'))) 

[1] 0.6666667 

Oczywiście, jest to closerate dla całości. Wyzwaniem jest uzyskanie closerate na country. Próbowałem dodając kalkulacji closerate do df przez:

df$closerate <- length(which(df$status == 'closed'))/
(length(which(df$status == 'closed')) + length(which(df$status == 'open'))) 

Ale daje wszystkich linii A closerate od 0,66 ponieważ nie jestem grupowania. Uważam, że nie powinienem używać funkcji długości, ponieważ liczenie można wykonać poprzez grupowanie. Przeczytałem kilka informacji o używaniu dplyr do liczenia wyjść logicznych na grupę, ale to się nie udało.

Jest to sygnał wyjściowy:

Grouped by country

Odpowiedz

8
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 

Było to rozwiązanie za pomocą table w komentarzach, które wydaje się mieć został usunięty. W każdym razie, można również użyć 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 
4

Można użyć 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))` 
+0

Dzięki za szybkie odpowiedzi, bardzo pomocne! – Rhulsb

4

data.table metoda będzie.

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 

która zwraca

country closed open closeRate 
1:  BE  3 1  0.75 
2:  NL  3 2  0.60 
2

Oto rozwiązanie dplyr.

output <- df %>% 
    count(country, status) %>% 
    group_by(country) %>% 
    mutate(total = sum(n)) %>% 
    mutate(percent = n/total) 

Powroty ...

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 
1

oto szybkie rozwiązanie z tidyverse:

library(dplyr) 
df %>% group_by(country) %>% 
    mutate(status =ifelse(closeday < '2017-08-20', 'open', 'closed'), 
     closerate=mean(status=="closed")) 

Wracając:

# 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 

Oto jestem wykorzystując przymus z logicals do liczba całkowita, gdy wektor TRUE/FALSE zostanie wstawiony do funkcji mean().

Alternatywnie, z data.table:

library(data.table) 
setDT(df)[,status:=ifelse(closeday < '2017-08-20', 'open', 'closed')] 
df[, .(closerate=mean(status=="closed")), by=country]