cultivars.spectral.band_pass#
Band-pass filters: the business-cycle component, with the costs stated.
The ideal band-pass filter – keep cycles with periods inside a stated band, kill everything else – has the gain function \(\mathbb{1}\{ \omega_l \le |\omega| \le \omega_h\}\) and therefore the weights
infinitely many of them, so every usable filter is an approximation with a bill attached, and the two standards pay it differently. Baxter-King truncates the ideal weights symmetrically at lag \(K\) and recentres them to sum to zero: phase-neutral everywhere it is defined, with exact removal of the zero frequency, at the price of losing \(K\) observations at each end, which is why a BK cycle ends years before the data does. Christiano-Fitzgerald keeps every observation by letting the weights turn asymmetric near the endpoints, folding the weights that fall outside the sample into the endpoint observations under their random-walk approximation of the series, at the price of phase shift and revision-prone estimates exactly where analysts look first – the recent end.
Two commitments shape the surface. First, both bills are carried on
the result rather than in fine print: BandPassResult records
the offset a method lost and a symmetric flag per row saying
where the estimate is phase-neutral and final, so a plot of the recent
end of a CF cycle can be marked as provisional by reading the record
rather than by remembering the paper. Second, bands are stated in
periods – observations per cycle – with the Burns-Mitchell
business-cycle convention at quarterly frequency being 6 to 32, because
periods are what an economist means and frequencies are what the
weights need; the conversion \(\omega = 2\pi / \text{period}\) is
made once, inside, and the shortest admissible period is 2, the Nyquist
limit of the sampling.
These are the module’s only members that touch data rather than fitted models; they are model-free linear filters, and detrending choices upstream (the filters assume no deterministic trend survives in the input beyond what the CF random-walk premise absorbs) remain the caller’s.
Layout. BaxterKingFilter and ChristianoFitzgeraldFilter
are the producers, each validated at construction and applied through
filter, and BandPassResult the record they share. The
numerics live in _core: _ideal_weights gives \(b_0, \dots,
b_K\) at any truncation, which BK mirrors and recentres and CF extends to
the sample length; _validate_band enforces 2 <= low < high; and
_validate_endog_matrix coerces a series or panel to (nobs, k).
The Hodrick-Prescott high-pass filter lives in
filters, and the spectral estimators that
show where a series’ power sits before a band is chosen in
periodogram.
References
Baxter, M., & King, R. G. (1999). Measuring business cycles: Approximate band-pass filters for economic time series. Review of Economics and Statistics, 81(4), 575-593.
Christiano, L. J., & Fitzgerald, T. J. (2003). The band pass filter. International Economic Review, 44(2), 435-465.
Burns, A. F., & Mitchell, W. C. (1946). Measuring Business Cycles. NBER.
Example
A 12-period cycle riding on an 80-period swing, extracted both ways; BK loses twelve observations at each end and is final everywhere, CF keeps them all and is final only in the middle, and where both are final they agree:
>>> import numpy as np
>>> t = np.arange(300.0)
>>> y = np.sin(2 * np.pi * t / 12) + np.sin(2 * np.pi * t / 80)
>>> bk = BaxterKingFilter(low=6, high=32, truncation=12).filter(y)
>>> cf = ChristianoFitzgeraldFilter(low=6, high=32).filter(y)
>>> bk.cycle.shape, bk.offset, bool(bk.symmetric.all())
((276, 1), 12, True)
>>> cf.cycle.shape, cf.offset, int(cf.symmetric.sum())
((300, 1), 0, 236)
>>> agreement = np.corrcoef(bk.cycle[28:248, 0], cf.cycle[40:260, 0])[0, 1]
>>> bool(agreement > 0.99)
True
Classes#
A filtered panel: the cycle, the remainder, and the bookkeeping. |
|
The Baxter-King symmetric truncated band-pass filter. |
|
The Christiano-Fitzgerald asymmetric full-sample band-pass filter. |