2017-09-06 17 views
11

Tôi muốn đếm cho mỗi country số lần statusopen và số lần statusclosed. Sau đó, tính toán closerate cho mỗi country.Nhóm và đếm để có được một đóng cửa

dữ liệu:

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) 

Thêm 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 

tính closerate

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

[1] 0.6666667 

Rõ ràng, đây là closerate cho tổng số. Thách thức là để có được closerate mỗi country. Tôi đã cố gắng thêm các tính closerate để df bởi:

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

Nhưng nó mang lại cho tất cả các dòng một closerate 0,66 vì tôi không tập trung. Tôi tin rằng tôi không nên sử dụng chức năng chiều dài vì đếm có thể được thực hiện bằng cách nhóm. Tôi đọc một số thông tin về việc sử dụng dplyr để đếm kết quả đầu ra hợp lý cho mỗi nhóm nhưng điều này không hiệu quả.

Đây là đầu ra mong muốn:

Grouped by country

Trả lời

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 

Có một giải pháp sử dụng table trong các ý kiến ​​mà dường như có đã bị xóa. Dù sao, bạn cũng có thể sử dụng 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

Bạn có thể sử dụng 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

Cảm ơn bạn đã trả lời nhanh chóng của bạn, rất hữu ích! – Rhulsb

4

Một phương pháp data.table sẽ.

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 

trả về

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

Dưới đây là một giải pháp dplyr.

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

Returns ...

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

Dưới đây là một giải pháp nhanh chóng với tidyverse:

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

Trở:

# 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 

Ở đây tôi sử dụng việc cưỡng chế của logicals vào số nguyên khi vector của TRUE/FALSE được đưa vào hàm mean().

Ngoài ra, với data.table:

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