Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将向量与大数据表合并以执行计算的高效内存方法(R)_R_Performance_Merge_Data.table_Memory Efficient - Fatal编程技术网

将向量与大数据表合并以执行计算的高效内存方法(R)

将向量与大数据表合并以执行计算的高效内存方法(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 ),

我有一个数据集,包含多个模型预测的基于年份的数据,格式为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 ),   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