0

我一直在努力编写最佳代码来估计投资组合收益的每月加权平均值。

我有以下变量:

  • 公司股票收益(ret)

  • 月 1、年 1 和日期

  • 投资组合(port1):这定义了公司股票收益的投资组合

  • 市值(mcap):估计权重(按month1 year1 port1)

我想计算每个月的加权回报和按市值加权的投资组合。(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]

4

1 回答 1

4

这似乎是一个案例书示例,说明了如何尽可能慢地做事,除非你自然不是故意这样做的。它所缺少的只是一个循环观察来计算总数。所以,好消息是您确实应该能够加快速度。

它似乎归结为

gen double wanted = . 
bysort port1 year month : replace wanted = sum(mcap) 
by port1 year month : replace wanted = (mcap * ret) / wanted[_N] 

原则。要在单个标量中获得总和,请使用summarize, meanonly而不是 usingegen, total()将该标量重复放入变量中,但在需要时使用sum()withby:将组总和放入变量中,如此处所示。sum()返回累积和,因此您需要累积和的最后一个值。

原则。foreach当可以在 的支持下进行分组计算时,不需要循环(此处使用) by:。这是 Stata 程序员需要学习的一个强大的结构。

原则。创建大量临时变量,这里 6 * 31 * 12 * 3 = 6696 个,会减慢速度并使用比需要更多的内存。每次执行tempvar和执行generate命令时,都会有另外三个临时变量,所有数据集中列的大小(这就是 Stata 中的变量),但是一旦使用它们,它们就会留在内存中,从不查看再次。每次都分配一个新名称是临时变量的一个微妙之处tempvar,但应该清楚的是generate每次都会创建一个新变量;generate永远不会覆盖现有的变量。临时变量将在程序结束时全部删除,但到该程序结束时,您会持有很多不必要的东西,可能是数据集的大小乘以大约一千。如果该临时扩展的数据集无法全部放入内存中,则您将 Stata 翻转为爬行。

原则。使用if强制 Stata 依次检查每个观察结果;在这种情况下,大多数与正在执行的循环的特定交集无关,并且您让 Stata 检查几乎所有数据集(2231/2232 的一小部分,几乎是 1),同时对数据集的 1/2232 进行每次特定计算。如果您有更多年或更多投资组合,则无关紧要的分数会更高。

本质上,Stata 会遵守您的指示(并且不会尝试任何类型的优化——您的代码是完全按字面解释的),但by:会更快地提供交叉组合。

笔记。我不知道这些数字会有多大或接近于零,所以我给了你一个double. 据我所知,afloat对你有用。

评论。我猜你正受到其他语言编码经验的影响,在这些语言中,创建变量意味着类似于x = 42保持一个常数。你也可以在 Stata 中使用标量或本地或全局宏,更不用说 Mata 了。请记住,Stata 中的新变量是数据集中的一个全新列,无论它在每个观察值中是保持不变还是不同的值。你会得到你想要的,但它更像是每次都得到一个数组。同样,您最终似乎只想要一个新变量,实际上您根本不需要临时创建任何其他变量。

于 2015-02-22T00:55:02.727 回答