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]