将向量与大数据表合并以执行计算的高效内存方法(R)
我有一个数据集,包含多个模型预测的基于年份的数据,格式为data.table将向量与大数据表合并以执行计算的高效内存方法(R),r,performance,merge,data.table,memory-efficient,R,Performance,Merge,Data.table,Memory Efficient,我有一个数据集,包含多个模型预测的基于年份的数据,格式为data.table library(data.table) nYears = 20 # real data: 110 nMod = 3 # real data: ~ 100 nGrp = 45 dataset <- data.table( group_code = rep(seq(1:nGrp ), times= 3*nYears ), Year = rep(seq(1:nYears ),
library(data.table)
nYears = 20 # real data: 110
nMod = 3 # real data: ~ 100
nGrp = 45
dataset <- data.table(
group_code = rep(seq(1:nGrp ), times= 3*nYears ),
Year = rep(seq(1:nYears ), each=nGrp ),
value = rnorm(2700 , mean = 10, sd = 2),
var1 = rep (rnorm(nGrp , mean = nMod, sd = 1) , times= nMod*nYears ),
var2 = rep (rnorm(nGrp , mean = 1.5, sd = 0.5) , times= nMod*nYears ),
model = as.character(rep(seq( from = 1, to = nMod ) , each=nGrp *nYears ))
)
setkey(dataset, Year, model)
由于我的原始数据集包含数百个模型,因此此操作的内存效率不高
我需要的最重要的操作,包括根据组别代码、年份和模型生成x的正态分布,平均值=var1,sd=var2。例如:
# key computation
dt [, norm_dist := dnorm (x, var1, var2) , by= .(group_code, Year, model )]
最后一个操作在我的桌面上相当快。但是,我还需要执行其他操作,这些操作需要对data.table进行子集,并且占用大量RAM。例如:
dt[ x %between% c( 2, 5.99), dt2 := rep_len( rev(dt [x %between% c(-2, 1.99)]$value), length.out=.N) , by= .(Year, model) ]
将弹出以下错误消息:
Error: cannot allocate vector of size 1.3 Gb
我相信这个特定步骤中的问题与子集和rev()函数有关
然而,我使用的基于data.table dt中的向量“x”执行一组计算的方法似乎并不合适,因为从我将数据集与计算所需的向量(“x”)合并的那一刻起
我希望有人能教我如何有效地改进代码,因为我在原始数据集中有大量的模型,大大增加了它的大小
谢谢大家! 我认为这部分代码应该更清晰
dt[ x %between% c( 2, 5.99), dt2 := rep_len( rev(dt [x %between% c(-2, 1.99)]$value), length.out=.N) , by= .(Year, model) ]
因为它对我来说有点像一个黑匣子。特别是因为这个双重子集是产生问题的地方
在所有情况下,x%介于%c(2,5.99)
和dt[x%介于%c(-2,1.99)]
之间的这些代码位应始终位于相同的位置。您应该在代码中考虑这一点以使其更有效。
尝试这样做,让事情更清楚一些:
by_YM <- split(dt, by=c("Year", "model"))
ind1 <- which(by_YM[[1]][["x"]] %between% c( 2, 5.99))
ind2 <- which(by_YM[[1]][["x"]] %between% c(-2, 1.99))
for(i in 1:length(by_YM)){
dt_i <- by_YM[[i]]
#val1 <- rep_len(rev(dt_i$value[ind2]), length.out=length(ind1)) #val1 is equal to val, no need for rep_len
val <- rev(dt_i$value[ind2])
by_YM[[i]] <- dt_i[ind1, dt2 := val]
}
by_YM有没有一种方法可以用不包含数百万行的data.table来演示预期结果?在第二个rep_len
s乘以第一个rep_len
s之后,我开始失去对事情的跟踪。亲爱的@r2evans,我做了一些编辑,使我的问题更加清晰。thnks!非常感谢。我希望减少问题集并获得“预期结果”,也许有人可以推荐一种更有效的方法来获得相同的结果。你可以做dt2:=rep_len(rev(dt[condition,value),length.out=.N)
这将略微有助于内存分配。我不确定您的数据范围,但如果您的所有数据点都跨越-2到6,您也可以在子集设置之前进行逻辑比较,例如,ind=x<2;dt[ind==T,dt2:=rep_len(rev(dt[!ind,value]),length.out=.N),by=…]
by_YM <- split(dt, by=c("Year", "model"))
ind1 <- which(by_YM[[1]][["x"]] %between% c( 2, 5.99))
ind2 <- which(by_YM[[1]][["x"]] %between% c(-2, 1.99))
for(i in 1:length(by_YM)){
dt_i <- by_YM[[i]]
#val1 <- rep_len(rev(dt_i$value[ind2]), length.out=length(ind1)) #val1 is equal to val, no need for rep_len
val <- rev(dt_i$value[ind2])
by_YM[[i]] <- dt_i[ind1, dt2 := val]
}
dt2_a <- dt[Year == 20 & model == 3, dt2]
dt2_b <- by_YM[["20.3"]][, dt2]
test <- cbind(dt2_a, dt2_b)
library(microbenchmark)
microbenchmark( "new_code" = {
by_YM <- split(dt, by=c("Year", "model"))
ind1 <- which(by_YM[[1]][["x"]] %between% c( 2, 5.99))
ind2 <- which(by_YM[[1]][["x"]] %between% c(-2, 1.99))
for(i in 1:length(by_YM)){
dt_i <- by_YM[[i]]
val1 <- rep_len(rev(dt_i$value[ind2]), length.out=length(ind1)) #val1 is equal to val, no need for rep_len
val <- rev(dt_i$value[ind2])
by_YM[[i]] <- dt_i[ind1, dt2 := val]
}}, "old_code" = dt[ x %between% c( 2, 5.99),
dt2 := rep_len( rev(dt [x %between% c(-2, 1.99)]$value), length.out=.N) , by= .(Year, model) ],
times = 5)
Unit: milliseconds
expr min lq mean median uq max neval cld
new_code 155.426 156.4916 200.6587 185.0347 188.9436 317.3977 5 a
old_code 1290.909 1299.8570 1398.6866 1370.4526 1471.0569 1561.1574 5 b