data.table中的最佳方式,可以从列名字符串的向量中生成多个列

时间:2015-08-19 07:53:09

标签: r data.table

我目前正在尝试使用data.table并寻找最佳的'做事的方式。

我想在下面的例子中做的是有一个带有列名的字符串,追加" .d"对于正常的增量和附加" .dP"百分比增量。 (请记住,字符串中的列只是一个子集而不是完整的data.table,即使我的示例仅限于这些。)

我希望代码尽可能紧凑和快速,同时使用R和data.table的优点。

我目前提出的解决方案是:

percentDelta<-function(newvalue,basevalue){
  return((newvalue-basevalue)/basevalue)
}

normalDelta<-function(newvalue,basevalue){
  return(newvalue-basevalue)
}

DT = data.table(price=c(2,3,4,5,6,7,8), otherMetric=c(3,4,5,1,3,4,5))
deltaColsNames = c("otherMetric")
deltaColsNewNames <- paste0(deltaColsNames,'.d')
percentColsNewNames <- paste0(deltaColsNames,'.dP')

DT[,eval(deltaColsNewNames) := lapply(DT[,eval(deltaColsNames),with=F],normalDelta,price)]
DT[,eval(percentColsNewNames) := lapply(DT[,eval(deltaColsNames),with=F],percentDelta,price)]

我不太确定data.table调用生成多列是否正确?正在使用&#34; lapply&#34;与&#34; eval&#34;一个人会这样做的方式?

编辑:我应该避免使用&#34;使用= F&#34;?

DT[,eval(deltaColsNewNames) := lapply(DT[,which(names(DT) %in% deltaColsNames)],normalDelta,price)]
DT[,eval(percentColsNewNames) := lapply(DT[,which(names(DT) %in% deltaColsNames)],percentDelta,price)]

2 个答案:

答案 0 :(得分:3)

问题#495现已通过this recent commit解决,我们现在可以做到这一点:

require(data.table) # v1.9.7+
DT[, (deltaColsNewNames) := lapply(.SD, normalDelta, price), .SDcols=deltaColsNames]

答案 1 :(得分:1)

因此,为了回答问题并从评论中添加优化,出现了以下答案:

require(data.table) #version 1.9.5 from github needed!

normalDelta<-function(newvalue,basevalue){
  return(newvalue-basevalue)
}

DT = data.table(price=rep(c(3,4,5),each=200000000), otherMetric=sample(c(1,3,6),200000000,T))
deltaColsNames = c("otherMetric")
deltaColsNewNames <- paste0(deltaColsNames,'.d')

场景1,使用“eval”和“with = F”:

system.time(DT[,(deltaColsNewNames) := lapply(DT[,eval(deltaColsNames),with=F],normalDelta,price)])
#   user  system elapsed 
#2.134   1.747   3.880 

场景2,使用“which(names)%in%”来避免字符串作为列索引:

system.time(DT[,(deltaColsNewNames) := lapply(DT[,which(names(DT) %in% deltaColsNames)],normalDelta,price)])
#user  system elapsed 
#1.652   1.105   2.756 

场景3,在1.9.5中使用“.SD”语法和eval()(在1.9.4中,这个速度较慢):

system.time(DT[,(deltaColsNewNames) := lapply(.SD[, eval(deltaColsNames),with=F], normalDelta, price)])
 #user  system elapsed
#2.148   1.847   4.764 

场景4,使用“.SD”语法和1.9.5中的哪个()(在1.9.4中,这也慢了):

system.time(DT[,(deltaColsNewNames) := lapply(.SD[, which(names(DT) %in% deltaColsNames)], normalDelta, price)])
#user  system elapsed 
#1.701   1.117   2.817  

场景5,使用mget():

system.time(DT[, (deltaColsNewNames) := lapply(mget(deltaColsNames), normalDelta, price)])
#user  system elapsed 
#1.426   1.166   2.591 

场景6:mget和.SD合并:

system.time(DT[, (deltaColsNewNames) := lapply(.SD[, mget(deltaColsNames)], normalDelta, price)])
#user  system elapsed 
#2.149   1.788   4.974 

更新:增加数据集的大小后: 情景2和4&amp; 5正在提前出现。 但是,方案5的内存占用量远高于2&4,因为我在使用更大的数据集进行测试时遇到笔记本电脑上的内存问题 (参见上面的更新结果)