我一直在努力编写最佳代码来估算投资组合回报的月度加权平均值。
我有以下变量:
坚定的股票回报(ret)
month1,year1和date
投资组合(port1):这定义了公司股票收益的投资组合
市值(mcap):估算权重(按月1年1港1)
我想计算每个月的加权回报和按市值加权的投资组合。 (mcap)每个公司。
我编写了以下代码,但这些代码可以正常运行,但需要很长时间并且效率很低:
foreach x in 11 12 13 21 22 23 {
display `x'
forvalues y = 1980/2010 {
display `y'
forvalues m = 1/12 {
display `m'
tempvar tmp_wt tmp_tm tmp_p
egen `tmp_tm' = total(mcap) if month1==`m' & year1==`y' & port1 ==`x'
gen `tmp_wt' = mcap/`tmp_tm' if month1==`m' & year1==`y' & port1 ==`x'
gen `tmp_p' = ret*`tmp_wt' if month1==`m' & year1==`y' & port1 ==`x'
gen port_ret_`m'_`y'_`x' = `tmp_p'
}
}
}
数据如图所示:![价值加权投资组合回报的数据] [1]
答案 0 :(得分:4)
这似乎是一个案例手册,说明如何尽可能慢地做事情,除了你自然没有故意这样做。它所缺乏的只是观察循环来计算总数。所以,好消息是你确实应该加快速度。
似乎归结为
gen double wanted = .
bysort port1 year month : replace wanted = sum(mcap)
by port1 year month : replace wanted = (mcap * ret) / wanted[_N]
原理。要在单个标量中获得总和,请使用summarize, meanonly
而不是使用egen, total()
将该标量重复放入变量中,但使用sum()
和by:
来获取组合和一个变量,当你需要它时,就像这里一样。 sum()
返回累计金额,因此您需要累计金额的最后一个值。
原理。当在foreach
的支持下进行分组计算时,不需要循环(此处使用by:
)。这是Stata程序员需要学习的强大构造。
原理。创建大量临时变量,这里有6 * 31 * 12 * 3 = 6696,它们会减慢速度并使用更多内存。每次执行tempvar
并遵循generate
命令时,还有三个临时变量,数据集中列的所有大小(这是变量在Stata中的变量),但是一旦使用它们他们只是留在记忆中,再也没有看过。对于临时变量而言,tempvar
每次都会分配一个新名称,这是一个微妙之处,但应该清楚generate
每次创建一个新变量; generate
永远不会覆盖现有变量。临时变量都会在程序结束时被删除,但是到那个程序结束时,你会不必要地占用很多东西,可能是数据集的大小乘以大约一千。如果暂时扩展的数据集不能全部适合内存,则可以将Stata翻转为爬行状态。
原理。使用if
迫使Stata依次检查每个观察结果;在这种情况下,大多数与正在执行的循环的特定交集无关,并且您在对数据集的1/2232进行每个特定计算时,使Stata几乎无关地检查所有数据集(2231/2232的一小部分,几乎为1)。如果你有更多的年份或更多的投资组合,那么无关紧要的分数甚至更高。
从本质上讲,Stata将遵守您的指示(而不是尝试任何类型的优化 - 您的代码完全按字面解释)但by:
会更快地提供交叉组合。
请注意。我不知道这些数字会有多大或接近零,所以我给了你一个double
。据我所知,float
对你来说很合适。
注释。我猜你受到其他语言编码经验的影响,其中创建变量意味着类似于x = 42
来保持常量。你也可以在Stata中使用标量或本地或全局宏来做到这一点,更不用说Mata了。请记住, Stata中的新变量是数据集中的全新列,无论它是在每个观察中保持不变还是不同。你会得到你所要求的,但更像是每次都得到一个阵列。同样,您似乎只想要一个新变量作为最终结果,而实际上您根本不需要临时创建任何其他变量。