2013-11-27 44 views
1

我有一個公司的列表開始結束日期爲每個。我想統計一段時間以來存活的公司數量。我有以下代碼,但它在我的大型數據集上運行緩慢。在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'","DMY") <= end_dt 

    } 
} 

回答

1

一種方法是使用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) 

    } 
} 

這一項將爲您節省大量的時間。爲50.000觀測(和虛構的數據):

. timer list 1 
    1:  3.40/  1 =  3.3980 

. timer list 2 
    2:  18.61/  1 =  18.6130 

計時器1inrange計時器2是您的原代碼。結果以秒爲單位。有關詳細信息,請運行help inrangehelp timer

也就是說,也許有人可以提出一個整體更好的策略。

+0

請注意,這樣每個不同的日期只被評估一次。對於原始代碼,每次觀察都要進行兩次評估。 –

+0

@NickCox我知道Stata函數(不包括'egen'函數)不是開源的,但是你可以說'inrange'正在做什麼?我傾向於認爲它也做了雙重評估,但是編譯** C **語言使其更快。這是正確的嗎? –

+0

我不是暗指'inrange()',而是執行'date()'評估。 'inrange()'評估必須爲每個觀察分開進行。正如你所說,我無法評論Stata的內部C代碼是如何編碼的,但可能是對C代碼的調用。 –

1

假設一個確定的標識符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] 

所以,

  1. 我們expand每個觀測到2,把兩個日期在一個新的變量,在一個觀察的開始日期和在其他觀測結束日期。

  2. 我們給一個公司開始時的分數爲1,當它結束時爲-1。

  3. 企業數量每增加1次,企業就會增加1次,每次減少1次。我們只需要按日期排序,公司數量就是這些分數的累計總和。 (編輯:有修改在同一天的變化。)

這個新的數據結構可能是有用的其他目的。

有一個寫了在http://www.stata-journal.com/article.html?article=dm0068

編輯:響應@Roberto費雷爾(和其他人誰讀這)

注:

  1. 我固定一個拙劣的bug ,這使得這很難理解。對於那個很抱歉。

  2. 這裏使用的日期只是公司開始和結束的日期。在任何其他日期評估公司數量都沒有明顯的意義,因爲它與前一個日期的數字相同。但是,如果您需要插入日期網格,則複製之前的計數就足夠了。

  3. 重要的是不要混淆Stata函數sum(),它將累計和與任何egen函數返回。 egentotal()是另一個替代品,這是我的bug的一個副作用。

+0

我一直無法閱讀這篇文章,但讓我看看我是否明白: 您的最終結果確定了並非所有可能的 日期(例如在循環中)的生存公司數量,但是對於每個日期 變量' eitherdate'。如果這個數字是負數,那麼這些公司正在瀕死 。那是對的嗎?爲什麼不使用'egen,total()'代替 的最後兩行?是因爲速度問題嗎? –

+0

我在答案中添加了一些註釋。 –

+0

相當優雅的解決方案;非常巧妙。 –