halo 的技术博客

返回

给你三段曲线:一段是完美正弦,一段是逻辑斯蒂混沌 xₙ₊₁=4x(1−x),一段是纯随机白噪声。肉眼能立刻分清——正弦最「有规律」,噪声最「乱」,混沌介于中间。但怎么用一个数字把它们量化出来?

这就是 排列熵(Permutation Entropy, PE, Bandt & Pompe 2002) 干的事。它的妙处在于:完全不看数值大小,只看「升跌的相对形状」。把每个时间窗口里几个点的位置排个序(比如「小、大、中」),数一遍所有形状出现的频率,再算个香农熵——复杂度就出来了:

  • 正弦 → 形状高度重复 → PE 低;
  • 白噪声 → 所有形状近乎均匀 → PE 高(归一化≈1);
  • 逻辑斯蒂混沌 → 介于二者之间。

更省心的是它对单调变换、量纲、平移都不变(因为只比相对大小),所以跨品种、跨周期比「复杂度」特别顺手,做 regime 检测几乎是开箱即用。本文用纯 numpy 从零实现序数模式计数与滑动窗 PE,把三类序列的复杂度量成 0–1,并展示 PE 如何实时追踪「正弦→噪声→正弦」的 regime 切换。所有图表均由下文 Python 真实计算,非占位图。

三类序列的归一化排列熵:正弦最低(0.26)、逻辑斯蒂混沌居中(0.68)、白噪声最高(0.99)

一、排列熵在算什么:把序列切成「升跌形状」再数频率#

给定序列 x 和嵌入维度 m,取长度为 m 的窗口,看窗口内 m 个点的相对大小排名(序数模式,ordinal pattern)。例如 m=3、窗口 [5, 9, 3],排序后排名是「小、大、中」→ 用索引表示成 (0, 2, 1)

把所有长度为 m 的窗口都映射成一个排列,统计 m! 种排列各自出现的频率 p_π,排列熵就是这些频率的香农熵,再除以 log(m!) 归一化到 [0,1]:

PE(x;m)=1log(m!)πpπlogpπ\mathrm{PE}(x; m) = -\frac{1}{\log(m!)} \sum_{\pi} p_\pi \log p_\pi

直觉特别朴素:如果序列有规律,少数几种形状会反复出现 → 频率极不均匀 → 熵低;如果完全随机,所有形状差不多均等 → 熵高。 注意实现时给相等值加一点微扰打破平局,否则排名不确定。

举个具体例子:窗口 [5, 9, 3](m=3),三个数从小到大是 3<5<9,所以原位置「第1个是中间值、第2个是最大值、第3个是最小值」,序数模式记为 (0, 2, 1)(用索引 0/1/2 表示小/中/大)。滑到下个窗口 [9, 3, 7] → 排名 (1, 0, 2)。整条序列滑完,就得到一长串像 (0,2,1),(1,0,2),(0,1,2)... 的模式序列,数频率即可。

从零实现(无第三方依赖):

tau 是步长(可以取大于 1 做降采样嵌入),m 是窗口长度——m 越大,能分辨的形状越细,但模式总数 m! 爆炸,小样本下会稀疏。第五节约专门拆这个。

二、三类序列的 PE:复杂度被一刀切开#

造三个各 2000 点的序列(取 m=5):

rng = np.random.default_rng(20260723)
N = 2000; t = np.arange(N)
sine  = np.sin(0.12 * t)                       # 规则
logi  = np.zeros(N); v = 0.4
for i in range(1, N):
    v = 4.0 * v * (1 - v); logi[i] = v          # 逻辑斯蒂混沌
noise = rng.normal(0, 1, N)                     # 白噪声

print(permutation_entropy(sine, 5))   # 0.262
print(permutation_entropy(logi,  5))  # 0.679
print(permutation_entropy(noise, 5))  # 0.994
python

结果正好落在预期的三档:

PE(m=5)  正弦=0.262  逻辑斯蒂=0.679  白噪声=0.994
plaintext
  • 正弦 (0.26):窗口形状几乎是固定的几种(升-平-降的循环),频率极不均匀 → 低熵。
  • 白噪声 (0.99):每个窗口的形状都是随机的,24 种排列差不多均分 → 熵逼近理论上限 1。
  • 逻辑斯蒂 (0.68):混沌看似乱,但有确定性结构,比纯噪声「有序」→ 居中。

m=4(24 种模式)的频率分布画出来,能直观看到「秩序」长什么样:

序数模式频率:正弦少数形状霸屏、白噪声近乎均匀、逻辑斯蒂中等散布——排列熵的本质就是数形状的均匀程度

三、滑动窗 PE:实时追踪 regime 切换#

单点 PE 是全局统计。更有用的是滑动窗 PE——每滑一个窗口算一次,得到一条随时间变化的复杂度曲线。这让它成了天然的 regime 检测器:市场从「趋势/震荡有序」切到「无序乱跳」,PE 会立刻跳升。

造一段「正弦 → 噪声 → 正弦」切换序列,窗口 200,看 PE 怎么走:

def pe_series(x, win, m, tau=1):
    out = np.full(len(x), np.nan)
    for i in range(win, len(x) + 1):
        out[i - 1] = permutation_entropy(x[i - win:i], m, tau)
    return out
python

滑动窗排列熵实时追踪 regime:噪声段 PE 冲到 0.94、正弦段回落到 0.25——复杂度本身就是状态开关

曲线清清楚楚:噪声段 PE 冲到 0.94,两端正弦段回落到 0.25 左右。复杂度本身就是一个可交易/可风控的状态变量——比如「PE 持续高于某分位 → 市场进入无序态 → 降杠杆 / 关掉趋势策略」。

四、边界:嵌入维度 m 是把双刃剑#

PE 对 m 很敏感,这是它最大的实操陷阱:

  • m 太小(如 m=2):只能区分「升/降」两种形状,漏掉了序列里的时序结构——正弦在 m=2 时 PE 直接=1.0(因为只看相邻两点,正弦的相邻升跌看着也挺随机),完全失去分辨力
  • m 太大(如 m=6,720 种模式):模式数爆炸,小样本下每种模式命中次数极少、估计方差暴涨,曲线开始抖。

实测三类序列随 m 的变化:

m        2      3      4      5      6
正弦     1.000  0.492  0.336  0.262  0.218
逻辑斯蒂 0.914  0.828  0.739  0.679  0.629
白噪声   1.000  1.000  0.998  0.994  0.970
plaintext

规律很明显:m=2 时正弦已经「假饱和」成 1.0(丢信息),m≥3 才开始拉开三档;白噪声则无论 m 多大都≈1(它本来就均匀)。实务里 m 取 3–6 比较稳,且最好对同批序列用同一个 m 才有可比性。

PE 随嵌入维度 m 曲线:m 太小漏结构、m 太大稀疏抖动——中间段才是稳定分辨区

五、在量化里它能干什么(以及不该干什么)#

能干的:

  1. 市场状态(regime)识别:滑动窗 PE 高 → 无序/高波动/噪声市,低 → 有序/趋势或震荡规律市。可当风控开关。
  2. 品种复杂度排序:跨资产比 PE,找出「结构最清晰 / 最混沌」的标的,做配对或轮动。
  3. 异常检测:某序列平时 PE 稳定在某区间,突然跳变 → 可能有结构性事件(停牌复牌、流动性断裂、操纵)。
  4. 特征去冗余:两个序列 PE 都高且同步高 → 可能承载同类信息。

不该干的:

  1. 别拿 PE 当收益率预测:它量的是「序列的复杂度」,和「未来涨跌」没有先验关系,只能当状态量。
  2. 别在超短窗口硬用:窗口太短,模式计数不足,PE 噪声极大。窗口至少容纳几十个点。
  3. 别和不同 m 的 PE 横向比:m 不同,熵的量纲基准不同,比出来没意义。

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

  1. m 太小假饱和:m=2 时连正弦都 PE≈1,分辨力归零——永远用 m≥3。
  2. 平局处理:相等值排名不确定,必须加微扰(或显式定义打平规则)否则结果随运行抖动。
  3. 窗口长度门槛:滑动窗 PE 的窗口要够长才数得清 m! 种模式;短窗口估计方差大。
  4. 高 m 稀疏化:m=6 以上模式数爆炸,n 不够则估计不稳,曲线抖。
  5. PE 只是复杂度不是因果:PE 高只说明「无序」,不说明「要跌」或「要反转」——它必须配合方向性信号使用,别单独当买卖依据。

结语#

排列熵的优雅在于:用「升跌形状」这种最粗糙、最鲁棒的信息,就把规则、混沌、随机一刀切开。它对幅度、量纲、单调变换免疫,算力只是 O(n·m!),做实时 regime 检测几乎是白送。但它也只是「复杂度」——不是收益、不是方向、不是因果。把它当成一个状态描述子:PE 高 → 市场无序 → 收杠杆;PE 低且稳定 → 规律可期 → 趋势/均值回复策略的环境在。再配上合适的嵌入维度 m 与窗口,它就能稳稳待在你的市场显微镜里。

完整可复跑代码与全部图表脚本已随本文生成(gen_perm_entropy.py),三类序列的 PE 对照、序数模式频率、滑动窗 regime 追踪、m 维度曲线均由该脚本真实计算。

排列熵与复杂度:用序数模式把「混沌」和「随机」一刀切开
https://blog.halo26812.eu.org/blog/permutation-entropy-complexity
Author halo
Published at 2026年7月23日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨