2016-07-29 58 views
4

假設我有兩個數據集。其中一個包含開始/結束日期的促銷清單,另一個包含每個程序的月度銷售數據。按日期範圍和分類變量組合數據集

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

請注意,sales$year.month.day用於表示年/月。 Day包含在內,因此R可以更簡單地將列視爲日期對象的向量,但與實際銷售額無關。

我需要確定每個程序每月發生的促銷次數。下面是產生我想要的輸出循環的例子:

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 
     } 
    } 
    } 
} 

輸出示例:

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

但是因爲我的實際數據集是非常大的,這個循環崩潰時我在R.

運行

有沒有更高效的方法來達到同樣的效果?也許與dplyr有什麼關係?

+0

你可以添加所需的輸出數據幀嗎?我不太瞭解你的循環輸出。此外,如果您對每個計劃每月的促銷數量感興趣,爲什麼需要銷售數據框? – thepule

+0

我編輯了帖子以包含我的循環的輸出。該循環將「計數」列添加到原始銷售數據框架。 – heo

+0

對於我的分析,我需要每個程序的銷售額和每月促銷數量,所以是的,銷售數據框是必要的。 – heo

回答

3

我哈德利的包的粉絲:

library(dplyr) 
library(lubridate) 

樓日期,以便他們在相同的格式sales數據框:

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

展開的日期間隔:

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

根據日期範圍,組和計數展開數據框,併合併到日期和時間的銷售ogram:

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

輸出:

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

可以試試?data.table::foverlaps

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 

這基本上是在sales創建間隔柱,由他們加入+通過program,計數重疊,並加入回sales。如果它真的困擾你,你可以通過做sales[, c("start.date", "end.date") := NULL]刪除額外的列。谷歌foverlapsdata.table更多例子

5

你可以用sql來做到這一點。

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

這將首先加入2個數據集,其中年月日的銷售額是在這兩個數據的推廣和程序的啓動和結束日期之間是相同的。那麼它將按ymd進行分組並計數實例。我已經從變量的名稱中刪除了句點。

+0

這似乎每ymd只返回一行。對於某些數據集可能沒問題,但對於每個分類變量都不需要每月計數的那些數據。 – heo

+1

我已經編輯過它,因此它會給出與程序一樣多的ymd。 –

5

使用新實施非等距從data.table目前的開發版本加入:

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 

參見開發安裝說明版本號here