Use Carryforward with Dynamic Condition to Limit Carry Forward Time Interval

I am using carryforward (ssc install carryforward) to fill in missing observations. Some of my data are annual and I want to use them for subsequent monthly observations, but only if the carried forward data are less than two years old. Can I achieve this logic with the dynamic_condition() option, particularly using @? I have to complete this for many variables, and would like to avoid a lot of variable generation and dropping (and really I'd like to know if it's possible).

The following "manual" solution works, but can I replicate it on the fly with dynamic_condition()? My attempts below fail.

/* generate data with observation every June */
clear
set obs 100
generate date_ym = ym(2001, 1) + (_n - 1)
format date_ym %tm
generate date_m = month(dofm(date_ym))
generate x = runiform() if (date_m == 6) & !inlist(_n, 30, 42)

/* carryforward (ssc install carryforward), "manual" solution */
egen date_m2 = group(date_ym) if !missing(x)
carryforward date_m2, replace
bysort date_m2 (date_ym): generate date_m3 = cond(_n > 24, ., date_m2)
carryforward x if !missing(date_m3), gen(x_cf) 
tsset date_ym
list, sep(12)

/* can I replicate this with dynamic_condition() option? */
/* no time series operators with @ */
/* carryforward x, gen(x_cf2) dynamic_condition(sum(d.@ == 0) < 24) */
/* x_cf2:  d.x_cf2 invalid name */

/* second @ doesn't work */
/* carryforward x, gen(x_cf3) dynamic_condition(sum(@ == @[_n - 1]) < 24) */
/* x_cf3:  equation [_n-1] not found */

1 Answer

Disclosure: I don't use carryforward (SSC), but that's because I tend to think back to the principles as I understand them, as documented here.

To do this, you need to keep a record not only of previous non-missing values but also of the dates when a variable was last not missing. This arose previously: see this answer

The essence of a simpler approach is here:

clear
set seed 2803 
set obs 100
generate date_ym = ym(2001, 1) + (_n - 1)
format date_ym %tm
generate x = runiform() if  inlist(_n, 30, 42)
gen last = date_ym if !missing(x)
replace last = last[_n-1] if missing(last)
replace x = x[_n-1] if  missing(x) & (date_ym - last) < 24 

The generalisation to panels is using by: and the generalisation to multiple variables uses a foreach loop. If the dates of missing values can be different for different variables, that mostly just shifts the loop.

Schematically, suppose we are cycling over an arbitary varlist and that the dates of missing values differ, but we use the rule of using the last value within 24 months.

gen last = . 
quietly foreach v of varlist <varlist> { 
    replace last = cond(!missing(`v'), date_ym, .) 
    replace last = last[_n-1] if missing(last)
    replace `v' = `v'[_n-1] if  missing(`v') & (date_ym - last) < 24 
} 
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Robert Thorne

Robert Thorne

Automotive & Future Transportation Editor

Robert Thorne covers electric vehicle innovations, autonomous driving systems, global mobility trends, and automotive engineering developments.

Share this article
Twitter Facebook Pinterest