我的数据 我正在使用以下格式的拼写数据集: clsclear allset more offinput id spellnr str7 bdate_str str7 edate_str employed 1 1 2008m1 2008m9 1 1 2 2008m12 2009m8 0 1 3 2009m11 2010m9 1 1 4 2010m10 2011m9 0 /// 2 1 2007m4
我正在使用以下格式的拼写数据集:
cls clear all set more off input id spellnr str7 bdate_str str7 edate_str employed 1 1 2008m1 2008m9 1 1 2 2008m12 2009m8 0 1 3 2009m11 2010m9 1 1 4 2010m10 2011m9 0 /// 2 1 2007m4 2009m12 1 2 2 2010m4 2011m4 1 2 3 2011m6 2011m8 0 end * translate to Stata monthly dates gen bdate = monthly(bdate_str,"YM") gen edate = monthly(edate_str,"YM") drop *_str format %tm bdate edate list, sepby(id)
对应于:
+---------------------------------------------+ | id spellnr employed bdate edate | |---------------------------------------------| 1. | 1 1 1 2008m1 2008m9 | 2. | 1 2 0 2008m12 2009m8 | 3. | 1 3 1 2009m11 2010m9 | 4. | 1 4 0 2010m10 2011m9 | |---------------------------------------------| 5. | 2 1 1 2007m4 2009m12 | 6. | 2 2 1 2010m4 2011m4 | 7. | 2 3 0 2011m6 2011m8 | +---------------------------------------------+
在这里,给定的人(id)可以有两种类型的多个法术(spellnr)(unmpl:1表示失业; 0表示就业).每个法术的起始日期分别由bdate和edate定义.
想象一下,数据已经被清理过,并且没有任何法术相互重叠.
但是在任何两个法术之间可能存在“缺失”时期.
这由上面的虚拟数据集捕获.
我的问题:
对于每个失业咒语,我需要计算过去6个月,12个月和24个月的就业月数.
请注意,重要的是,每个身份证可以进入和退出就业,并且应考虑所有过去的就业咒语(不仅仅是最后一个).
在我的示例中,这将导致以下所需的输出:
+--------------------------------------------------------------+ | id spellnr employed bdate edate m6 m24 m48 | |--------------------------------------------------------------| 1. | 1 1 1 2008m1 2008m9 . . . | 2. | 1 2 0 2008m12 2009m8 4 9 9 | 3. | 1 3 1 2009m11 2010m9 . . . | 4. | 1 4 0 2010m10 2011m9 6 11 20 | |--------------------------------------------------------------| 5. | 2 1 1 2007m4 2009m12 . . . | 6. | 2 2 1 2010m4 2011m4 . . . | 7. | 2 3 0 2011m6 2011m8 5 20 44 | +--------------------------------------------------------------+
我的(工作)尝试:
以下代码返回所需的结果.
* expand each spell to one observation per time unit (here "months"; works also for days) expand edate-bdate+1 bysort id spellnr: gen spell_date = bdate + _n - 1 format %tm spell_date list, sepby(id spellnr) * fill-in empty months (not covered by spells) xtset id spell_date, monthly tsfill * compute cumulative time spent in employment and lagged values bysort id (spell_date): gen cum_empl = sum(employed) if employed==1 bysort id (spell_date): replace cum_empl = cum_empl[_n-1] if cum_empl==. bysort id (spell_date): gen lag_7 = L7.cum_empl if employed==0 bysort id (spell_date): gen lag_24 = L25.cum_empl if employed==0 bysort id (spell_date): gen lag_48 = L49.cum_empl if employed==0 qui replace lag_7=0 if lag_7==. & employed==0 // fix computation for first spell of each "id" (if not enough time to go back with "L.") qui replace lag_24=0 if lag_24==. & employed==0 qui replace lag_48=0 if lag_48==. & employed==0 * compute time spent in employment in the last 6, 24, 48 months, at the beginning of each unemployment spell bysort id (spell_date): gen m6 = cum_empl - lag_7 if employed==0 bysort id (spell_date): gen m24 = cum_empl - lag_24 if employed==0 bysort id (spell_date): gen m48 = cum_empl - lag_48 if employed==0 qui drop if (spellnr==.) qui bysort id spellnr (spell_date): keep if _n == 1 drop spell_date cum_empl lag_* list
这种方法很好,但在使用(数百万)日常数据时变得非常低效.您能否提出任何不涉及扩展数据集的替代方法?
用语言我在上面做的是:
>我将数据扩展为每月一行;
>我用-tsfill-填写法术之间的“空白”
> I计算在就业中花费的运行时间,并使用滞后运算符来获得三个感兴趣的数量.
在我发布的过去的一个问题中,这与here所做的一致.然而,那里的工作示例不必要地复杂并且有一些错误.
解决方案性能
我尝试了下面接受的答案中建议的不同方法(包括在早期版本的答案中建议使用joinby).为了创建我使用的更大的数据集:
expand 500000 bysort id spellnr: gen new_id = _n drop id rename new_id id
它创建了一个拥有500,000个id的数据集(总共3,500,000个法术).
第一个解决方案在很大程度上支配了使用joinby或rangejoin的解决方案(另请参阅下面接受的答案的注释).
bys id (employed): gen tag = _n if !employed sum tag, meanonly local maxtag = `r(max)' foreach i in 6 24 48 { gen m`i' = . forval d = 1/`maxtag' { by id: gen x = 1 + min(bdate[`d'],edate) - max(bdate[`d']-`i',bdate) if employed egen y = total(x*(x>0)), by(id) replace m`i' = y if tag == `d' drop x y } } sort id bdate
同样的逻辑,以及-rangejoin-(ssc)也应该值得一试.请在测试(大)实际数据后提供一些反馈.
preserve keep if employed replace employed = 0 tempfile em save `em' restore foreach i in 6 24 48 { gen _bd = bdate - `i' rangejoin edate _bd bdate using `em', by(id employed) p(_) egen m`i' = total(_edate - max(_bd,_bdate)+1) if !employed, by(id bdate) bys id bdate: keep if _n==1 drop _* }