2015-12-20 8 views
7

Ich versuche, jede meiner id/Jahr/Monat Zeilen alle Zeilen haben, die alle sieben Wochentage mit NAs für 'fehlende Wochentage.' Hierdplyr - rechts beitreten nach group_by nicht produzieren gewünschte/erwartete Ergebnis

ist der Datenrahmen und mein Versuch, diese Aufgabe zu erreichen:

> 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 

Versuchte group_by() zu verwenden und das Recht kommen. Aber es produziert nicht das, was ich dachte. Gibt es einen einfachen Weg, um das gewünschte Ergebnis zu erzielen?

> 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 

Ich mag 7 Zeilen pro id/Jahr/Monat Kombination, in der Menge für fehlende Wochentag wird NA (oder idealerweise Nullen, aber ich weiß, wie das von mutieren zu bekommen()).

Resultierende Datenrahmen sollte wie folgt aussehen:

> 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 

Antwort

7

Wir expand.grid verwenden können

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

Wusste nicht einmal, dass es im Basispaket existierte. Klappt wunderbar. – Gopala

4

sqldf Für komplexe Joins ist es in der Regel einfacher SQL zu verwenden:

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") 

Geben:

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 und wenn wir wirklich verwenden dplyr wollten könnten wir die transform mit mutate, rename ersetzen und: mit merge und transform

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 

Basis R Wir konnten dies in der Basis R replizieren 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)) 

Hinweis: Wenn es nur einen Wochentag pro Gruppe (wie in der Frage) gibt, könnten wir optional Group by/sum, aggregate und group_by/summary in den drei Lösungen weglassen.

+0

hinzugefügt zusätzliche Lösungen –

4

Mit tidyr und dplyr. complete hier macht das schwere Heben - wenn Sie schon jeden Wochentag irgendwo in df haben, werden Sie nicht die bind_rows oder na.omit (oder dplyr) benötigen.

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 
Verwandte Themen