法术数据管理:过去 24 个月内处于给定状态的月数

Management of spell data: months spent in given state in the past 24 months

我正在使用具有以下形式的拼写数据集:

    clear all

input persid    start   end t_start t_end   spell_type  year    spell_number    event
    1   8   9   44  45  1   1999    1   0
    1   12  12  60  60  1   2000    1   0
    1   1   1   61  61  1   2001    1   0
    1   7   11  67  71  1   2001    2   0
    1   1   4   85  88  2   2003    1   0
    1   5   7   89  91  1   2003    2   1
    1   8   11  92  95  2   2003    3   0
    1   1   1   97  97  2   2004    1   0
    1   1   3   121 123 1   2006    1   1
    1   4   5   124 125 2   2006    2   0
    1   6   9   126 129 1   2006    3   1
    1   10  11  130 131 2   2006    4   0
    1   12  12  132 132 1   2006    5   1
    1   1   12  157 168 1   2009    1   0
    1   1   12  169 180 1   2010    1   0
    1   1   12  181 192 1   2011    1   0
    1   1   12  193 204 1   2012    1   0
    1   1   12  205 216 1   2013    1   0
end

lab define lab_spelltype 1 "unemployment spell" 2 "employment spell"
lab val spell_type lab_spelltype

其中persid是人的id; startend 分别是每年 unemployment/employment 法术开始和结束的月份; t_startt_end 是相同的措施,但从 1996 年 1 月 1 日开始计算; event 对于前一行是失业期的就业条目等于 1。

数据是这样的,在给定的年份中没有重叠的法术,并且每年都会将相同类型的连续法术合并在一起。

我的目标是,对于使 event 为 1 的每一行,计算过去 6 个月和 24 个月中受雇的月数。 在这个具体的例子中,我想得到的是:

clear all
input persid    start   end t_start t_end   spell_type  year    spell_number    event   empl_6  empl_24
    1   8   9   44  45  1   1999    1   0   .   .
    1   12  12  60  60  1   2000    1   0   .   .
    1   1   1   61  61  1   2001    1   0   .   .
    1   7   11  67  71  1   2001    2   0   .   .
    1   1   4   85  88  2   2003    1   0   .   .
    1   5   7   89  91  1   2003    2   1   0   5
    1   8   11  92  95  2   2003    3   0   .   .
    1   1   1   97  97  2   2004    1   0   .   .
    1   1   3   121 123 1   2006    1   1   0   0
    1   4   5   124 125 2   2006    2   0   .   .
    1   6   9   126 129 1   2006    3   1   3   3
    1   10  11  130 131 2   2006    4   0   .   .
    1   12  12  132 132 1   2006    5   1   4   7
    1   1   12  157 168 1   2009    1   0   .   .
    1   1   12  169 180 1   2010    1   0   .   .
    1   1   12  181 192 1   2011    1   0   .   .
    1   1   12  193 204 1   2012    1   0   .   .
    1   1   12  205 216 1   2013    1   0   .   .
end 

所以我的想法是,我必须返回到每个 event==1 条目之前的行,并计算这个人受雇了多少个月。

你能建议一种获得最终结果的方法吗? 有人建议 expand 数据集,但也许有更好的方法来解决这个问题(特别是因为数据集非常大)。

编辑

就业状态的正确标注是:

lab define lab_spelltype 1 "employment spell" 2 "unemployment spell"

过去在工作中花费的月数(empl_6empl_24)和 event 的定义现在使用此标签是正确的。

发布的示例在开发和测试解决方案方面没有多大用处,因此我编造了具有相同属性的假数据。使用 1 和 2 作为指标的值是一种不好的做法,因此我将 employed 指标替换为 1,表示 employed,否则为 0。单独使用月份和年份也没有用,所以使用 Stata 月度日期。

第一个解决方案在将每个法术扩展为每月一次观察后使用 tsegen(来自 SSC)。使用面板数据,您需要做的就是将所需时间的就业指标相加 window。

第二个解决方案使用 rangestat(也来自 SSC)并进行相同的计算而根本不扩展数据。这个想法很简单,如果法术的结束在所需的 window 范围内,只需添加以前的就业法术的持续时间。当然,如果咒语的结尾在 window 之内而不是开始之内,则必须减去 window 之外的天数。

* fake data for 100 persons, up to 10 spells with no overlap
clear
set seed 123423
set obs 100
gen long persid = _n
gen spell_start = ym(runiformint(1990,2013),1)
expand runiformint(1,10)
bysort persid: gen spellid = _n
by persid: gen employed = runiformint(0,1)
by persid: gen spell_avg = int((ym(2015,12) - spell_start) / _N) + 1
by persid: replace spell_start = spell_start[_n-1] + ///
    runiformint(1,spell_avg) if _n > 1
by persid: gen spell_end = runiformint(spell_start, spell_start[_n+1]-1)
replace spell_end = spell_start + runiformint(1,12) if mi(spell_end)
format %tm spell_start spell_end

* an event is an employment spell that immediately follow an unemployment spell
by persid: gen event = employed & employed[_n-1] == 0

* expand to one obs per month and declare as panel data
expand spell_end - spell_start + 1
bysort persid spellid: gen ym = spell_start + _n - 1
format %tm ym
tsset persid ym

* only count employement months; limit results to first month event obs
tsegen m6 = rowtotal(L(1/6).employed)
tsegen m24 = rowtotal(L(1/24).employed)
bysort persid spellid (ym): replace m6 = . if _n > 1 | !event
bysort persid spellid (ym): replace m24 = . if _n > 1 | !event

* --------- redo using rangestat, without any monthly expansion ----------------

* return to original obs but keep first month results
bysort persid spellid: keep if _n == 1

* employment end and duration for employed observations only
gen e_end = spell_end if employed
gen e_len = spell_end - spell_start + 1 if employed

foreach target in 6 24 {

    // define interval bounds but only for event observations
    // an out-of-sample [0,0] interval will yield no results for non-events
    gen low`target' = cond(event, spell_start-`target', 0)
    gen high`target' = cond(event, spell_start-1, 0)

    // sum employment lengths and save earliest employment spell info
    rangestat (sum) empl`target'=e_len ///
        (firstnm) firste`target'=e_end firste`target'len=e_len, ///
        by(persid) interval(spell_end low`target' high`target')

    // remove from the count months that occur before lower bound
    gen e_start = firste`target' - firste`target'len + 1
    gen outside = low`target' - e_start
    gen empl`target'final = cond(outside > 0, empl`target'-outside, empl`target')
    replace empl`target'final = 0 if mi(empl`target'final) & event
    drop e_start outside
}

* confirm that we match the -tsegen- results
assert m24 == empl24final
assert m6 == empl6final

问题的解决方案是:

  • 扩展数据以便每月获取,
  • tsfill 填补空白月份,最后
  • 使用 sum() 和滞后运算符获得过去 6 个月和 24 个月的 运行 总和。

有关我借鉴的一些想法,另请参阅 Robert 解决方案。

重要提示:这几乎肯定不是解决问题的有效方法,尤其是在数据很大的情况下(如我的情况)。 但是,加号是实际上 "sees" 在后台发生的事情以确保最终结果是所需的。

此外,重要的是,此解决方案考虑了 2 个(或更多)事件在 6(或 24)个月内发生的情况。

clear all

input persid    start   end t_start t_end   spell_type  year    spell_number    event
    1   8   9   44  45  1   1999    1   0
    1   12  12  60  60  1   2000    1   0
    1   1   1   61  61  1   2001    1   0
    1   7   11  67  71  1   2001    2   0
    1   1   4   85  88  2   2003    1   0
    1   5   7   89  91  1   2003    2   1
    1   8   11  92  95  2   2003    3   0
    1   1   1   97  97  2   2004    1   0
    1   1   3   121 123 1   2006    1   1
    1   4   5   124 125 2   2006    2   0
    1   6   9   126 129 1   2006    3   1
    1   10  11  130 131 2   2006    4   0
    1   12  12  132 132 1   2006    5   1
    1   1   12  157 168 1   2009    1   0
    1   1   12  169 180 1   2010    1   0
    1   1   12  181 192 1   2011    1   0
    1   1   12  193 204 1   2012    1   0
    1   1   12  205 216 1   2013    1   0
end

lab define lab_spelltype 1 "employment" 2 "unemployment"
lab val spell_type lab_spelltype
list

* generate Stata monthly dates
gen spell_start = ym(year,start)
gen spell_end = ym(year,end)
format %tm spell_start spell_end
list

* expand to monthly data
gen n = spell_end - spell_start + 1
expand n, gen(expanded)
sort persid year spell_number (expanded)
bysort persid year spell_number: gen month = spell_start + _n - 1
by persid year spell_number: replace event = 0 if _n > 1
format %tm month

* xtset, fill months gaps with "empty" rows, use lags and cumsum to count past months in employment
xtset persid month, monthly // %tm format
tsfill
bysort persid (month): gen cumsum = sum(spell_type) if spell_type==1
bysort persid (month): replace cumsum = cumsum[_n-1] if cumsum==.
bysort persid (month): gen m6  = cumsum-1 - L7.cumsum if event==1  // "-1" otherwise it sums also current empl month
bysort persid (month): gen m24 = cumsum-1 - L25.cumsum if event==1
drop if event==.
list persid start end year m* if event