R//如果满足data.table中其他列中的多个条件,则计算行数并求和列值//高效&;快速数据表解决方案

R//如果满足data.table中其他列中的多个条件,则计算行数并求和列值//高效&;快速数据表解决方案,r,performance,data.table,conditional-statements,R,Performance,Data.table,Conditional Statements,我有一个很大的数据表(~4100万行*20+col),我想根据数据表其他行的结果进行行计算。具体来说,我想做一些计算。 (1) 计算在每次采购交易(时间戳)时,特定ID(col ID)所做的销售交易(ID自_ID)的数量 (2) ID在每次采购交易(col ID)时所做的总销售额(col Value//from_ID)之和 我有一个可行的解决方案,但是效率很低,速度也很慢。我想知道是否有更快/更有效(可能)的基于data.table的解决方案来解决此问题 这是我的重复示例,我要计算的列是“以前的

我有一个很大的数据表(~4100万行*20+col),我想根据数据表其他行的结果进行行计算。具体来说,我想做一些计算。 (1) 计算在每次采购交易(时间戳)时,特定ID(col ID)所做的销售交易(ID自_ID)的数量 (2) ID在每次采购交易(col ID)时所做的总销售额(col Value//from_ID)之和

我有一个可行的解决方案,但是效率很低,速度也很慢。我想知道是否有更快/更有效(可能)的基于data.table的解决方案来解决此问题

这是我的重复示例,我要计算的列是“以前的销售额”和“以前的销售额”:

资料
timestamp=c(
"2018-04-04 00:39:02", "2018-06-04 00:50:22", "2018-09-04 03:07:29", 
"2018-12-04 02:15:57", "2018-08-04 02:15:57", "2018-09-04 02:15:57", 
"2018-10-04 02:15:57", "2018-12-20 02:15:57"
) 
ID=作为字符(c(1,1,1,1,10,9,8,7))
from_ID=as.字符(c(4,5,4,8,1,1,1,1))
值=c(100150,50200,50100150,40)
data\u sample=as.data.frame(cbind(timestamp,ID,from\u ID,Value),stringsAsFactors=F)
data_sample$timestamp=as.POSIXct(data_sample$timestamp)
数据样本$Value=as.numeric(数据样本$Value)
#接近
Previor_sales=data.frame()
以前的销售额金额=data.frame()
对于(1:nrow中的i(数据样本)){
行=数据\样本[i,]
销售=子集(数据样本,数据样本$from\u ID==行$ID和数据样本$timestamp<行$timestamp)
以前的=现在的(销售)
前期销售=rbind(前期销售,前期销售)
Previor_s_a=ifelse(Previor_s==0,0,总和(销售美元价值))
前期销售金额=rbind(前期销售金额,前期销售金额)
}
数据样本=cbind(数据样本、前期销售、前期销售金额)
这里有些东西

library(data.table)
setDT(data_sample)
data_sample[, c("X0L", "X0") := data_sample[.SD, 
                                            on = .(from_ID = ID, timestamp < timestamp), 
                                            .(X0L = .N, X0 = sum(Value, na.rm = TRUE)), 
                                            by = .EACHI
                                            ][, 
                                              .(X0L, X0)]]


             timestamp ID from_ID Value X0L  X0
1: 2018-04-04 00:39:02  1       4   100   0   0
2: 2018-06-04 00:50:22  1       5   150   0   0
3: 2018-09-04 03:07:29  1       4    50   2 150
4: 2018-12-04 02:15:57  1       8   200   3 300
5: 2018-08-04 02:15:57 10       1    50   0   0
6: 2018-09-04 02:15:57  9       1   100   0   0
7: 2018-10-04 02:15:57  8       1   150   0   0
8: 2018-12-20 02:15:57  7       1    40   0   0
库(data.table)
setDT(数据样本)
数据样本[,c(“X0L”,“X0”):=数据样本[.SD,
on=(from_ID=ID,timestamp
在base R中,您可以执行此操作

data_sample <- cbind(data_sample, t(apply(data_sample, 1, function(x) {
  r <- data_sample[data_sample$from_ID == x[["ID"]] &
                     data_sample$timestamp < x[["timestamp"]], ]
  c(x1=NROW(r), x2=sum(r$Value))
})))

data_sample
#             timestamp ID from_ID Value x1  x2
# 1 2018-04-04 00:39:02  1       4   100  0   0
# 2 2018-06-04 00:50:22  1       5   150  0   0
# 3 2018-09-04 03:07:29  1       4    50  2 150
# 4 2018-12-04 02:15:57  1       8   200  3 300
# 5 2018-08-04 02:15:57 10       1    50  0   0
# 6 2018-09-04 02:15:57  9       1   100  0   0
# 7 2018-10-04 02:15:57  8       1   150  0   0
# 8 2018-12-20 02:15:57  7       1    40  0   0

data\u sample这里是使用滚动连接的另一个选项:

#small tweak to timestamp to take care of < rather than <=
lu <- data_sample[, .(timestamp=timestamp+1, x1=1L:.N, x2=cumsum(Value)), from_ID]

#rolling join to look up the latest figures
data_sample[, c("x1", "x2") := lu[.SD, on=.(from_ID=ID, timestamp), roll=Inf,
    .(fcoalesce(x1, 0L), fcoalesce(x2, 0))]]

工作完美,比我的解决方案快得多,谢谢!附加问题:当应用到我的数据集时,我得到了这个错误,不知道如何解决它。我知道它不可复制,但你知道如何解决它吗:集合中的错误(origi,j=lc,value=factor(origi[[lc]]):.SD被锁定。使用:=或set通过引用更新.SD保留供将来使用。直接在j中使用:=。或者使用copy(.SD)作为(缓慢的)最后手段,直到shallow()被导出。@Carolin您使用的是最新版本的
data.table
?可能的解决方案是尝试用
数据样本
替换
.SD
?如果你能发布一个可复制的例子,那就太好了。是的,同样有效,而且对我来说更容易理解:-)。然而,data.table解决方案速度非常快,这与我的大型数据集有很大区别。谢谢你的帮助!好的,我的问题是变量是一个因子而不是一个字符,现在可以正常工作:-)
#small tweak to timestamp to take care of < rather than <=
lu <- data_sample[, .(timestamp=timestamp+1, x1=1L:.N, x2=cumsum(Value)), from_ID]

#rolling join to look up the latest figures
data_sample[, c("x1", "x2") := lu[.SD, on=.(from_ID=ID, timestamp), roll=Inf,
    .(fcoalesce(x1, 0L), fcoalesce(x2, 0))]]
library(data.table)
set.seed(0L)
nr <- 1e6
nID <- 1e4
data_sample <- data.table(ID=sample(nID, nr, TRUE), from_ID=sample(nID, nr, TRUE), 
    timestamp=1522773542 + sample(nr*10, nr), Value=rnorm(nr))
setorder(data_sample, ID, timestamp, from_ID)
DT0 <- copy(data_sample)
DT1 <- copy(data_sample)

mtd0 <- function() {
    DT0[, c("x1", "x2") := 
        .SD[.SD, on = .(from_ID = ID, timestamp < timestamp), 
            .(X0L = .N, X0 = sum(Value, na.rm = TRUE)), 
            by = .EACHI
        ][, .(X0L, X0)]]    
}

mtd1 <- function() {
    lu <- DT1[, .(timestamp=timestamp+1, x1=1L:.N, x2=cumsum(Value)), from_ID]
    DT1[, c("x1", "x2") := lu[.SD, on=.(from_ID=ID, timestamp), roll=Inf,
        .(fcoalesce(x1, 0L), fcoalesce(x2, 0))]]
}

fsetequal(DT0, DT1)
#[1] TRUE

microbenchmark::microbenchmark(mtd0(), mtd1(), times=1L)
Unit: milliseconds
   expr      min       lq     mean   median       uq      max neval
 mtd0() 1468.356 1468.356 1468.356 1468.356 1468.356 1468.356     1
 mtd1()  248.641  248.641  248.641  248.641  248.641  248.641     1