Группировка и подсчет для закрытия
Я хочу считать за country
количество раз status
open
и количество раз status
равно closed
. Затем вычислите closerate
за country
.
Данные:
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)
Добавление 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
Расчет closerate
closerate <- length(which(df$status == 'closed')) /
(length(which(df$status == 'closed')) + length(which(df$status == 'open')))
[1] 0.6666667
Очевидно, что это значение closerate
для всего. Задача состоит в том, чтобы получить closerate
за country
. Я попытался добавить вычисление closerate
к df
с помощью:
df$closerate <- length(which(df$status == 'closed')) /
(length(which(df$status == 'closed')) + length(which(df$status == 'open')))
Но он дает все строки a closerate
0,66, потому что я не группирую. Я считаю, что не следует использовать функцию длины, потому что подсчет может быть выполнен путем группировки. Я прочитал некоторую информацию об использовании dplyr
для подсчета логических выходов на группу, но это не сработало.
Это желаемый результат:
![Grouped by country]()
Ответы
Ответ 1
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
В комментариях, которые, как представляется, были удалены, было найдено решение с использованием table
. В любом случае, вы также можете использовать 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
Ответ 2
Вы можете использовать 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))`
Ответ 3
A data.table
будет.
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
который возвращает
country closed open closeRate
1: BE 3 1 0.75
2: NL 3 2 0.60
Ответ 4
Вот решение dplyr
.
output <- df %>%
count(country, status) %>%
group_by(country) %>%
mutate(total = sum(n)) %>%
mutate(percent = n/total)
Возвращает...
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
Ответ 5
Здесь быстрое решение с tidyverse
:
library(dplyr)
df %>% group_by(country) %>%
mutate(status =ifelse(closeday < '2017-08-20', 'open', 'closed'),
closerate=mean(status=="closed"))
Возврат:
# 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
Здесь я использую принуждение логических элементов к целому числу, когда вектор TRUE/FALSE помещается в функцию mean()
.
В качестве альтернативы, с data.table
:
library(data.table)
setDT(df)[,status:=ifelse(closeday < '2017-08-20', 'open', 'closed')]
df[, .(closerate=mean(status=="closed")), by=country]