2014-04-30 57 views
2

滾子data.table聚集我沿着這些線路與日期

d1 <- data.frame(
    cat1 = sample(c('a', 'b', 'c'), 100, replace = TRUE), 
    date = rep(Sys.Date() - sample(1:100)), 
    val = rnorm(100, 50, 5) 
) 

require(data.table) 

d2 <- data.table(d1) 

一組數據,我可以每天和沒有問題

d2[ , list(.N, sum(val)), by = c("cat1", "date")] 

我希望得到一個求和2天(和然後7天)

這工作:

d.list <- sort(unique(d2$date)) 
o.list <- list() 

for(i in seq_along(d.list)){ 
    o.list[[i]] <- d2[d2$date >= d.list[i] - 1 & d2$date <= d.list[i], list(.N, sum(val), max(date)), by = c("cat1")] 
} 

do.call(rbind, o.list) 

但是減慢了一個更大的數據集,並且似乎並不是data.table的最佳用法。

有沒有更高效的方法?

+0

首先,你需要什麼'N'列?對於每日總和只是做'd2 < - setDT(d1)[,sum(val),by = c(「cat1」,「date」)]' –

回答

0

是否可以設置分箱日期,然後對此做by

d2$day7 <- as.integer(d2$date) %/% 7 
d2[ , list(.N, sum(val)), by = c("cat1", "day7")] 

這會給一個分箱值 - 如果你想要一個滑動的7天窗口,我需要再想一想。另外,對於分組方法,如果您想選擇組開始的星期幾,則可能需要在執行%/%之前減去偏移量。

+0

我會試試看 - 謝謝。我確實需要一個滑動窗口,並且日期不規則(跳過日期) –

3

這是一個有點快:

首先,我們加入了精確匹配,並獲得了最後一個索引(在多場比賽的情況下)

setkey(d2, cat1, date) 
tmp1 = d2[unique(d2, by=key(d2)), which=TRUE, mult="last", allow.cartesian=TRUE] 

然後,我們構造的d2一個copy和改變datedate-1,通過參考。然後,我們與roll=-Inf進行加入 - 這是下一個觀察結果向後。換句話說,如果沒有完全匹配,它將填充下一個可用值。

d3 = copy(d2)[, date := date-1] 
setkey(d3, cat1, date) 
tmp2 = d2[unique(d3, by=key(d2)), roll=-Inf, which=TRUE, allow.cartesian=TRUE] 

從這裏,我們放在一起指數:

idx1 = tmp1-tmp2+1L 
idx2 = data.table:::vecseq(tmp2, idx1, sum(idx1)) 

子集d2idx2和生成唯一的ID從idx1

ans1 = d2[idx2][, grp := rep(seq_along(idx1), idx1)] 

最後的總量,除以grp,並得到想要的結果:

ans1 = ans1[, list(cat1=cat1[1L], date=date[.N], 
     N = .N, val=sum(val)), by=grp][, grp:=NULL] 
> head(ans1, 10L) 
#  cat1  date N  val 
# 1: a 2014-01-20 1 47.69178 
# 2: a 2014-01-25 1 52.01006 
# 3: a 2014-02-01 1 46.82132 
# 4: a 2014-02-06 1 44.62404 
# 5: a 2014-02-11 1 49.63218 
# 6: a 2014-02-14 1 48.80676 
# 7: a 2014-02-22 1 49.27800 
# 8: a 2014-02-23 2 96.17617 
# 9: a 2014-02-26 1 49.20623 
# 10: a 2014-02-28 1 46.72708 

結果與您的解決方案中相同。這個在我的筆記本電腦上花費了0.02秒,在那裏你的花費了0.58秒。


7天,只是改變:

d3 = copy(d2)[, date := date-1] 

d3 = copy(d2)[, date := date-6] 
+0

非常感謝@Arun。我會通過這個工作,並嘗試瞭解步驟 –

+0

@EdG,祝你好運:) –

+0

嗨,你知道這是否仍然是當前版本的'data.table'的方式,或者有在過去的三年中'data.table'的一些變化會使這個計算變得更容易(理解:))? – ira

1

它在你想要的OP解釋很差,但是這似乎是它:

# generate the [date-1,date] sequences for each date 
# adjust length.out to suit your needs 
dates = d2[, list(date.seq = seq(date, by = -1, length.out = 2)), by = date] 

setkey(dates, date.seq) 
setkey(d2, date) 

# merge and extract info needed 
dates[d2][, list(.N, sum(val), date.seq[.N]), by = list(date, cat1)][, 
      !"date", with = F] 
#  cat1 N  V2   V3 
# 1: a 1 38.95774 2014-01-21 
# 2: a 1 38.95774 2014-01-21 
# 3: c 1 55.68445 2014-01-22 
# 4: c 2 102.20806 2014-01-23 
# 5: c 1 46.52361 2014-01-23 
# ---        
#164: c 1 50.17986 2014-04-27 
#165: b 1 51.43489 2014-04-28 
#166: b 2 100.91982 2014-04-29 
#167: b 1 49.48493 2014-04-29 
#168: c 1 54.93311 2014-04-30