我有以下dt
set.seed(1)
dt <- data.table(expand.grid(c("a","b"),1:2,1:2,c("M","N","O","P","Q")))
dt$perf <- rnorm(nrow(dt),0,.01)
colnames(dt) <- c("ticker","par1","par2","row_names","perf")
我想选择ticker,par1,par2
的最佳组合,以使row_names
上的累积乘积最大化。例如,下面的代码可以做到这一点,但是以data.table
的方式效率不高,我需要这样:
x <- split(dt,list(dt$ticker,dt$par1,dt$par2))
combn <- setDT(expand.grid(seq(1,length(x),2),seq(2,length(x),2)))
res <- data.table()
for(i in 1:nrow(combn)){
tmp <- rbindlist(x[as.numeric(combn[i])])
tmp <- tmp[,list(perf=mean(perf),par1=paste(par1,collapse=","),
par2=paste(par2,collapse=",")),by=row_names]
cumRet <- c(cumRet,tail(cumprod(tmp$perf+1)-1,1))
res <- rbind(res,data.table(cumRet=cumRet,
comb1 = names(x)[as.numeric(combn[i])][1],
comb2=names(x)[as.numeric(combn[i])][2]))
}
res[which.max(cumRet)]
cumRet comb1 comb2
1: 0.02452314 a.2.2 b.1.1
我知道以下代码以data.table
的方式执行类似的操作。但是,它会最大化每个周期的组合,而无需考虑ticker,par1,par2
上的row_names M,N,O,P,Q
相同。我正在寻找与此类似但具有上述实现逻辑的解决方案。
# best possible return
tmp1 <- dt[,list(par1=par1[which.max(perf)],
par2=par2[which.max(perf)],perf=max(perf)),by=list(ticker,row_names)]
res1 <- tmp1[,list(perf=mean(perf),comb1= paste(c(rbind(par1,par2))[1:.N],collapse="."),
comb2=paste(c(rbind(par1,par2))[-1:-.N],collapse=".")),
by=row_names]
row_names perf comb1 comb2
1: M 0.010413549 2.2 2.1
2: N 0.009508122 2.1 2.1
3: O 0.009314068 1.2 1.1
4: P 0.008883106 2.2 1.2
5: Q 0.009316006 2.2 2.2
tail(cumprod(res1$perf+1)-1,1)
[1] 0.0483428
这是执行此操作的另一种方法,但这仍然不是我真正需要的:
# individual way
tmp2 <- dt[,list(perf=tail(cumprod(perf+1)-1,1)),by=list(ticker,par1,par2)]
tmp2 <- tmp2[,list(perf=max(perf),par1=par1[which.max(perf)],
par2=par2[which.max(perf)]),by=ticker]
> tmp2
ticker perf par1 par2
1: a 0.042091594 2 2
2: b 0.007095708 1 1
> mean(tmp2$perf)
[1] 0.02459365
结果与我的实际计算res
非常相似。它给出了正确的组合a.2.2
和b.1.1
。但是,平均值perf
的计算是错误的,因为取平均值然后取累加乘积与取累加乘积取平均值不同。
我需要针对前者的解决方案,而这找到了针对后者的解决方案(并非总是如此,它们会如此接近或具有相同的组合)。
最后,这是执行此操作的另一种方法,但并非完全符合我的需要。下面,我尝试结合par1,par2
来最大化我的结果。但是,在这里,我在两个par1,par2
上都使用了相同的tickers
。我想在par1,par2
上应用相同的row_names
,但允许不同的tickers
使用不同的组合。
# group way
tmp3 <- dt[,.(perf=mean(perf)),by=.(par1,par2,row_names)]
res3 <- tmp3[,.(perf=tail(cumprod(perf+1)-1,1)),by=.(par1,par2)]
res3[which.max(perf)]
> res3[which.max(perf)]
par1 par2 perf
1: 2 2 0.01756057
答案 0 :(得分:0)
这是一种更data.table
的方法!
dt[,id:= paste(ticker,par1,par2,sep=".")]
setkey(dt,id)
combn <- unique(setDT(expand.grid(unique(dt$id)[1:length(unique(dt$id))/2],
unique(dt$id)[(length(unique(dt$id))/2+1):length(unique(dt$id))])))
f1 <- function(x){
return(tail(cumprod(dt[x,.(row_names,perf),by=.EACHI]
[,.(perf=mean(perf)),by=row_names]$perf+1)-1,1))
}
combn[,perf:=apply(combn,1,f1)]
combn[which.max(perf)]
Var1 Var2 perf
1: a.2.2 b.1.1 0.02452314
我不确定如何遍历combn
组合并应用data.table
所使用的f1
方法来使其成为完整的data.table
方法。但是我相信这会使其尽快!
编辑:这是一种几乎完整的data.table
方法!
# create new dt that has all combinations and data
res2 <- rbindlist(lapply(1:nrow(combn),function(i)
dt[as.matrix(combn[i])[1,],.(row_names,perf,comb=.GRP*i)]))
res2 <- res2[,.(perf=mean(perf)),by=.(row_names,comb)]
res2 <- res2[,.(perf=tail(cumprod(perf+1)-1,1)),by=comb]
res2[which.max(perf)]
comb perf
1: 4 0.02452314
> combn[4]
Var1 Var2
1: a.2.2 b.1.1