Identification of spells or runs in time series
tsspell [varname] [if exp] [in range] [, { fcond(fcondstr) | cond(condstr) | pcond(pcondstr) } spell(spellvar) seq(seqvar) end(endvar) replace ]
Description
tsspell examines the data, which must be tsset time series, to identify spells or runs, which are contiguous sequences defined by some condition. tsspell generates new variables:
(1) indicating distinct spells (0 for not in spell, or integers 1 up);
(2) giving sequence in spell (0 for not in spell, or integers 1 up); and
(3) indicating whether observations occur at the end of spells (0 or 1).
By default, these variables will be called _spell, _seq and _end.
If the data are panel data, all operations are automatically performed separately within panels.
Remarks
There are four ways of defining spells in tsspell.
First, given
tsspell varname
a new spell starts whenever varname changes. Strictly, the condition is (varname != L.varname) | (_n == 1). (The condition _n == 1 is protection against the possibility that the first value is missing.)
Second, a new spell starts whenever some condition defining the first observation in a spell is true. A spell ends just before a new spell starts. Such a condition may be specified by the fcond() option. For example, suppose we wish to divide time into spells of consecutive values. A new spell starts whenever L.varname is missing, which works for the first observation as well because the expression varname[0] is evaluated as missing. Spells started by earthquakes, eruptions, accidents, revolutions, elections, births or other traumatic events may often be defined in this way.
Third, spells are defined by some condition being true for every observation in the spell. A spell ends when that condition becomes false. Such a condition may be specified by the cond() option.
Fourth, a special but useful case of the previous kind is cond(varname > 0 & varname < .); that is, values of varname are positive (but not missing). Given daily data, spells of rain are defined by there being some rainfall every day. As a convenience, such conditions may be specified by pcond(varname), or more generally, pcond(expression).
Spells are deemed to end at the last observation.
Specifying if and/or in adds extra conditions and does not override the rule that spells consist of sequences of values.
Missing values may be ignored by using if to exclude them. They are not ignored by default, as a convenience to users wishing to explore patterns of missing values. Recall that numeric missing . is treated as larger than any positive number. Thus be careful to exclude missing values where appropriate.
Options
fcond(fcondstr) specifies a true or false condition that defines the start of a spell: to be precise, the first observation in a spell. A new spell starts whenever this condition is true.
If varname is specified, and neither fcond() nor cond() is specified, fcond() defaults to (varname != L.varname) | (_n == 1). To span gaps, use (varname != varname[_n-1]) | (_n == 1).
cond(condstr) specifies a true or false condition that defines a spell.
pcond(pcondstr) is equivalent to
cond((pcondstr) > 0 & (pcondstr) < .))
That is, some expression pcondstr evaluates to a positive number (but not missing). Commonly, the expression is just the name of a numeric variable.
Only one of fcond(), cond() and pcond() may be specified.
end(endvar) defines a new variable that is 1 at the end of each spell and 0 otherwise. _end is tried as a variable name if this option is not specified.
seq(seqvar) defines a new variable that is the number of observations so far in the spell. _seq is tried as a variable name if this option is not specified.
spell(spellvar) defines a new variable that is the number of spells so far. All observations in the first spell are tagged with 1, all in the second with 2, and so on. _spell is tried as a variable name if this option is not specified. With panel data, a separate count is kept for each panel.
replace indicates that any variables created by tsspell may overwrite existing variables with the same names.
Examples
Who is in office:
. tsspell party
Spells are distinct jobs (panel data):
. tsspell job
Number of spells (panel data):
. egen nspells = max(_spell), by(id)
Spells of consecutive values of time:
. tsspell, f(L.time == .)
Rainfall spells:
. tsspell, p(rain)
Spells in which rainfall was at least 10 mm every day:
. tsspell, c(rain >= 10 & rain < .) end(hrend) seq(hrseq)
To get information on spell lengths (# observations):
. su hrseq if hrend . tab hrseq if hrend
Length of each spell in a new variable, non-panel and panel data:
. egen length = max(_seq), by(_spell)
. egen length = max(_seq), by(id _spell)
Duration (length in time) of each spell in a new variable, panel data:
. egen tmax = max(time), by(id _spell) . egen tmin = min(time), by(id _spell) . gen duration = tmax - tmin
Cumulative totals of varname:
. bysort _spell (_seq) : gen total = sum(varname) if _seq
Sums of varname:
. egen total = sum(varname), by(_spell)
Spells of growth, stability, decline:
. gen sign = sign(D.varname) . tsspell sign
Define a recession as at least two quarters' decline in real GDP:
. gen sign = sign(D.realGDP) . tsspell sign . egen qtrs = max(_seq), by(_spell) . gen recession = D.realGDP < 0 & qtrs >= 2
One observation per spell:
. ... if _end
A left-censored spell starts at the first relevant observation (so it might have started earlier, except that we have no data to determine that). A right-censored spell ends at the last relevant observation (so it might have ended later, except that we have no data to determine that). Indicator variables:
. by id : gen byte censoredleft = _seq == 1 & _n == 1 . by id : gen byte censoredright = _end == 1 & _n == _N
A liberal definition of a spell might allow inclusion of periods that were no longer than some specified number of observations, even though they do not fit the strict definition of that spell. For example, two spells of heavy rain separated by a brief period might be regarded, meteorologically, as part of the same spell. More generally, we might consider including any part of the data that is not part of a strictly identified spell, i.e. before the first spell, between two spells, or after the last spell. One approach to this is a two-pass process. In the second pass, periods omitted from spells on the first pass are themselves treated as another kind of spell. Then once the length of each gap has been calculated, the new definition is just the old definition or the fact that gap lengths are acceptable:
. tsspell, cond(_spell == 0) spell(_gap) seq(_gapseq) end(_gapend) . bysort id _gap: gen _gaplength = _N if _gap . tsset . tsspell, cond(_spell | _gaplength <= 2) spell(_spell2) seq(_seq2) end(_end2)
Author
Nicholas J. Cox, University of Durham, U.K. n.j.cox@durham.ac.uk
Acknowledgements
Richard Goldstein was the co-author of an earlier program, spell, which did not assume tsset data. Kit Baum, Jan Dehn, Stephen Jenkins, Philippe Van Kerm and Fred Wolfe made very helpful direct or indirect contributions.
Also see On-line: help for tsset, varlist (time series operators) Manual: [R] tsset, [U] 14.4.3 Time-series varlists