Stata:估计投资组合的每月加权平均值
Stata: estimating monthly weighted mean for portfolio
我一直在努力编写最佳代码来估算投资组合的每月加权平均值 returns。
我有以下变量:
固定库存returns(ret)
1 月、1 年和日期
portfolio (port1): 这定义了公司股票的投资组合 returns
市值(mcap):估算权重(按月1年1端口1)
我想计算每个月的加权 returns 和按市值加权的投资组合。每家公司的 (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'
}
}
}
数据如图所示:![价值加权投资组合的数据 return][1]
这看起来确实是一个如何尽可能慢地做事的案例示例,只是您自然不会故意那样做。它所缺少的只是一个循环观察以计算总数。所以,好消息是你确实应该能够加快速度。
似乎可以归结为
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()
returns 累计和,所以你想要累计和的最后一个值。
原则。当可以在 by:
的支持下进行分组计算时,不需要循环(此处使用 foreach
)。这是 Stata 程序员需要学习的强大结构。
原则。创建大量临时变量,这里有 6 * 31 * 12 * 3 = 6696 个,会减慢速度并使用比需要更多的内存。每次执行 tempvar
并执行 generate
命令时,都会多出三个临时变量,它们都是数据集中一列的大小(这就是 Stata 中的变量),但是一旦它们被使用他们只是留在记忆中,再也没有看过。临时变量的一个微妙之处是 tempvar
每次都分配一个新名称,但应该清楚 generate
每次都创建一个新变量; generate
永远不会覆盖现有变量。临时变量将在程序结束时全部删除,但到该程序结束时,您会持有很多不必要的东西,可能是数据集的大小乘以大约一千。如果那个临时扩展的数据集不能全部放入内存,你可以让 Stata 陷入困境。
原则。使用 if
迫使 Stata 依次检查每个观察结果;在这种情况下,大多数与正在执行的循环的特定交集无关,并且您让 Stata 检查几乎所有数据集(2231/2232 的一小部分,几乎是 1),同时对数据集的 1/2232 进行每个特定计算。如果你有更多的年头或更多的投资组合,那么无关紧要的部分就会更高。
本质上,Stata 会服从您的指示(并且不会尝试任何类型的优化——您的代码完全按字面解释)但是 by:
会更快地给出交叉组合。
注意。我不知道这些数字会有多大或接近于零,所以我给了你一个 double
。据我所知,float
对您来说效果很好。
评论。我猜您正在受到其他语言的编码经验的影响,在这些语言中创建变量意味着类似于 x = 42
的东西来保持常量。你也可以在 Stata 中做到这一点,使用标量或局部或全局宏,更不用说 Mata 了。请记住,Stata 中的新变量是数据集中的一个全新列,无论它在每个观察中是保持不变还是不同的值。你会得到你所要求的,但它更像是每次都得到一个数组。同样,您似乎只需要一个新变量作为最终结果,实际上您根本不需要临时创建任何其他变量。
我一直在努力编写最佳代码来估算投资组合的每月加权平均值 returns。
我有以下变量:
固定库存returns(ret)
1 月、1 年和日期
portfolio (port1): 这定义了公司股票的投资组合 returns
市值(mcap):估算权重(按月1年1端口1)
我想计算每个月的加权 returns 和按市值加权的投资组合。每家公司的 (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'
}
}
}
数据如图所示:![价值加权投资组合的数据 return][1]
这看起来确实是一个如何尽可能慢地做事的案例示例,只是您自然不会故意那样做。它所缺少的只是一个循环观察以计算总数。所以,好消息是你确实应该能够加快速度。
似乎可以归结为
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()
returns 累计和,所以你想要累计和的最后一个值。
原则。当可以在 by:
的支持下进行分组计算时,不需要循环(此处使用 foreach
)。这是 Stata 程序员需要学习的强大结构。
原则。创建大量临时变量,这里有 6 * 31 * 12 * 3 = 6696 个,会减慢速度并使用比需要更多的内存。每次执行 tempvar
并执行 generate
命令时,都会多出三个临时变量,它们都是数据集中一列的大小(这就是 Stata 中的变量),但是一旦它们被使用他们只是留在记忆中,再也没有看过。临时变量的一个微妙之处是 tempvar
每次都分配一个新名称,但应该清楚 generate
每次都创建一个新变量; generate
永远不会覆盖现有变量。临时变量将在程序结束时全部删除,但到该程序结束时,您会持有很多不必要的东西,可能是数据集的大小乘以大约一千。如果那个临时扩展的数据集不能全部放入内存,你可以让 Stata 陷入困境。
原则。使用 if
迫使 Stata 依次检查每个观察结果;在这种情况下,大多数与正在执行的循环的特定交集无关,并且您让 Stata 检查几乎所有数据集(2231/2232 的一小部分,几乎是 1),同时对数据集的 1/2232 进行每个特定计算。如果你有更多的年头或更多的投资组合,那么无关紧要的部分就会更高。
本质上,Stata 会服从您的指示(并且不会尝试任何类型的优化——您的代码完全按字面解释)但是 by:
会更快地给出交叉组合。
注意。我不知道这些数字会有多大或接近于零,所以我给了你一个 double
。据我所知,float
对您来说效果很好。
评论。我猜您正在受到其他语言的编码经验的影响,在这些语言中创建变量意味着类似于 x = 42
的东西来保持常量。你也可以在 Stata 中做到这一点,使用标量或局部或全局宏,更不用说 Mata 了。请记住,Stata 中的新变量是数据集中的一个全新列,无论它在每个观察中是保持不变还是不同的值。你会得到你所要求的,但它更像是每次都得到一个数组。同样,您似乎只需要一个新变量作为最终结果,实际上您根本不需要临时创建任何其他变量。