Stata 有效地统计活公司的数量
我有一个公司列表,每个公司都有开始日期和结束日期。我想数一数随着时间的推移还活着的公司的数量。我有以下代码,但在我的大数据集上运行缓慢。在斯塔塔有没有更有效的方法Stata 有效地统计活公司的数量,stata,Stata,我有一个公司列表,每个公司都有开始日期和结束日期。我想数一数随着时间的推移还活着的公司的数量。我有以下代码,但在我的大数据集上运行缓慢。在斯塔塔有没有更有效的方法 forvalues y = 1982/2012 { forvalues m = 1/12 { *display date("01-`m'-`y'","DMY") count if start_dt <= date("01-`m'-`y'","DMY") & date("01-`m'-`y'","
forvalues y = 1982/2012 {
forvalues m = 1/12 {
*display date("01-`m'-`y'","DMY")
count if start_dt <= date("01-`m'-`y'","DMY") & date("01-`m'-`y'","DMY") <= end_dt
}
}
forvalues y=1982/2012{
对于值m=1/12{
*显示日期(“01-‘m’-‘y’,‘DMY”)
如果开始计数,一种方法是使用inrange
函数。在Stata中,Date
变量只是整数,因此可以轻松地对它们进行操作
forvalues y = 1982/2012 {
forvalues m = 1/12 {
local d = date("01-`m'-`y'","DMY")
count if inrange(`d', start_dt, end_dt)
}
}
仅此一项就可以为您节省大量时间。对于50000次观察(和合成数据):
计时器1在范围内带有inrange
,计时器2是您的原始代码。结果以秒为单位。有关详细信息,请运行范围内的help
和help timer
这就是说,也许有人可以提出一个总体上更好的策略。假设一个公司标识符firmid
,这是另一种思考问题的方法,但使用不同的数据结构。在执行此操作之前,请确保保存了数据集的副本
expand 2
bysort firmid : gen eitherdate = cond(_n == 1, start_dt, end_dt)
by firmid : gen score = cond(_n == 1, 1, -1)
sort eitherdate
gen living = sum(score)
by eitherdate : replace living = living[_N]
所以
我们将每个观测值扩展为2,并将两个日期放入一个新变量中,一个观测值的开始日期和另一个观测值的结束日期
当一家公司开始时,我们给它的分数是1,当它结束时,我们给它的分数是-1
公司的数量在公司开始时增加1,在公司结束时减少1。我们只需要按日期排序,公司的数量是这些分数的累积总和。(编辑:在同一日期有一个更改修复。)
这种新的数据结构可用于其他目的
网站上有一篇评论文章
编辑:
回复@Roberto Ferrer(以及阅读本文的任何其他人)的注释:
我修复了一个坏错误,这使它太难理解。对此表示抱歉
此处使用的日期仅为公司开始和结束的日期。评估任何其他日期的公司数量没有明显意义,因为它与之前使用的日期相同。但是,如果需要插入日期网格,复制之前的计数就足够了
重要的是不要将返回累计和的Stata函数sum()
与任何egen
函数混淆。给人的印象是egen
的total()
是我的错误的一个副作用
请注意,这样每个不同的日期只计算一次。使用原始代码,每次观察都会计算两次。@NickCox我知道Stata函数(不包括egen
函数)不是开源的,但是你能说一下inrange
在幕后做了什么吗?我倾向于认为它也做了双重计算,但是用编译过的C语言使它更快。这是正确的吗?我不是指inrange()
,而是指执行的date()
计算
每次观察都必须单独进行评估。正如你所说,我无法评论Stata的内部C代码中是如何编码的,但调用C代码大概是这样。我还没读过这篇文章,但让我看看我是否理解:你的最终结果确定了活公司的数量,并不是所有可能的日期(就像在循环中一样),但是对于变量eitherdate
中的每个日期。如果数字为负数,那么这些都是垂死的公司。这是正确的吗?为什么不使用egen,total()
来代替最后两行?是因为速度问题吗?我在答案中添加了一些注释。这是一个非常优雅的解决方案,非常巧妙。
expand 2
bysort firmid : gen eitherdate = cond(_n == 1, start_dt, end_dt)
by firmid : gen score = cond(_n == 1, 1, -1)
sort eitherdate
gen living = sum(score)
by eitherdate : replace living = living[_N]