2016-07-29 25 views
4

Angenommen, ich habe zwei Datensätze. Einer enthält eine Liste von Werbeaktionen mit Start-/Enddatum, und der andere enthält monatliche Verkaufsdaten für jedes Programm.Kombinieren Sie Datensätze nach Datumsbereich und kategorischer Variable

promotions = data.frame(
    start.date = as.Date(c("2012-01-01", "2012-06-14", "2012-02-01", "2012-03-31", "2012-07-13")), 
    end.date = as.Date(c("2014-04-05", "2014-11-13", "2014-02-25", "2014-08-02", "2014-09-30")), 
    program = c("a", "a", "a", "b", "b")) 

sales = data.frame(
    year.month.day = as.Date(c("2013-02-01", "2014-09-01", "2013-08-01", "2013-04-01", "2012-11-01")), 
    program = c("a", "b", "a", "a", "b"), 
    monthly.sales = c(200, 200, 200, 400, 200)) 

Beachten Sie, dass sales$year.month.day verwendet wird Jahr/Monat anzuzeigen. Tag ist enthalten, so dass R die Spalte einfacher als Vektor von Datumsobjekten behandeln kann, aber für die tatsächlichen Verkäufe nicht relevant ist.

Ich muss die Anzahl der Aktionen, die pro Monat für jedes Programm aufgetreten sind, ermitteln. Hier ist ein Beispiel für eine Schleife, die die Ausgabe erzeugt, ich will:

sales$count = rep(0, nrow(sales)) 
sub = list() 
for (i in 1:nrow(sales)) { 
    sub[[i]] = promotions[which(promotions$program == sales$program[i]),] 
    if (nrow(sub[[i]]) > 1) { 
    for (j in 1:nrow(sub[[i]])) { 
     if (sales$year.month.day[i] %in% seq(from = as.Date(sub[[i]]$start.date[j]), to = as.Date(sub[[i]]$end.date[j]), by = "day")) { 
     sales$count[i] = sales$count[i] + 1 
     } 
    } 
    } 
} 

Beispiel Ausgabe:

sales = data.frame(
    year.month.day = as.Date(c("2013-02-01", "2014-09-01", "2013-08-01", "2013-04-01", "2012-11-01")), 
    program = c("a", "b", "a", "a", "b"), 
    monthly.sales = c(200, 200, 200, 400, 200), 
    count = c(3, 1, 3, 3, 2) 
) 

jedoch seit meiner eigentlichen Datensätze sehr groß sind, diese Schleife stürzt ab, wenn ich es in R. laufen

Gibt es einen effizienteren Weg, um das gleiche Ergebnis zu erzielen? Vielleicht etwas mit dplyr?

+0

Können Sie den gewünschten Ausgabedatenrahmen hinzufügen? Ich verstehe die Ausgabe Ihrer Schleife nicht wirklich. Auch wenn Sie an der Anzahl der Aktionen pro Monat pro Programm interessiert sind, warum benötigen Sie den Verkaufsdatenrahmen? – thepule

+0

Ich habe den Beitrag bearbeitet, um die Ausgabe meiner Schleife einzuschließen. Die Schleife fügt dem ursprünglichen Verkaufsdatenrahmen eine "Zähl" -Spalte hinzu. – heo

+0

Für meine Analyse brauche ich Umsatz und die Anzahl der Promotionen pro Monat für jedes Programm, also ja, der Umsatzdatenrahmen ist notwendig. – heo

Antwort

3

Ich bin ein Fan von Hadleys Pakete:

library(dplyr) 
library(lubridate) 

Bodendaten, so dass sie im gleichen Format wie die sales Datenrahmen sind:

df <- promotions %>% 
    mutate(start.date = floor_date(start.date, unit = "month"), 
      end.date = floor_date(end.date, unit = "month")) 

erweitern die Datumsintervalle:

df$output <- mapply(function(x,y) seq(x, y, by = "month"), 
     df$start.date, 
     df$end.date) 

Erweitern Sie den Datenrahmen basierend auf den Datumsbereichen, der Gruppe und der Anzahl, und führen Sie die Zusammenführung mit den Verkäufen nach Datum und pr durch Jean-Pierre Gerber:

df %>% tidyr::unnest(output) %>% 
    group_by(output, program) %>% 
    summarise(prom_num = n()) %>% 
    merge(sales, ., 
     by.x = c("year.month.day", "program"), 
     by.y = c("output", "program")) 

Ausgang:

year.month.day program monthly.sales prom_num 
1  2012-11-01  b   200  2 
2  2013-02-01  a   200  3 
3  2013-04-01  a   400  3 
4  2013-08-01  a   200  3 
5  2014-09-01  b   200  1 
3

konnte ?data.table::foverlaps versuchen für diese

library(data.table) 
setDT(sales)[, c("start.date", "end.date") := year.month.day] # Add overlap cols 
setkey(sales, program, start.date, end.date) # Key for join 
res <- foverlaps(setDT(promotions), sales)[, .N, by = year.month.day] # Count joins 
sales[res, count := i.N, on = "year.month.day"] # Update `sales` with results 
sales 
# year.month.day program monthly.sales start.date end.date count 
# 1:  2013-02-01  a   200 2013-02-01 2013-02-01  3 
# 2:  2013-04-01  a   400 2013-04-01 2013-04-01  3 
# 3:  2013-08-01  a   200 2013-08-01 2013-08-01  3 
# 4:  2012-11-01  b   200 2012-11-01 2012-11-01  2 
# 5:  2014-09-01  b   200 2014-09-01 2014-09-01  1 

Dies ist im Grunde Intervall Spalte in sales schafft, schließt sich ihnen von + von program zählt Überschneidungen, und schließt sich an sales zurück. Sie könnten die zusätzlichen Spalten entfernen, indem Sie sales[, c("start.date", "end.date") := NULL] tun, wenn es Sie wirklich stört. Google foverlaps und data.table für weitere Beispiele

5

Sie können dies mit SQL tun.

library(sqldf) 
sqldf("select s.ymd,p.program,s.monthlysales, count(*) from promotions p outer left join sales s on p.program=s.program 
where s.ymd between p.startdate and p.enddate and p.program=s.program group by s.ymd, s.program") 

Dies würde die 2 Datensatz zunächst verbinden, in der ymd Umsatz zwischen dem Start- und Enddatum der Förderung und Programm in den beiden Daten gleich ist. dann würde es nach ymd gruppieren und die Instanz zählen. Ich habe die Perioden aus den Namen der Variablen entfernt.

+0

Dies scheint nur eine Zeile pro ymd zurückzugeben. Es könnte für einige Datensätze in Ordnung sein, aber nicht für solche, die monatliche Zählungen für jede kategorische Variable benötigen. – heo

+1

Ich habe es so bearbeitet, dass es Ihnen so viele ymd gibt, wie es Programme gibt. –

5

Mit dem neu implementierten nicht-equi aus der aktuellen Entwicklungsversion von data.table verbindet:

require(data.table) # v1.9.7+ 
setDT(promotions) # convert to data.table by reference 
setDT(sales) 

ans = promotions[sales, .(monthly.sales, .N), by=.EACHI, allow.cartesian=TRUE, 
     on=.(program, start.date<=year.month.day, end.date>=year.month.day), nomatch=0L] 

ans[, end.date := NULL] 
setnames(ans, "start.date", "year.month.date") 
# program year.month.date monthly.sales N 
# 1:  a  2013-02-01   200 3 
# 2:  b  2014-09-01   200 1 
# 3:  a  2013-08-01   200 3 
# 4:  a  2013-04-01   400 3 
# 5:  b  2012-11-01   200 2 

Installationsanleitung finden Sie für die Entwicklung Version here.