2016-03-23 16 views
2

Ich habe ein Dataset und ich möchte etwas wie Group Rollup wie wir in SQL für aggregierte Werte haben.Wie funktioniert die Gruppierung nach Rollup in R? (Wie SQL)

Unten ist ein reproduzierbares Beispiel. Ich weiß Aggregat funktioniert wirklich gut, wie erklärt here, aber keine zufriedenstellende Passform für meinen Fall.

year<- c('2016','2016','2016','2016','2017','2017','2017','2017') 
month<- c('1','1','1','1','2','2','2','2') 
region<- c('east','west','east','west','east','west','east','west') 
sales<- c(100,200,300,400,200,400,600,800) 
df<- data.frame(year,month,region,sales) 
df 


year month region sales 
1 2016  1 east 100 
2 2016  1 west 200 
3 2016  1 east 300 
4 2016  1 west 400 
5 2017  2 east 200 
6 2017  2 west 400 
7 2017  2 east 600 
8 2017  2 west 800 

jetzt, was ich tun möchte, ist die Aggregation (Summen- von Jahr-Monat-Region) und fügen Sie die neue Aggregat Zeile in dem bestehenden Datenrahmen z.B. es sollte für die aggreagted Reihen

year month region sales 
1 2016  1 east 400 
2 2016  1 west 600 
3 2016  1 USA 1000 
4 2017  2 east 800 
5 2017  2 west 1200 
6 2017  2 USA 2000 

Ich habe herausgefunden, einen Weg (unten) mit einem neuen Namen für Region ‚USA‘ zwei zusätzliche Zeilen wie unten sein, aber ich bin mir sehr sicher, dass es eine optimale Lösung besteht für dies oder eine bessere Problemumgehung als meine

df1<- setNames(aggregate(df$sales, by=list(df$year,df$month, df$region), FUN=sum), 
    c('year','month','region', 'sales')) 


df2<- setNames(aggregate(df$sales, by=list(df$year,df$month), FUN=sum), 
       c('year','month', 'sales')) 

df2$region<- 'USA'     ## added a new column- region- for total USA 
df2<- df2[, c('year','month','region', 'sales')] ## reordering the columns of df2 

df3<- rbind(df1,df2) 

df3<- df3[order(df3$year,df3$month,df3$region),] ## order by 
rownames(df3)<- NULL ## renumbered the rows after order by 

df3 

Danke für die Unterstützung!

Antwort

3

melt/dcast im reshape2 Paket kann subtotalling tun. wir ersetzen "(all)" im Monat Spalte mit dem Monat nach dcast laufen na.locf aus dem Zoo-Paket mit:

library(reshape2) 
library(zoo) 

m <- melt(df, measure.vars = "sales") 
dout <- dcast(m, year + month + region ~ variable, fun.aggregate = sum, margins = "month") 

dout$month <- na.locf(replace(dout$month, dout$month == "(all)", NA)) 

geben:

> dout 
    year month region sales 
1 2016  1 east 400 
2 2016  1 west 600 
3 2016  1 (all) 1000 
4 2017  2 east 800 
5 2017  2 west 1200 
6 2017  2 (all) 2000 
+0

Ihre Antwort ist sehr nah, aber die 3. und 6. Reihe sollte auch mit dem Monat gefüllt werden. Irgendeine Problemumgehung? – freetiger

+0

haben na.loff hinzugefügt, um die Monate in den Zwischensummenzeilen zu füllen, und außerdem eine Schmelze hinzugefügt, die es erlaubt, dass dcast die korrekten Namen erzeugt, ohne sie später zu reparieren. Außerdem wurde die Gesamtsumme entfernt, die nicht erwünscht scheint. –

+0

Dang! Hab deine Erwähnung in einer Zeitschrift gesehen. Sie sind der Schöpfer von Zoo und anderen Klassen. :) – freetiger

-1
plyr::ddply(df, c("year", "month", "region"), plyr::summarise, sales = sum(sales)) 
+1

Dies ist der o/p von df1 in meinem Beispiel (mit Aggregat), nicht die gewünschte Antwort. – freetiger

1

In der letzten Entwick data.table 1.10.5 können Sie neue Funktion verwenden, genannt „Gruppierungsmengen“ sub Summen zu erzeugen:

library(data.table) 
setDT(df) 
res = groupingsets(df, .(sales=sum(sales)), sets=list(c("year","month"), c("year","month","region")), by=c("year","month","region")) 
setorder(res, na.last=TRUE) 
res 
# year month region sales 
#1: 2016  1 east 400 
#2: 2016  1 west 600 
#3: 2016  1  NA 1000 
#4: 2017  2 east 800 
#5: 2017  2 west 1200 
#6: 2017  2  NA 2000 

Sie NA-ersetzen könnenmit res[is.na(region), region := "USA"].