如何在data.table中高效利用多列值自定义函数计算新列
高效实现data.table中动态列的自定义行计算
我在用data.table处理包含多列的数据集,需要根据部分列的值为每行计算专属新列。简单函数可以用.SDcols实现,但遇到需要区分列值处理的自定义逻辑时就比较麻烦。
数据集结构
Training Age Client1 Stim1.0 Stim1.1 Client2 Stim2.0 Stim2.1 Choice Val.00 Val.01 1: 0 1 absence 0 0 absence 0 0 2 0 0 2: 0 2 absence 0 0 absence 0 0 2 0 0 3: 0 3 Object 1 1 1 Object 2 2 2 1 0 0 4: 0 4 Object 2 2 1 Object 2 2 1 1 0 0 5: 0 5 absence 0 0 absence 0 0 2 0 0 6: 0 6 absence 0 0 absence 0 0 2 0 0 Val.02 alpha.0 Val.10 Val.11 Val.12 alpha.1 V25 1: 0.0000 0.005 0 0.0000 0.0000 0.005 NA 2: 0.0000 0.005 0 0.0000 0.0000 0.005 NA 3: 0.0025 0.005 0 0.0000 0.0025 0.005 NA 4: 0.0050 0.005 0 0.0025 0.0025 0.005 NA 5: 0.0050 0.005 0 0.0025 0.0025 0.005 NA 6: 0.0050 0.005 0 0.0025 0.0025 0.005 NA
小列数场景的实现(fcase)
当Stim和Val列数量较少时,可以直接用fcase硬编码实现:
rawData[,`:=`(Val.Client1=fcase(Stim1.0==0,Val.00, Stim1.0==1,Val.01,Stim1.0==2,Val.02)+ fcase(Stim1.1==0,Val.10, Stim1.1==1,Val.11,Stim1.1==2,Val.12), Val.Clien2=fcase(Stim2.0==0,Val.00, Stim2.0==1,Val.01,Stim2.0==2,Val.02)+ fcase(Stim2.1==0,Val.10, Stim2.1==1,Val.11,Stim2.1==2,Val.12))]
当前通用但低效的实现(apply+.SDcols)
由于不同数据集的列数不固定,我写了通用代码,但用apply逐行处理速度极慢:
numSti<-2; numFeat<-2 # 定义预期的列数参数 rawData[,Val.Client1:=apply(.SD,MARGIN = 1,FUN = function(x){ x<-as.numeric(x) # 必须强制转为数值型 Stim1.tmp<-x[1:numSti]+1 # 提取Stim相关列的值并调整索引 vals<-x[(numSti*2+1): (numSti*2+numSti*(1+numFeat))] # 提取Val相关列的值 locVal<-Stim1.tmp+(numFeat+1)*(0:(numSti-1)) # 映射Stim值到对应的Val列索引 return(sum(vals[locVal])) # 对选中的Val值求和 }),.SDcols=patterns("Stim.|Val.")]
数据集dput输出
as.data.table(structure(list(Age = 1:6, Client1 = c(2L, 2L, 0L, 1L, 2L, 2L), Stim1.0 = c(0L, 0L, 1L, 2L, 0L, 0L), Stim1.1 = c(0L, 0L, 1L, 1L, 0L, 0L), Client2 = c(2L, 2L, 1L, 1L, 2L, 2L), Stim2.0 = c(0L, 0L, 2L, 2L, 0L, 0L), Stim2.1 = c(0L, 0L, 2L, 1L, 0L, 0L), Choice = c(2L, 2L, 1L, 1L, 2L, 2L), Val.00 = c(0, 0, 0, 0, 0, 0), Val.01 = c(0, 0, 0, 0, 0, 0), Val.02 = c(0, 0, 0.0025, 0.005, 0.005, 0.005), alpha.0 = c(0.005, 0.005, 0.005, 0.005, 0.005, 0.005), Val.10 = c(0, 0, 0, 0, 0, 0), Val.11 = c(0, 0, 0, 0.0025, 0.0025, 0.0025), Val.12 = c(0, 0, 0.0025, 0.0025, 0.0025, 0.0025), alpha.1 = c(0.005, 0.005, 0.005, 0.005, 0.005, 0.005), V25 = c(NA, NA, NA, NA, NA, NA)), row.names = c(NA, -6L), class = c("data.table", "data.frame")))
求高效的通用解决方案,能避免逐行处理的性能问题。
内容的提问来源于stack exchange,提问作者Andres Eduardo Quiñones
相关产品推荐
相关产品推荐

