在 data.table 内对带时间戳的交易使用动物园的 rollsum
Using zoo's rollsum within data.table on timestamped transactions
与 this question and this one, I'm having trouble calculating a rolling sum. Unlike those questions, I would like to try to use zoo:rollsum
as analogous to the rollapply
answer here 有点相关。 (但如果有更 data.table
的方法,无论如何。)
让我们从一些数据开始:
set.seed(123)
some_dates <- function(){as.Date('1980-01-01') + sort(sample.int(1e4,100))}
d <- data.table(cust_id = c(rep(123,100),rep(456,100)),
purch_dt = c(some_dates(), some_dates()),
purch_amt = round(runif(200, 1, 100),2) )
head(d)
# cust_id purch_dt purch_amt
# 1: 123 1980-01-08 24.63
# 2: 123 1980-09-03 96.27
# 3: 123 1981-02-24 60.54
我想为每个客户做一个滚动的 365 天购买金额总和,在每个交易日计算。
答案here建议采用以下方法:
首先,使用交叉连接为所有客户-日期对创建虚拟行,例如:
setkey(d, cust_id, purch_dt)
dummy <- d[ CJ(unique(cust_id), seq(min(purch_dt), max(purch_dt), by='day') ) ]
# cust_id purch_dt purch_amt
# 1: 123 1980-01-08 24.63
# 2: 123 1980-01-09 NA
# 3: 123 1980-01-10 NA
到目前为止,一切顺利(尽管我确信有办法将这个虚拟 table 收紧到客户级别 min/max purch_dt)。
我的问题是如何使用 rollsumr
计算尾随 365 天总和。
我试过了:
dummy[, purch_365 := rollsumr(x=purch_amt, k=365, na.rm=TRUE) , by=cust_id]
但这会创建 purch_365
作为所有 NA
并给出两个警告,例如:
Warning messages:
1: In `[.data.table`(dummy, , `:=`(purch_365, rollsumr(x = purch_amt, :
Supplied 9550 items to be assigned to group 1 of size 9914 in column 'purch_365' (recycled leaving remainder of 364 items).
我得到 364 = k-1,以及 2 cust_id
秒的 2 个警告。除此之外,我不知所措。
# Desired output:
# cust_id purch_dt purch_amt purch_365
# 1: 123 1980-01-08 24.63 24.63
# 2: 123 1980-09-03 96.27 120.90
# 3: 123 1981-02-24 60.54 156.81
提前致谢!
这完全是在黑暗中拍摄,因为我没有完全理解你的问题,但也许将 purch_amt 中的 NA 值变成数字 0 可能会解决问题? R 可能将 NA 值加在一起,这将导致答案为 NA。
例如NA + 1 = NA
。尝试将这些 NA 值更改为零。
这是一种方法。首先,添加一个包含您关心的最后日期的列,以及一个用于跟踪事物的索引:
d[, old.date := purch_dt - 365]
d[, idx := .I]
然后在该日期进行滚动连接(假设版本为 1.9.5+),并提取每个匹配项的索引范围(即 .EACHI
):
res = d[d, .(idx = i.idx, seq = idx:i.idx), by = .EACHI, roll = -Inf,
on = c(cust_id = 'cust_id', purch_dt = 'old.date')]
最后,将原始 data.table
与适当的范围进行子集,并计算总和:
d[, purch_365 := d[res$seq, sum(purch_amt), by = res$idx]$V1][]
# cust_id purch_dt purch_amt idx old.date purch_365
# 1: 123 1980-01-08 24.63 1 1979-01-08 24.63
# 2: 123 1980-09-03 96.27 2 1979-09-04 120.90
# 3: 123 1981-02-24 60.54 3 1980-02-25 156.81
# 4: 123 1981-04-01 51.99 4 1980-04-01 208.80
# 5: 123 1981-04-02 40.85 5 1980-04-02 249.65
# ---
#196: 456 2006-01-29 24.72 196 2005-01-29 187.81
#197: 456 2006-02-15 27.78 197 2005-02-15 215.59
#198: 456 2006-09-22 11.00 198 2005-09-22 74.94
#199: 456 2006-09-27 12.67 199 2005-09-27 87.61
#200: 456 2006-11-18 99.13 200 2005-11-18 186.74
与 this question and this one, I'm having trouble calculating a rolling sum. Unlike those questions, I would like to try to use zoo:rollsum
as analogous to the rollapply
answer here 有点相关。 (但如果有更 data.table
的方法,无论如何。)
让我们从一些数据开始:
set.seed(123)
some_dates <- function(){as.Date('1980-01-01') + sort(sample.int(1e4,100))}
d <- data.table(cust_id = c(rep(123,100),rep(456,100)),
purch_dt = c(some_dates(), some_dates()),
purch_amt = round(runif(200, 1, 100),2) )
head(d)
# cust_id purch_dt purch_amt
# 1: 123 1980-01-08 24.63
# 2: 123 1980-09-03 96.27
# 3: 123 1981-02-24 60.54
我想为每个客户做一个滚动的 365 天购买金额总和,在每个交易日计算。
答案here建议采用以下方法:
首先,使用交叉连接为所有客户-日期对创建虚拟行,例如:
setkey(d, cust_id, purch_dt)
dummy <- d[ CJ(unique(cust_id), seq(min(purch_dt), max(purch_dt), by='day') ) ]
# cust_id purch_dt purch_amt
# 1: 123 1980-01-08 24.63
# 2: 123 1980-01-09 NA
# 3: 123 1980-01-10 NA
到目前为止,一切顺利(尽管我确信有办法将这个虚拟 table 收紧到客户级别 min/max purch_dt)。
我的问题是如何使用 rollsumr
计算尾随 365 天总和。
我试过了:
dummy[, purch_365 := rollsumr(x=purch_amt, k=365, na.rm=TRUE) , by=cust_id]
但这会创建 purch_365
作为所有 NA
并给出两个警告,例如:
Warning messages:
1: In `[.data.table`(dummy, , `:=`(purch_365, rollsumr(x = purch_amt, :
Supplied 9550 items to be assigned to group 1 of size 9914 in column 'purch_365' (recycled leaving remainder of 364 items).
我得到 364 = k-1,以及 2 cust_id
秒的 2 个警告。除此之外,我不知所措。
# Desired output:
# cust_id purch_dt purch_amt purch_365
# 1: 123 1980-01-08 24.63 24.63
# 2: 123 1980-09-03 96.27 120.90
# 3: 123 1981-02-24 60.54 156.81
提前致谢!
这完全是在黑暗中拍摄,因为我没有完全理解你的问题,但也许将 purch_amt 中的 NA 值变成数字 0 可能会解决问题? R 可能将 NA 值加在一起,这将导致答案为 NA。
例如NA + 1 = NA
。尝试将这些 NA 值更改为零。
这是一种方法。首先,添加一个包含您关心的最后日期的列,以及一个用于跟踪事物的索引:
d[, old.date := purch_dt - 365]
d[, idx := .I]
然后在该日期进行滚动连接(假设版本为 1.9.5+),并提取每个匹配项的索引范围(即 .EACHI
):
res = d[d, .(idx = i.idx, seq = idx:i.idx), by = .EACHI, roll = -Inf,
on = c(cust_id = 'cust_id', purch_dt = 'old.date')]
最后,将原始 data.table
与适当的范围进行子集,并计算总和:
d[, purch_365 := d[res$seq, sum(purch_amt), by = res$idx]$V1][]
# cust_id purch_dt purch_amt idx old.date purch_365
# 1: 123 1980-01-08 24.63 1 1979-01-08 24.63
# 2: 123 1980-09-03 96.27 2 1979-09-04 120.90
# 3: 123 1981-02-24 60.54 3 1980-02-25 156.81
# 4: 123 1981-04-01 51.99 4 1980-04-01 208.80
# 5: 123 1981-04-02 40.85 5 1980-04-02 249.65
# ---
#196: 456 2006-01-29 24.72 196 2005-01-29 187.81
#197: 456 2006-02-15 27.78 197 2005-02-15 215.59
#198: 456 2006-09-22 11.00 198 2005-09-22 74.94
#199: 456 2006-09-27 12.67 199 2005-09-27 87.61
#200: 456 2006-11-18 99.13 200 2005-11-18 186.74