2015-12-20 2 views
7

Я пытаюсь получить каждый из моих строк id/year/month, чтобы иметь все строки, соответствующие всем семи рабочим дням с NA для «отсутствия рабочих дней».dplyr - право присоединиться после group_by, не создавая желаемого/ожидаемого результата

Вот кадр данных и моя попытка решения этой задачи:

> df 
    id year month weekday amount 
1 1 2015  1 Friday 3650.43 
2 2 2015  1 Monday 1271.12 
3 1 2015  2 Friday 1315.79 
4 2 2015  2 Monday 2195.37 
> wday 
    weekday 
1 Friday 
2 Saturday 
3 Wednesday 
4 Sunday 
5 Tuesday 
6 Monday 
7 Thursday 

Пытались использовать group_by() и право присоединиться. Но это не то, что я думал. Есть ли простой способ добиться результата, который я получаю после?

> df <- df %>% group_by(id, year, month) %>% right_join(wday) 
Joining by: "weekday" 
> df 
Source: local data frame [9 x 5] 
Groups: id, year, month [?] 

    id year month weekday amount 
    (dbl) (int) (int)  (chr) (dbl) 
1  1 2015  1 Friday 3650.43 
2  1 2015  2 Friday 1315.79 
3 NA NA NA Saturday  NA 
4 NA NA NA Wednesday  NA 
5 NA NA NA Sunday  NA 
6 NA NA NA Tuesday  NA 
7  2 2015  1 Monday 1271.12 
8  2 2015  2 Monday 2195.37 
9 NA NA NA Thursday  NA 

Я хочу 7 строк на ид/год/месяц комбинации, где сумма недостающих будней будет NA (или нули в идеале, но я знаю, как получить что мутировать()).

Результирующий кадр данных должен выглядеть следующим образом:

> df 
    id year month weekday amount 
1 1 2015  1 Friday 3650.43 
2 1 2015  1 Monday 0.00 
3 1 2015  1 Saturday 0.00 
4 1 2015  1 Sunday 0.00 
5 1 2015  1 Thursday 0.00 
6 1 2015  1 Tuesday 0.00 
7 1 2015  1 Wednesday 0.00 
8 1 2015  2 Friday 1315.79 
9 1 2015  2 Monday 0.00 
10 1 2015  2 Saturday 0.00 
11 1 2015  2 Sunday 0.00 
12 1 2015  2 Thursday 0.00 
13 1 2015  2 Tuesday 0.00 
14 1 2015  2 Wednesday 0.00 
15 2 2015  1 Friday 0.00 
16 2 2015  1 Monday 1271.12 
17 2 2015  1 Saturday 0.00 
18 2 2015  1 Sunday 0.00 
19 2 2015  1 Thursday 0.00 
20 2 2015  1 Tuesday 0.00 
21 2 2015  1 Wednesday 0.00 
22 2 2015  2 Friday 0.00 
23 2 2015  2 Monday 2195.37 
24 2 2015  2 Saturday 0.00 
25 2 2015  2 Sunday 0.00 
26 2 2015  2 Thursday 0.00 
27 2 2015  2 Tuesday 0.00 
28 2 2015  2 Wednesday 0.00 

ответ

7

Мы можем использовать expand.grid

expand.grid(c(lapply(df[1:3], unique), wday['weekday'])) %>% 
     left_join(., df) %>% 
     mutate(amount=replace(amount, is.na(amount), 0)) %>% 
     arrange(id, year, month, weekday) 
# id year month weekday amount 
#1 1 2015  1 Friday 3650.43 
#2 1 2015  1 Monday 0.00 
#3 1 2015  1 Saturday 0.00 
#4 1 2015  1 Sunday 0.00 
#5 1 2015  1 Thursday 0.00 
#6 1 2015  1 Tuesday 0.00 
#7 1 2015  1 Wednesday 0.00 
#8 1 2015  2 Friday 1315.79 
#9 1 2015  2 Monday 0.00 
#10 1 2015  2 Saturday 0.00 
#11 1 2015  2 Sunday 0.00 
#12 1 2015  2 Thursday 0.00 
#13 1 2015  2 Tuesday 0.00 
#14 1 2015  2 Wednesday 0.00 
#15 2 2015  1 Friday 0.00 
#16 2 2015  1 Monday 1271.12 
#17 2 2015  1 Saturday 0.00 
#18 2 2015  1 Sunday 0.00 
#19 2 2015  1 Thursday 0.00 
#20 2 2015  1 Tuesday 0.00 
#21 2 2015  1 Wednesday 0.00 
#22 2 2015  2 Friday 0.00 
#23 2 2015  2 Monday 2195.37 
#24 2 2015  2 Saturday 0.00 
#25 2 2015  2 Sunday 0.00 
#26 2 2015  2 Thursday 0.00 
#27 2 2015  2 Tuesday 0.00 
#28 2 2015  2 Wednesday 0.00 
+1

Даже не знал, что он существует в базовом пакете. Работает как шарм. – Gopala

4

sqldf Для сложные соединения обычно проще в использовании SQL:

library(sqldf) 
sqldf("select 
     id, 
     year, 
     month, 
     wday.weekday, 
     sum((df.weekday = wday.weekday) * amount) amount 
     from df 
     join wday 
     group by 1, 2, 3, 4") 

:

id year month weekday amount 
1 1 2015  1 Friday 3650.43 
2 1 2015  1 Saturday 0.00 
3 1 2015  1 Wednesday 0.00 
4 1 2015  1 Sunday 0.00 
5 1 2015  1 Tuesday 0.00 
6 1 2015  1 Monday 0.00 
7 1 2015  1 Thursday 0.00 
8 2 2015  1 Friday 0.00 
9 2 2015  1 Saturday 0.00 
10 2 2015  1 Wednesday 0.00 
11 2 2015  1 Sunday 0.00 
12 2 2015  1 Tuesday 0.00 
13 2 2015  1 Monday 1271.12 
14 2 2015  1 Thursday 0.00 
15 1 2015  2 Friday 1315.79 
16 1 2015  2 Saturday 0.00 
17 1 2015  2 Wednesday 0.00 
18 1 2015  2 Sunday 0.00 
19 1 2015  2 Tuesday 0.00 
20 1 2015  2 Monday 0.00 
21 1 2015  2 Thursday 0.00 
22 2 2015  2 Friday 0.00 
23 2 2015  2 Saturday 0.00 
24 2 2015  2 Wednesday 0.00 
25 2 2015  2 Sunday 0.00 
26 2 2015  2 Tuesday 0.00 
27 2 2015  2 Monday 2195.37 
28 2 2015  2 Thursday 0.00 

база R Мы могли бы повторить это в базе R, используя merge и transform:

xt <- transform(
    merge(df, wday, by = c()), 
    amount = (as.character(weekday.x) == as.character(weekday.y)) * amount, 
    weekday = weekday.y, 
    weekday.x = NULL, 
    weekday.y = NULL 
)) 
aggregate(amount ~., xt, sum) 

dplyr и если мы действительно хотели использовать dplyr мы могли бы заменить transform с mutate, rename и select:

library(dplyr) 
merge(df, wday, by = c()) %>% 
mutate(amount = (as.character(weekday.x) == as.character(weekday.y)) * amount) %>% 
rename(weekday = weekday.y) %>% 
select(-weekday.x) %>% 
group_by(id, year, month, weekday) %>% 
summarise(amount = sum(amount)) 

Примечание: Если в каждой группе есть только один день недели (как в вопросе), мы могли бы опционально опустить группу по/сумме, aggregate и group_by/summary в трех решениях соответственно.

+0

добавлены дополнительные решения –

4

Использование tidyr и dplyr. complete здесь тяжелый подъем - если у вас уже есть каждый будний день где-то в df, вам не понадобятся bind_rows или na.omit (или dplyr).

library(dplyr) 
library(tidyr) 
df %>% #initial data 
    bind_rows(wday) %>% #adding on so we have all the weekdays 
    complete(id, year, month, weekday, #completing all levels of id:year:month:weekday 
       fill = list(amount = 0)) %>% #filling amount column with 0 
    na.omit() #remove the NAs we got from the bind_rows 
Смежные вопросы