我一直在努力编写最优的代码来估计月平均投资组合的收益。
我有以下变量:
我想计算每个月的加权回报和按市值加权的投资组合。(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'
}
}
}
数据看起来如图像中所示:
发布于 2015-02-21 16:55:02
这似乎是一个例子,说明如何尽可能慢地做事情,除了你自然不是故意这样做的。它所缺少的只是一个循环的观测来计算总数。因此,好消息是,你确实应该能够加快速度。
它似乎可以归结为
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()
返回累积和,因此您需要累积和的最后一个值。
原则。当groupwise计算可以在foreach
的支持下完成时,不需要循环(这里使用by:
)。这是Stata程序员需要学习的一个强大的构造。
原则。创建大量临时变量(在这里6* 31 * 12 *3= 6696 )将减缓速度,使用比所需的内存更多的内存。每次执行tempvar
并执行generate
命令时,都会有另外三个临时变量,它们都是dataset中列的大小(这就是Stata中变量的大小),但是一旦使用了它们,它们就会留在内存中,再也不会被查看了。这是一个临时变量的微妙之处,tempvar
每次都会指定一个新的名称,但是应该很清楚,generate
每次都会创建一个新变量;generate
永远不会覆盖现有的变量。临时变量都会在程序结束时被删除,但是在程序结束时,您会不必要地保存很多东西,可能是数据集的大小乘以大约1000。如果临时扩展的数据集不能全部存储在内存中,则可以将Stata翻转为爬行。
原则。使用if
要求Stata依次检查每个观察;在这种情况下,大多数与正在执行的循环的特定交点无关,因此在对数据集的1/2232进行每个特定计算时,Stata检查几乎所有的数据集(分数为2231/2232,几乎为1)。如果你有更多的年,或者更多的投资组合,那么看起来不相关的比例就更高了。
本质上,Stata将服从您的指示(而不是尝试任何类型的优化--您的代码是完全按字面解释的),但是by:
会给出更快的交叉组合。
请注意。我不知道这些数字会有多大或接近于零,所以我给了你一个double
。据我所知,float
对你来说很好。
备注。我猜您正在受到其他语言的编码经验的影响,在其他语言中,创建变量意味着类似于x = 42
来保持常量。您也可以在Stata中这样做,使用标量或本地或全局宏,更不用说Mata了。请记住,( Stata中的一个新变量)是dataset中的一个完整的新列,无论它在每个观察中持有一个常数还是不同的值。你会得到你想要的东西,但这更像是每次都得到一个数组。同样,您似乎只需要一个新变量作为最终结果,而且实际上根本不需要创建任何其他变量。
https://stackoverflow.com/questions/28652615
复制