| mbh_filter | R Documentation |
Decomposes a time series into trend and cycle using a robust boosting algorithm. Unlike the HP filter, MBH uses the Huber loss function to automatically downweight outliers (like the COVID-19 shock), preventing them from distorting the trend.
mbh_filter(
x,
d = "auto",
boot_iter = 0,
block_size = "auto",
knots = NULL,
mstop = 500L,
nu = 0.1,
df = 4L,
select_mstop = FALSE,
boundary.knots = NULL,
hp_lambda = NULL
)
x |
Numeric vector, |
d |
Numeric or |
boot_iter |
Non-negative integer.
Number of block-bootstrap iterations for uncertainty quantification
(default |
block_size |
Positive integer or |
knots |
Integer.
Number of interior knots for the P-Spline.
If |
mstop |
Integer.
Maximum number of boosting iterations (default 500).
If Under-smoothing warning ( |
nu |
Numeric. The learning rate (shrinkage) for boosting (default 0.1). |
df |
Integer. Effective degrees of freedom per boosting step for the P-Spline base learner (default 4). This enforces the weak-learner constraint of Bühlmann & Hothorn (2007): each boosting step contributes only a small, smooth update so that the trend is built up gradually over many iterations rather than fitted in one pass. End-point instability warning: Higher |
select_mstop |
Logical.
If AICc underfitting warning: In the combination of Huber
quasi-likelihood + P-splines, AICc penalises model complexity
hyper-aggressively. In practice the algorithm stops at iteration ~5–15
instead of the intended ~500. The resulting trend is nearly a straight
line; all long-run variance is pushed into the cycle component, defeating
the purpose of the filter. Treat |
boundary.knots |
A numeric vector of length 2 specifying the global
domain for the B-spline basis (e.g., |
hp_lambda |
Numeric or |
The model estimated is an additive model:
y_t = \text{Linear}(t) + \text{Smooth}(t) + \epsilon_t
It is fitted using mboost::mboost() with:
Base Learners: A linear time trend (mboost::bols()) to capture
the global path, plus a B-spline (mboost::bbs()) to capture local
curvature.
Loss Function: Huber loss (mboost::Huber()) with parameter
d. This is the key to robustness.
The default parameters (knots = min(n/2, 250), mstop = 500) are
calibrated to mimic the flexibility of a standard HP filter while retaining
the robustness of the Huber loss.
A list of class c("macrofilter", "list") with:
$trendNumeric trend vector.
$cycleNumeric cycle vector.
$dataOriginal input as numeric.
$metaNamed list: method, knots, d, mstop, nu,
df, select_mstop, compute_time.
$trend_lower, $trend_upper95% normal-approximation bootstrap
band (trend +/- 1.96 * sd). Present only when boot_iter > 0.
Three failure modes were discovered through empirical stress-testing. The defaults guard against all three:
d)The automatic fallback mad(diff(y)) operates on the scale of
growth rates, not the output gap. For log-level input this sets d
one to two orders of magnitude too small, causing ordinary
business-cycle swings to be treated as outliers. If the estimated
cycle looks implausibly large or the trend is nearly linear, override
with d = mad(hp_filter(x)$cycle) as a starting point.
select_mstop)AICc + Huber quasi-likelihood + P-splines stops boosting at
iteration ~5–15. The trend degenerates to a near-straight line and
the cycle absorbs all long-run variance. Leave select_mstop = FALSE
(the default) and set mstop explicitly instead.
df)Values above 4 shift the B-spline basis matrix non-smoothly as
the sample grows, producing a "rubber-band" distortion in the final
observations. Keep df = 4 (the default) for real-time applications.
# Fast example with reduced series and iterations
set.seed(42)
y <- ts(cumsum(rnorm(80)), start = c(2000, 1), frequency = 4)
result <- mbh_filter(y, mstop = 100L)
print(result)
# Full example with default parameters
y2 <- ts(cumsum(rnorm(200)), start = c(2000, 1), frequency = 4)
result2 <- mbh_filter(y2)
print(result2)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.