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

非 Y 不嫁゛ 提交于 2019-12-12 04:45:00

问题


I am working with a spell dataset that has the following form:

    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

where persid is the id of the person; start and end are the months when the yearly unemployment/employment spell starts and ends, respectively; t_start and t_end are the same measures but starting to count from 1st January 1996; event is equal to 1 for the employment entries for which the previous row was an unemployment spell.

The data is such that there are no overlapping spells during a given year, and each year contiguous spells of the same type have been merged together.

My goal is, for each row such that event is 1, to compute the number of months spent as employed in the last 6 months and 24 months. In this specific example, what I would like to get is:

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 

So the idea is that I have to go back to rows preceding each event==1 entry and count how many months the individual was employed.

Can you suggest a way to obtain this final result? Some suggested to expand the dataset, but perhaps there are better ways to tackle the problem (especially because the dataset is quite large).

EDIT

The correct labeling of the employment status is:

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

The number of past months spent in employment (empl_6 and empl_24) and the definition of event are now correct with this label.


回答1:


A solution to the problem is to:

  • expand the data so to have it monthly,
  • fill in the gap months with tsfill and finally,
  • use sum() and lag operators to get the running sum for the last 6 and 24 months.

See also Robert solution for some ideas I borrowed.

Important: this is almost surely not an efficient way to solve the issue, especially if the data is large (as in my case). However, the plus is that one actually "sees" what happens in background to make sure the final result is the one desired.

Also, importantly, this solution takes into account cases where 2 (or more) events happen within 6 (or 24) months from each other.

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



回答2:


The posted example is of little utility in developing and testing a solution so I made up fake data that has the same properties. It's bad practice to use 1 and 2 as values for an indicator so I replaced the employed indicator with 1 meaning employed, 0 otherwise. Using month and year separately is also useless so Stata monthly dates are used.

The first solution uses tsegen (from SSC) after expanding each spell to one observation per month. With panel data, all you need to do is to sum the employment indicator for the desired time window.

The second solution uses rangestat (also from SSC) and does the same computations without expanding the data at all. The idea is simple, just add the duration of previous employment spells if the end of the spell falls within the desired window. Of course if the end of the spell falls within the window but not the start, days outside the window must be subtracted.

* 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


来源:https://stackoverflow.com/questions/42890158/management-of-spell-data-months-spent-in-given-state-in-the-past-24-months

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!