第 9 章 工程实践要点 从「能跑」到「能发表、能上线」:参数调优、短序列策略、可视化规范与常见陷阱。 9.1 标准分析 Checklist 在提交结果前,逐项核对: # | 检查项 | 通过标准 1 | 输入是增量而非价格 | 已差分/取收益率 2 | 已 toAggregated | profile 长度 = 增量长度 3 | nmax ≤ L/4 | 分段数足够 4 | F(n) 双对数近似线性 | 拟合 R² 可目视判断 5 | revSeg 已开启 | 减少端点效应 6 | polOrd 与趋势阶数匹配 | 通常 1,有漂移试 2 7 | 短序列 L<1000 | unbiased=True 8 | MFDFA 含 q=2 | 与 DFA 对照 9 | DCCA ρ 与置信带对比
从「能跑」到「能发表、能上线」:参数调优、短序列策略、可视化规范与常见陷阱。
在提交结果前,逐项核对:
| # | 检查项 | 通过标准 |
|---|---|---|
| 1 | 输入是增量而非价格 | 已差分/取收益率 |
| 2 | 已 toAggregated | profile 长度 = 增量长度 |
| 3 | n_max ≤ L/4 | 分段数足够 |
| 4 | F(n) 双对数近似线性 | 拟合 R² 可目视判断 |
| 5 | revSeg 已开启 | 减少端点效应 |
| 6 | polOrd 与趋势阶数匹配 | 通常 1,有漂移试 2 |
| 7 | 短序列 L<1000 | unbiased=True |
| 8 | MFDFA 含 q=2 | 与 DFA 对照 |
| 9 | DCCA ρ 与置信带对比 | 显著性有依据 |
| 10 | 引用 fathon 论文 | JOSS 2020 |
import numpy as np import fathon from fathon import fathonUtils as fu np.random.seed(0) L = 8000 # 带线性漂移的序列 t = np.arange(L) increments = np.random.randn(L) * 0.01 + 0.0001 * t profile = fu.toAggregated(increments) wins = fu.linRangeByStep(10, L // 4, step=5) results = {} for m in [1, 2, 3, 4]: dfa = fathon.DFA(profile) n, F = dfa.computeFlucVec(wins, polOrd=m, revSeg=True) H, _ = dfa.fitFlucVec() results[m] = H print(f"polOrd={m}: H={H:.4f}") # 选 H 稳定且 F(n) 标度区间最长的 m
经验法则:
polOrd=1polOrd=2polOrd ≥ 3 仅在强理论支撑时使用import numpy as np import fathon from fathon import fathonUtils as fu L = 500 increments = np.random.randn(L) profile = fu.toAggregated(increments) wins = fu.linRangeByStep(8, L // 5, step=2) # 更保守的 n_max dfa = fathon.DFA(profile) n, F = dfa.computeFlucVec(wins, polOrd=1, unbiased=True) H, _ = dfa.fitFlucVec(nStart=int(n[2]), nEnd=int(n[-2])) print(f"短序列 L={L}, unbiased DFA: H={H:.4f}")
| 策略 | 说明 |
|---|---|
unbiased=True |
v1.3.2+ 无偏 DFA |
| 缩小 n_max | L/5 或 L/10 |
| 增大 step | 减少噪声窗口点 |
| 勿过度解读 H | 置信区间宽,报告时说明 L 限制 |
| 避免 MFDFA | q×wins 成本与方差都大 |
import numpy as np import matplotlib.pyplot as plt import fathon from fathon import fathonUtils as fu profile = fu.toAggregated(np.random.randn(10000)) wins = fu.linRangeByStep(10, 2500, step=10) dfa = fathon.DFA(profile) n, F = dfa.computeFlucVec(wins, revSeg=True, polOrd=1) H, c = dfa.fitFlucVec() fig, ax = plt.subplots(figsize=(6, 4.5)) ax.loglog(n, F, 'ko', markersize=4, markerfacecolor='white', markeredgewidth=1.2) n_line = np.logspace(np.log10(n[0]), np.log10(n[-1]), 50) F_line = np.exp(c + H * np.log(n_line)) ax.loglog(n_line, F_line, 'r-', lw=1.5, label=f'$H = {H:.3f}$') ax.set_xlabel('Window size $n$') ax.set_ylabel('$F(n)$') ax.legend() ax.grid(True, which='both', ls=':', alpha=0.5) plt.tight_layout() plt.show()
参见第 5 章四联图:F_q(n)、h(q)、τ(q)、f(α)。
参见第 6 章:实测 ρ 曲线 + 灰色置信带 + 零线。
import numpy as np import fathon from fathon import fathonUtils as fu def batch_dfa(series_list, labels, L_min=500): """对多条增量序列批量估计 H""" rows = [] wins_cache = None for inc, label in zip(series_list, labels): if len(inc) < L_min: rows.append((label, np.nan, "序列过短")) continue profile = fu.toAggregated(inc) n_max = len(inc) // 4 wins = fu.linRangeByStep(10, n_max, step=max(1, n_max // 100)) dfa = fathon.DFA(profile) n, F = dfa.computeFlucVec(wins, revSeg=True, polOrd=1, unbiased=(len(inc) < 1000)) H, _ = dfa.fitFlucVec() rows.append((label, H, "OK")) return rows # 演示 series = [np.random.randn(3000), np.diff(np.cumsum(np.random.randn(3001)))] labels = ["白噪声", "随机游走"] for label, H, status in batch_dfa(series, labels): print(f"{label}: H={H:.4f} ({status})")
## DFA 结果摘要 - 数据:XXX,长度 L=XXXX,采样间隔 XXX - 预处理:对数收益率 → toAggregated - 参数:polOrd=1, revSeg=True, wins=[10, L/4], step=10 - Hurst 指数:H = 0.XX ± 0.XX(bootstrap 可选) - 标度区间:n ∈ [XX, XX] - 解读:H > 0.5,存在持久性长记忆 - 软件:fathon v1.3.x
| 陷阱 | 症状 | 修复 |
|---|---|---|
| 对价格直接 DFA | H 异常高(→1) | 改用增量/收益率 |
| n_max 过大 | F(n) 末端上翘/下弯 | 限制 n_max ≤ L/4 |
| 忘记 revSeg | H 偏差 0.02~0.05 | revSeg=True |
| polOrd 过高 | H → 0.5(记忆被去掉) | 降至 1 或 2 |
| MFDFA q 过宽 | NaN 或 h(q) 乱抖 | 缩小 q 范围 |
| DCCA 长度不等 | 报错 | 对齐两条序列长度 |
| HT 序列太短 | H(t) 全噪声 | 增加 L 或减少 scales |
| logBase 混用 | q0Fit 与 HT 不一致 | 统一用 np.e |
| 技巧 | 效果 |
|---|---|
| 增大 wins 的 step | 线性加速 |
| powRangeByCount 固定窗口数 | 可预测耗时 |
| saveObject 缓存 F(n) | 避免重复 computeFlucVec |
| MFDFA 先粗 q 步长 0.5 再细化 | 两阶段探索 |
| OpenMP | fathon 内置多线程,长序列自动受益 |
import numpy as np np.random.seed(42) # 合成数据固定种子 # 记录环境 import fathon import numpy print("fathon version:", getattr(fathon, '__version__', 'unknown')) print("numpy:", numpy.__version__)
DCCA 的 rhoThresholds 含随机模拟,固定 nSim 并记录种子(若 fathon 暴露)或多次平均。
DFA 本身不给 p 值。可选补充:
rhoThresholdsimport numpy as np import fathon from fathon import fathonUtils as fu def bootstrap_H(increments, n_boot=200, **dfa_kw): L = len(increments) H_list = [] for _ in range(n_boot): idx = np.random.randint(0, L, size=L) inc_boot = increments[idx] profile = fu.toAggregated(inc_boot) wins = fu.linRangeByStep(10, L // 4, step=10) dfa = fathon.DFA(profile) n, F = dfa.computeFlucVec(wins, revSeg=True, **dfa_kw) H, _ = dfa.fitFlucVec() H_list.append(H) return np.mean(H_list), np.percentile(H_list, [2.5, 97.5]) np.random.seed(0) inc = np.random.randn(4000) H_mean, H_ci = bootstrap_H(inc) print(f"Bootstrap H = {H_mean:.4f}, 95% CI = [{H_ci[0]:.4f}, {H_ci[1]:.4f}]")
工程落地的核心是:正确的 profile、合理的窗口、匹配的 polOrd、可重复的可视化。短序列用无偏 DFA;多分形用 MFDFA;双序列用 DCCA;时变 persistence 用 HT。
prepare_dfa 配置表(不同 L 对应的 wins 策略)。「工程实践五件套」示例覆盖短序列无偏修正、polOrd 对趋势序列的影响、窗口上限稳定性、surrogate 置信区间、拟合区间选择。下面给出其中最实用的 surrogate 置信区间脚本:
"""shuffle surrogate 置信区间完整示例。 打乱增量顺序破坏长记忆但保留边缘分布,得到 H 的零假设分布, 判断原序列 H 是否「显著」偏离白噪声。这是论文级实验的标准做法。 依赖:pip install fathon numpy """ import numpy as np import fathon from fathon import fathonUtils as fu def estimate_H(profile, wins, **kw): dfa = fathon.DFA(profile) dfa.computeFlucVec(wins, **kw) H, _ = dfa.fitFlucVec() return H def main(): rng = np.random.default_rng(3) increments = rng.standard_normal(4000) profile = fu.toAggregated(increments) wins = fu.linRangeByStep(10, 1000, step=20) # 原序列 H H_real = estimate_H(profile, wins, revSeg=True) # 打乱增量顺序:破坏长记忆,但保留边缘分布。期望 H ≈ 0.5 H_shuffled = [] for _ in range(30): shuffled = rng.permutation(increments) H_shuffled.append(estimate_H(fu.toAggregated(shuffled), wins, revSeg=True)) H_shuffled = np.array(H_shuffled) print("=== shuffle surrogate 置信区间 ===") print(f" 原序列 H = {H_real:.4f}") print(f" shuffled H 均值={H_shuffled.mean():.4f} " f"95% 区间=[{np.percentile(H_shuffled, 2.5):.4f}, " f"{np.percentile(H_shuffled, 97.5):.4f}]") lo, hi = np.percentile(H_shuffled, [2.5, 97.5]) if H_real < lo or H_real > hi: print(" → 原序列 H 显著偏离 shuffled 区间,提示存在真实长记忆。") else: print(" → 原序列 H 落在零假设区间内,长记忆证据不足。") if __name__ == "__main__": main()
💡 surrogate 是论文级实验的标准做法:打乱增量顺序破坏长记忆但保留边缘分布,得到 H 的零假设区间,判断原序列 H 是否「显著」偏离白噪声。
下一章介绍进阶方向与生态对比。