halo 的技术博客

返回

你有一段价格或收益序列,想量化它「有多不规则、多复杂」。直觉反应是算**样本熵(Sample Entropy, SampEn)**或近似熵——值越大越「乱」。但这个方法藏着一个反直觉的陷阱:它对白噪声给的分数最高

白噪声是最「无结构」的序列,可 SampEn 却把它判成最复杂。为什么?因为 SampEn 只在单一时间尺度上比较相邻点的模式:白噪声在最小尺度上确实每个点都不重复、最「 unpredictably」,于是它拿到了最高熵。问题在于——白噪声的复杂度只存在于最细的尺度,你只要把序列「粗看」一点(比如每 5 个点取平均),它的不规则性就塌没了。

真正区分「白噪声 / 分形长记忆 / 周期驱动」的,是不同时间尺度上的复杂度分布。这就是 多尺度熵(Multiscale Entropy, MSE, Costa 2002)去趋势波动分析(DFA, Peng 1994) 要解决的问题。本文用纯 numpy 从零实现 SampEn / MSE / DFA,在三类合成序列上把尺度结构拆开,并诚实指出「MSE 必须用固定容忍半径」这一最易踩的坑。所有图表均由下文 Python 真实计算,非占位图。

三类序列形态对照:白噪声无结构、1/f 粉红噪声呈分形、周期+噪声由单一主导频率驱动

一、样本熵 SampEn:单尺度的「不规则性」#

SampEn 的想法很朴素:把序列切成长度为 mm 的模板向量,看「再延长一步、仍然匹配」的比例。匹配越多说明越规律,匹配越少说明越复杂。写成公式:

SampEn(m,r)=lnAB\text{SampEn}(m, r) = -\ln\frac{A}{B}
  • BB:长度为 mm 的模板向量中,能找到另一个不同位置、且逐点距离 <r< r 的配对总数;
  • AA:长度为 m+1m+1 的模板向量中,同样匹配的配对总数;
  • rr 是容忍半径(抗噪声),默认取 0.15σ0.15\cdot\sigma

值越大 \Rightarrow 模板越难重复 \Rightarrow 越不规则。纯 numpy 实现:

二、多尺度熵 MSE:用粗粒化把尺度分开#

MSE 的关键一步是粗粒化(coarse-graining):把序列按窗口 τ\tau 不重叠平均,得到一条更「粗」、更短的序列。τ\tau 越大,越抹掉细尺度波动、越暴露粗尺度结构:

yj(τ)=1τi=(j1)τ+1jτxiy_j^{(\tau)} = \frac{1}{\tau}\sum_{i=(j-1)\tau+1}^{j\tau} x_i

然后在每个尺度 τ\tau 上各算一次 SampEn,得到一条 MSE(τ)MSE(\tau) 曲线。不同序列在这条曲线上的形状天差地别——这才是真正的信息:

在白噪声、1/f 粉红噪声、周期+噪声三类序列(各 2400 点)上算出的 MSE 曲线:

多尺度熵曲线:白噪声随尺度单调塌缩,1/f 粉红噪声在粗尺度反而回升,周期序列单调下降最快

实测数字(SampEn 在 τ=1,5,10,20\tau=1,5,10,20 处):

序列τ=1τ=5τ=10τ=20
白噪声2.4761.7171.3911.124
1/f 粉红噪声1.9871.8911.7312.565
周期+噪声1.9531.2921.0420.687

三条曲线的形状完全不同:

  • 白噪声:随尺度单调塌缩(2.48→1.12)。因为它没有跨尺度结构,粗化后迅速「变得可预测」——这就是单尺度熵误判它「最复杂」的真相:它的复杂度只活在 τ=1。
  • 1/f 粉红噪声:在粗尺度不降反升(τ=20 冲到 2.565)。它每个尺度都有结构(分形/长程相关),越粗越显出持续的相关性,所以分形过程才是真正「多尺度都复杂」的。
  • 周期+噪声:单调下降最快(1.95→0.69)。粗粒化会把周期平滑掉、只留趋势,于是迅速变规则。

三、DFA:给长程相关一个标度指数 α#

MSE 看的是「复杂度的尺度分布」,而 DFA(Detrended Fluctuation Analysis) 直接问「序列有没有长程记忆、记忆多强」。它的三步:

  1. 对去均值序列做累计和 yk=i=1k(xixˉ)y_k = \sum_{i=1}^k (x_i - \bar x)
  2. 把序列切成长度为 ss 的窗口,每个窗口用线性拟合去趋势,算残差的 RMS F(s)F(s)
  3. logF(s)αlogs\log F(s) \sim \alpha \log s 回归,斜率就是标度指数 α\alpha

三种序列的 α\alpha

序列α解读
白噪声0.529≈0.5,近似无记忆(随机游走)
1/f 粉红噪声1.022>0.5,强持续相关(分形长记忆)
周期+噪声0.566≈0.5,周期被噪声主导,记忆弱

DFA 标度:log F(s) 对 log s 的斜率 α 把白噪声(~0.5)与粉红噪声(~1.0)一刀切开

α0.5\alpha \approx 0.5 读作「无记忆/白噪声」, α>0.5\alpha > 0.5 读作「持续相关」(涨完还涨、跌完还跌,分形市场的指纹),α<0.5\alpha < 0.5 读作「反持续」(均值回复)。这正是 MSE 之外一个互补的尺度探针:MSE 量复杂度分布,DFA 量相关性结构。

四、最易踩的坑:MSE 必须用「固定」容忍半径#

很多人实现 MSE 时,在每个粗化尺度上重新用该尺度的标准差算 r=0.15σ(粗化序列)r=0.15\cdot\sigma(\text{粗化序列})。这是错的。粗化后序列方差变小,rr 跟着变小,会把样本熵人为推高——于是白噪声的 MSE 曲线不降反升,和粉红噪声「撞型」,完全失去区分力。

正确做法是 Costa 原论文的设定:rr 固定在原始序列标准差的 0.150.15 倍,跨所有尺度不变。这样白噪声在粗尺度才能真正「塌缩」,粉红噪声才能保持高位。本文所有数字都用固定 rr 计算。如果你看到某篇博客里白噪声 MSE 随尺度上升,那八成是踩了这个坑,而不是反直觉的真发现。

五、单尺度熵在金融里的无力:regime 切换#

把 MSE 用到收益序列还有一个现实问题:单尺度 SampEn 对 regime 极不敏感。构造一段「平静—危机—平静—危机」切换的收益率(各 300 点,危机段波动是平静段的 3.5 倍),用滑动窗 SampEn(τ=1) 监测:

平静段平均 SampEn = 2.248
危机段平均 SampEn = 2.545
plaintext

区分只有 0.3,而且单尺度熵在窗内很吵、边界模糊。MSE 的价值在于不盯一个点,而是看跨尺度结构是否整体迁移——平静市和危机市的「复杂度谱形状」差异,远大于单个 τ=1 的数字差异。这也是为什么做市场状态监测时,应报告整条 MSE 曲线(或它的统计量,如曲线下面积、斜率),而不是一个标量。

单尺度熵在 regime 切换里很嘈杂,边界不清晰;MSE 的跨尺度结构才稳定

六、五类真实陷阱(必看)#

  1. 容忍半径 r 随尺度重算:上文详述,会让白噪声 MSE 不降反升、粉红噪声撞型。永远用固定 r=0.15σ(原序列)r=0.15\sigma(\text{原序列})
  2. 短序列 MSE 不可信:粗化到 τ=20 时序列只剩 N/20 个点,m+1m+1 模板配对严重不足,尾部熵估计方差爆炸。本文 N=2400 尚可,实盘日频 250 天时 τ>5 就要打问号。
  3. DFA 最低尺度受噪声污染:极小 ssF(s)F(s) 被微观结构噪声/采样误差主导,回归应截取 ss 的中间段(本文用 10~N/4),别把最小点也塞进线性拟合。
  4. 周期序列的 α 会骗人:纯周期的 F(s)F(s)ss 接近周期整数倍处出现周期性下凹,把周期误读成「长程记忆」。1/f 与周期的 α 接近时要用 MSE 形状区分,不能只看 α。
  5. MSE 量「不规则性」不量「方向」:高 MSE 可能是趋势市(持续相关)也可能是噪声市(随机),必须配 DFA 的 α 一起看,否则分不清「有结构的复杂」和「无结构的乱」。

结语#

多尺度熵 MSE 和 DFA 是同一件事的两面:把序列的不规则性按时间尺度拆开。SampEn 只在单尺度看「乱不乱」,会错把白噪声捧成最复杂;MSE 用粗粒化让白噪声在粗尺度塌缩、让粉红噪声在每个尺度都保持复杂、让周期序列迅速变规则;DFA 再补一刀,用标度指数 α 把「有没有长程记忆」量化成一个数(白噪声≈0.5、粉红噪声≈1.0)。实战要点就两条:MSE 必须固定容忍半径,以及复杂度谱 + α 配合看,别用单标量。把它和上一篇的排列熵放在一起——排列熵看「涨跌形状的结构」,MSE/DFA 看「跨尺度的结构」,三个工具合起来才是完整的复杂性度量箱。

完整可复跑代码与全部图表脚本已随本文生成(gen_multiscale_entropy_dfa.py),三类序列的 MSE 曲线、DFA 标度、regime 对照均由该脚本真实计算。

多尺度熵与 DFA:用粗粒化把不同时间尺度的不规则性分开
https://blog.halo26812.eu.org/blog/multiscale-entropy-dfa
Author halo
Published at 2026年7月23日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨