做什么(One-liner)
经典 Hodrick-Prescott 滤波:trend = argmin ||y - t||² + λ ||D t||²,直接 numpy.linalg.solve((I + λ D'D) t = y) 求解。分解时间序列为 trend + cycle。默认 λ=1600 (HP 1997 quarterly)。
怎么用
内部 Python primitive — 不是 Canvas 节点。被 mfle_output_gap 调用,也可在自定义 graphlet 里 from services.mfle.output_gap import _hp_filter。
trend = _hp_filter(gdp_series, lamb=1600) # quarterly
cycle = gdp_series.reindex(trend.index) - trend核心公式
# Minimization:
trend = argmin_{t} ||y - t||² + λ ||D t||²
# where D is (n-2, n) second-difference matrix:
# row i = [0...0, 1, -2, 1, 0...0] at columns (i, i+1, i+2)
# First-order condition:
(I + λ D'D) t = y
# Direct solve:
M = eye(n) + lamb * (D.T @ D)
trend = numpy.linalg.solve(M, y.values)假设与适用场景
假设:序列按时间 index 排序 + 无 time-gap + 传入正确频率 λ + 长度 ≥ 5 + pandas Series(不是 list / ndarray)。
适用:GDP / IP / CPI 等宏观序列 trend 提取;output_gap 计算;自定义 detrending。
不适用:实时端点估计(boundary bias)、超长序列(O(n³))、structural break、tick 频率。
输入 / 输出契约
(series: pd.Series, lamb=1600) → pd.Series (trend, same index as series.dropna());len<5 → empty Series.
已知局限
- 端点偏差(Phillips-Jin 2021):boundary trend 不可靠
- λ 频率依赖:monthly 用 14400,annual 用 100(caller 需知)
- Direct-solve O(n³):> 10k obs 改用 statsmodels 稀疏
- Hamilton (2018) 批判:建议 OLS alternative;本 operator 保留经典 HP 因 industry-standard
- 不处理 missing dates:只 dropna 值
- No structural break detection
参考文献
Hodrick-Prescott (1997) 原 paper + Ravn-Uhlig (2002) frequency-adjusted λ + Phillips-Jin (2021) end-point bias + Hamilton (2018) HP criticism。详见 frontmatter。
Golden Test
tests/golden/fixtures/tier3/hp_filter/,statsmodels cross-validation (agreement 5e-11 at λ=1600)。1e-10 snapshot tolerance. 9 tests:
matches_snapshot— 6 scenarios byte-equalagrees_with_statsmodels— cross-validate vs statsmodels hpfilter < 1e-8short_series_returns_empty— len<5 → emptypreserves_index— output index == y.dropna() indexdropna_handling— NaN 值被 dropdeterminism— 5 reruns 一致lambda_quarterly_constant— HP_LAMBDA_QUARTERLY == 1600.0lambda_sensitivity— 高 λ → 更平滑 → 更大 cycle amplitudeexact_smooth_data— 完美线性输入 → cycle ≈ 0
Changelog
- 1.0.0 (2026-04-21) — 首次 Active(Tier 3 batch 3, HP primitive)

