我最早把“三体嵌套分形”这五个字写进工作笔记,是为了给一套多层级调度系统做复杂度体检。当时团队里两拨人吵得挺凶:一拨认为复杂度就是模块数乘接口数,另一拨坚持要看运行时的波动特征。两边都有道理,但两边都解释不了同一个现象——系统规模翻了一倍,故障密度却涨了接近四倍,而且三个不同层级的监控曲线长得惊人地像,只是横轴尺度不同。后来我们把数据按单节点、单集群、全局三个层级切开,各自算分形维数,再把尺度比对齐,那条增长曲线才露出真面目:它本身就是自相似的。所谓“三体嵌套分形”,在我这里的定义很朴素——三个尺度层级互相嵌套,层内自相似,层间按固定增益耦合。它要解决的问题也很具体:给系统复杂性的“自相似增长”找一个可计算、可比较、可复盘的量化口径,而不是停留在“感觉变复杂了”这种描述上。这套东西适合谁?做过系统观测、写过指标管道、又对非线性特征好奇的工程师;也适合做建模分析、需要给复杂度找一个标量指标的研究型同学。基础要求不高,会写点 Python、能看懂双对数坐标图就够。
1. 整体设计与思路拆解
1.1 把“三体嵌套”翻译成三个可计算的尺度层
很多人看到“三体”两个字容易往天体物理或者科幻作品上联想,我这里先把话说死:它跟那些都没关系。在这套模型里,“三体”指的是三个彼此嵌套的观测尺度层级,我习惯叫它们微层、中层、宏层。微层是单个节点或者单次事件级别的行为纹理,采样粒度最细,噪声也最大;中层是集群、模块、分区级别的聚合波动,它把微层的细节抹平了一部分,但保留了局部结构;宏层是系统整体或者全局视角下的涌现模式,采样最粗,但最能反映长期趋势。
为什么非得是三层,两层或者四层行不行?我试过。两层的模型太容易把“局部抖动”和“全局趋势”混成一锅,做出来的维数曲线没有明显的平台区,拟合出来的斜率很不稳。四层呢,最细那层的采样成本高得离谱,而且层与层之间的尺度比一旦拉得太大,跨层耦合系数就会被噪声吃掉,算出来的增益基本是随机数。三层是一个经验上的甜点:尺度比通常落在 4 到 12 之间,既能让每一层的自相似结构显形,又不至于让采样成本失控。这个结论不是理论推导出来的,是拿不同层级数的配置跑了几十组对照之后选出来的。
三层之间不是简单的包含关系,而是嵌套关系。嵌套的意思是:中层的每一个观测窗口内部,都嵌着一个完整的微层结构;宏层的每一个窗口内部,又嵌着一个完整的中层结构。这一点很关键,它决定了后面所有计算都不能用简单的加权平均,必须用递归或者分块对齐的方式处理。你可以把它想成俄罗斯套娃,但每一层娃娃的脸长得一样,只是尺寸不同——这个“长得一样”就是自相似,而“尺寸按固定比例缩放”就是标度律。
1.2 为什么用分形而不是方差、熵这些常规统计量
常规统计量的问题不在于不准,而在于它们对尺度不敏感。均值、方差、甚至香农熵,算的是某个固定窗口内的整体离散程度,你把窗口放大十倍,数值会变,但变化的规律通常没有结构。换句话说,它们告诉你“抖得厉害不厉害”,但不告诉你“抖的方式在不同尺度上是否一致”。
分形这套工具的核心价值就在这儿:它专门刻画“不同尺度下结构是否重复”。盒计数维数回答的是“覆盖这个结构需要多少个盒子,盒子边长缩小一半,盒子数量涨几倍”;Hurst 指数回答的是“序列的长程相关性有多强,是持续性还是反持续性”;空隙度回答的是“结构的分布是否均匀,有没有明显的空洞”。这三个指标凑在一起,基本能把一个系统的复杂度纹理描述清楚。
更实际的一点是,分形指标对“规模变化”天然友好。传统指标在系统扩容之后往往需要重新标定基线,因为绝对数值全变了。分形维数是个无量纲的量,它描述的是增长的方式而不是增长的绝对量,所以扩缩容之后基线基本能复用。我在实际项目里最看重这一点:一套指标如果每次架构调整都要重新校准,那它基本没法进常态化的观测体系。
1.3 三层模型的骨架与数据流
整个模型我拆成三块:观测层、生成层、度量层。观测层负责按三个尺度切数据,切的时候必须保证窗口是嵌套的,也就是微层窗口要能整除中层窗口,中层窗口要能整除宏层窗口,否则后面做跨层对齐会很难受。生成层负责把原始序列转成适合做分形分析的形式,常见做法是转成二值化的占用图或者累积和序列。度量层就是算指标、拟合斜率、算跨层增益。
数据流是单向的,但有一处回环:度量层算出来的跨层增益会反过来校验观测层的窗口切分是否合理。如果三个层级的增益系数差异过大,比如微层到中层的增益是 0.3,中层到宏层的增益是 2.7,那基本可以判定窗口切分出了问题,或者某一层的数据被别的周期污染了。这个回环是我后来加的,一开始没有,结果有一批数据算出来增益是负的,查了两天才发现是采样间隔没对齐,微层用的是秒级,中层用的是分钟级,中间有个 60 倍的错位,直接导致尺度比算错。
注意:三层窗口必须满足整除关系,尺度比建议取整数倍。非整数倍的尺度比会让盒计数过程中的盒子边界对不齐,拟合出来的维数系统性偏低,这个偏差在小样本上尤其明显。
2. 核心参数体系与量化公式
2.1 自相似增长的标度律怎么写成可算的形式
自相似增长的核心是一个幂律关系。设系统在尺度 L 下的复杂度为 C(L),那么自相似增长可以写成:
C(L) = C0 * L^β这里的 β 就是自相似增长指数,也叫标度指数。β 等于 1 表示复杂度随规模线性增长,β 大于 1 表示超线性增长,也就是规模扩大之后复杂度加速膨胀,β 小于 1 表示亚线性增长,通常对应规模经济或者结构简化。这个指数的实际意义比它看起来要大:我之前做过一组对照,两套功能相近的系统,一套 β 是 1.08,另一套是 1.62,前者扩容三次故障率基本平稳,后者扩容两次就开始出现连锁抖动。β 差 0.5,运维成本差一个量级。
具体怎么算?最稳的办法是对两侧取对数,然后做线性回归:
log C(L) = log C0 + β * log L回归的斜率就是 β,截距是 log C0。这里有个坑要提前说:L 的取值不能太密也不能太疏。太密的话相邻尺度的数据高度相关,回归的标准误会被人为压低,看起来拟合得很好其实没有信息量;太疏的话点数不够,斜率容易被一两个异常点带偏。我的经验是取 6 到 9 个尺度点,按等比数列排布,比如 L 取 8、16、32、64、128、256、512,公比固定为 2。这个配置在大多数场景下够用,数据量特别大的时候可以加密到 12 个点。
分形维数 D 和 β 之间是有换算关系的。对于一条自相似的曲线,如果它是以“覆盖”的方式定义的,那么 D 大致等于 2 减去 β;如果是按“增长”定义的,D 和 β 的关系取决于具体的生成机制。我在实操里不强行套公式,而是两个都算,然后看它们的走势是否一致。一致说明模型自洽,不一致说明数据里混进了非自相似的成分,得回去查。
2.2 三个嵌套维数与跨层增益系数
三体嵌套模型的精髓在于,它不是算一个维数,而是算三个维数,再算它们之间的传递关系。设微层、中层、宏层的维数分别是 D1、D2、D3,尺度比分别是 λ1(中层窗口除以微层窗口)和 λ2(宏层窗口除以中层窗口),那么跨层增益系数定义为:
g12 = (D2 - D1) / log(λ1) g23 = (D3 - D2) / log(λ2)这两个系数的物理含义是“每放大一个尺度单位,复杂度增加多少”。如果 g12 和 g23 接近相等,说明系统在不同尺度上的复杂度增长是同构的,这是典型的自相似结构。如果 g12 明显大于 g23,说明复杂度主要产生在细粒度层面,放大尺度之后被平均掉了,这类系统的典型特征是局部噪声大但全局稳定。反过来 g23 大于 g12,说明复杂度在聚合层面才涌现出来,细粒度看起来很干净,一到全局就乱,这类系统最难排查,因为你在单节点上看什么都正常。
我一般还会算一个嵌套一致性指标:
κ = |g12 - g23| / max(g12, g23)κ 小于 0.15 我认为是强自相似,0.15 到 0.35 是中等,超过 0.35 就要怀疑三个层级是不是真的嵌套关系,或者数据里混进了外部周期。这个阈值不是拍脑袋定的,是拿十几组已知结构的合成数据反推出来的:强自相似的数据集 κ 基本落在 0.08 到 0.12,混入一个异质周期之后 κ 会跳到 0.4 以上。
2.3 配套指标:空隙度、Hurst 指数与多尺度熵
光有维数还不够,维数只回答“结构有多复杂”,不回答“结构分布得匀不匀”和“序列有没有记忆”。所以我会配三个辅助指标。
空隙度描述的是结构的空间分布均匀性。算法很简单:用一个边长为 r 的滑动窗口扫过整个结构,统计窗口内占用像素比例的方差和均值,空隙度等于方差除以均值的平方再加一。均匀分布的结构空隙度接近 1,聚集型结构的空隙度会显著大于 1。这个指标在排查“复杂度是不是集中在某几个区域”时特别好用。
Hurst 指数描述长程相关性。H 等于 0.5 表示随机游走,大于 0.5 表示持续性,小于 0.5 表示反持续性。算的时候用 R/S 分析法:把序列切成若干长度为 n 的块,每块算极差除以标准差,然后对所有块取平均,最后对 log(n) 和 log(R/S) 做回归,斜率就是 H。这里要注意块长不能太大,一般不超过序列总长的四分之一,否则每块的样本太少,R/S 的估计会失真。
多尺度熵是这套体系里我最喜欢的指标,因为它直接把“自相似”变成了曲线形状。做法是对原始序列做粗粒化,尺度因子 τ 从 1 取到 20,每个 τ 下算样本熵,然后看样本熵随 τ 的变化曲线。自相似性强的序列,样本熵随 τ 下降得慢,曲线接近水平;自相似性弱的序列,样本熵下降得快,曲线陡降。我通常取曲线下面积作为单一的复杂度量化值,面积越大表示复杂度越“厚”。
| 指标 | 刻画维度 | 典型取值范围 | 主要用途 |
|---|---|---|---|
| 盒计数维数 D | 结构复杂度 | 1.0 - 2.0 | 判断结构是否分形 |
| 增长指数 β | 规模敏感性 | 0.5 - 2.0 | 判断扩容风险 |
| 跨层增益 g | 层间传递 | -1.0 - 3.0 | 判断复杂度来源层 |
| 嵌套一致性 κ | 自相似强度 | 0 - 1.0 | 判断三层是否同构 |
| 空隙度 Λ | 分布均匀性 | 1.0 - 5.0 | 定位复杂度聚集区 |
| Hurst 指数 H | 长程相关性 | 0 - 1.0 | 判断趋势持续性 |
| 多尺度熵面积 | 复杂度厚度 | 0.1 - 3.0 | 综合对比 |
3. 从零搭一套可复现的量化流程
3.1 数据准备与三层嵌套切分
数据准备这一步决定了后面所有计算的上限,我在这上面栽过的跟头比算法本身多得多。第一步是确定采样粒度,微层的采样间隔必须能整除中层,中层必须能整除宏层。举个具体配置:微层 10 秒一个点,中层 5 分钟一个点(30 个微层点聚合),宏层 2 小时一个点(24 个中层点聚合)。这个配置下 λ1 等于 30,λ2 等于 24,两个尺度比都落在合理区间内。
聚合方式也要想清楚。求平均是最省事的,但它会抹掉峰值信息,导致中层的维数系统性偏低。我的做法是同时保留三个聚合量:均值、极差、超阈计数,然后用这三个量分别算维数,取它们的几何平均作为该层的代表维数。这样既保留了水平信息,也保留了波动信息和稀疏事件信息。算麻烦一点,但结果稳得多。
预处理里还有一个容易被忽略的环节:去趋势。很多系统指标本身带缓慢漂移,比如内存占用随运行时长单调上升,这种趋势会让 Hurst 指数虚高,算出来接近 1,看起来持续性极强,其实是趋势在作祟。去趋势用差分或者滑动中位数扣除都行,我倾向滑动中位数,因为它对尖峰不敏感。
import numpy as np import pandas as pd def nested_split(series, micro_step, meso_ratio, macro_ratio): """ series: 一维数组,微层采样 micro_step: 微层采样间隔(秒) meso_ratio: 中层包含的微层点数 macro_ratio: 宏层包含的中层点数 返回三层嵌套的聚合序列 """ n = len(series) meso_len = n // meso_ratio macro_len = meso_len // macro_ratio trimmed = series[: meso_len * meso_ratio] micro = trimmed meso = trimmed.reshape(meso_len, meso_ratio) macro = meso[: macro_len * macro_ratio].reshape(macro_len, macro_ratio * meso_ratio) return { "micro": micro, "meso": meso, "macro": macro, "lambda1": meso_ratio, "lambda2": macro_ratio, }3.2 盒计数维数的实现细节与常见偏差
盒计数是分形分析里最基础也最容易写错的一步。标准做法是把序列转成二维的占用图,然后用不同边长的盒子去盖,统计非空盒子数,最后对盒子数和边长倒数做双对数回归。问题在于“转成二维占用图”这个操作有很多种实现,不同实现算出来的维数能差 0.2 以上。
我用的是一种比较稳妥的构造方式:横轴是时间,纵轴是数值,先把数值归一化到 0 到 1,然后按网格量化。网格的行数决定了纵轴的量化精度,行数太少会让结构塌缩成几条线,维数虚低;行数太多会让噪声也被当成结构,维数虚高。经验值是行数取序列长度的平方根,比如一万个点取 100 行。
回归区间也要挑。双对数图上,盒子边长太小的时候曲线会被噪声主导,太大时盒子数会饱和到 1,这两个区间都不能用。我通常只取中间那段线性度最好的区间,判断方法是看局部斜率是否稳定,斜率变化超过 20% 就切掉。
def box_counting_dim(signal, n_rows=None): x = (signal - signal.min()) / (signal.max() - signal.min() + 1e-12) n = len(x) if n_rows is None: n_rows = max(8, int(np.sqrt(n))) grid = np.floor(x * (n_rows - 1)).astype(int) sizes = [] counts = [] s = 2 while s <= n // 8: nb = n // s occupied = set() for i in range(nb): row = grid[i * s:(i + 1) * s] occupied.add((i, int(np.median(row)))) counts.append(len(occupied)) sizes.append(s) s *= 2 log_s = np.log(np.array(sizes, dtype=float)) log_c = np.log(np.array(counts, dtype=float)) slope, _ = np.polyfit(log_s, log_c, 1) return -slope这段代码里有个细节值得说:每个时间块我用中位数作为该块的代表行号,而不是用所有出现过的行号。用所有行号的话,噪声大的序列会占据很多行,盒子数虚高,维数偏向 1.5 以上;用中位数则只保留主结构,噪声被压掉,算出来的维数更贴近真实纹理。两种做法我都试过,在同一批数据上差 0.18 到 0.25,最后选了中位数版本,因为它在不同数据集之间的排序更稳定。
3.3 跨层耦合系数与嵌套一致性的计算
跨层耦合系数不能直接拿三个维数硬套公式,因为三个层级的样本量差着数量级,直接回归会引入偏差。我的做法是先各自算维数,再做一次尺度归一化,然后才代入增益公式。归一化的方式是除以该层样本数的对数,这样三层就站在同一条起跑线上了。
def cross_layer_gain(d1, d2, d3, lambda1, lambda2): g12 = (d2 - d1) / np.log(lambda1) g23 = (d3 - d2) / np.log(lambda2) kappa = abs(g12 - g23) / max(abs(g12), abs(g23), 1e-9) return {"g12": g12, "g23": g23, "kappa": kappa}算完增益,我还会做一件事:把三层的维数画在同一张图上,横轴是层级的对数尺度,看三个点是否近似共线。共线说明三层严格自相似,不共线说明某一层的数据有问题或者该层本身有独立的结构。这个检查特别直观,我在项目里基本靠扫一眼这张图就能判断数据质量。
3.4 多尺度熵曲线作为交叉验证
维数算完之后我一定会用多尺度熵做一遍交叉验证。两者的计算逻辑完全不同,如果它们给出的复杂度排序一致,结论就比较可靠;如果不一致,那就要回去查是维数算错了还是熵算错了。
def sample_entropy(x, m=2, r_factor=0.2): r = r_factor * np.std(x) n = len(x) def phi(mm): cnt = 0 for i in range(n - mm): for j in range(i + 1, n - mm): if np.max(np.abs(x[i:i+mm] - x[j:j+mm])) < r: cnt += 1 return cnt b = phi(m) a = phi(m + 1) return -np.log((a + 1e-12) / (b + 1e-12)) def multiscale_entropy(x, max_tau=20, m=2, r_factor=0.2): vals = [] for tau in range(1, max_tau + 1): n = len(x) // tau coarse = x[:n * tau].reshape(n, tau).mean(axis=1) vals.append(sample_entropy(coarse, m, r_factor)) return np.array(vals)样本熵的复杂度是 O(n²),序列长了会很慢。我在实际用的时候会先做一次降采样,把序列长度压到 2000 以内再算,精度损失可以接受。另外 r_factor 这个参数要跟着数据的噪声水平调,噪声大的数据用小一点,噪声小的大一点,否则算出来的熵值全是饱和的。
4. 模拟项目实测:三个层级的复杂度演化
4.1 场景设定与数据特征
拿一个模拟项目来说事。这个项目是一套三层调度结构:底层是若干工作节点,中层是若干分区调度器,顶层是全局协调器。我们把三个层级的负载指标各采了一年的数据,微层 10 秒一个点,中层 5 分钟一个点,宏层 2 小时一个点,正好满足 30 倍和 24 倍的整除关系。
这一年里系统经历了一次大扩容,节点数从 40 涨到 160,分区数从 4 涨到 12。扩容发生在第 7 个月。我们想看的是:扩容之后复杂度是线性涨的还是有加速,三层级的增长关系有没有变化。
预处理阶段做了三件事:滑动中位数去趋势(窗口取 1 小时)、按层归一化到 0 到 1、剔除采样缺失超过 5% 的时间窗。剔除这一步很关键,缺失数据会让盒计数在对应位置出现空洞,空隙度会被显著抬高,如果不剔除,算出来的空隙度虚高 0.6 以上。
4.2 结果对照与解读
扩容前算出来的三层维数分别是:微层 1.32,中层 1.41,宏层 1.58。三层递增,说明复杂度确实是往上层聚集的,细粒度相对简单,聚合之后才复杂起来。对应的跨层增益 g12 是 0.026,g23 是 0.053,κ 算出来是 0.51。这个 κ 偏高,说明扩容前系统其实不是强自相似的,宏层有自己的独立结构。
扩容后重算:微层 1.38,中层 1.55,宏层 1.83。g12 涨到 0.050,g23 涨到 0.086,κ 降到 0.42。变化的方向很有意思:三层维数都在涨,但中层的涨幅最大,说明扩容之后复杂度主要堆在了中间层。κ 虽然还是偏高但确实下降了,意味着系统变得更“自相似”了——这个结论一开始让团队很意外,因为直觉上扩容应该让系统更异构才对。
后来想明白了:扩容前的系统里,各分区是手工配置的,结构差异大,所以宏层和微层对不上;扩容后统一了调度策略,各分区的结构被拉齐了,反而让三层变得更同构。复杂度总量上去了,但结构的一致性也上去了。这个发现直接改变了我们对“复杂度”的理解——复杂不等于异构,规模上去之后结构反而可能收敛。
再把增长指数算出来。以节点数为规模变量,微层 β 是 0.92,中层 1.31,宏层 1.47。三个都超线性,宏层超得最厉害。这个结果对容量规划的指导意义很直接:按节点数线性扩容是不够的,协调层的资源得按 1.5 次幂配置,否则扩到一定规模协调层会先崩。
| 层级 | 扩容前 D | 扩容后 D | 增长指数 β | 结论 |
|---|---|---|---|---|
| 微层 | 1.32 | 1.38 | 0.92 | 接近线性,节点级可控 |
| 中层 | 1.41 | 1.55 | 1.31 | 明显超线性,需重点扩容 |
| 宏层 | 1.58 | 1.83 | 1.47 | 超线性最强,协调层是瓶颈 |
4.3 参数敏感性
这套模型对上文提到的几个参数比较敏感,我做过一轮扫描。尺度比从 4 变到 12,算出来的维数变化在 0.05 以内,说明 λ 的选择不敏感,这是好事。盒子行数从 sqrt(n)/2 变到 sqrt(n)*2,维数能差 0.15,比较敏感,所以这个参数我写死在配置里不随便改。回归区间取点数量从 5 个变到 12 个,β 能差 0.2,也敏感,最终固定为 7 个点。
最敏感的是去趋势窗口。窗口取 30 分钟和取 4 小时,宏层的 Hurst 指数能差 0.3 以上。我的处理办法是让窗口跟着尺度走:微层用 10 分钟,中层用 1 小时,宏层用 6 小时,大致是各自采样间隔的 60 倍。这个比例是试出来的,没有理论依据,但在几组数据上都表现稳定。
提示:如果你只做一次评估,参数敏感性可以跳过;但如果要做前后对比或者跨系统对比,一定要固定全套参数,并且记在配置里。换参数之后算出来的维数没法直接比。
5. 常见问题与排查速查
5.1 典型故障与排查思路
这类分形量化最容易出问题的不是算法,是数据对齐和指标解释。我把踩过的坑整理成一张表,遇到问题先按表扫一遍,能省掉大半时间。
| 现象 | 可能原因 | 排查动作 | 处理方式 |
|---|---|---|---|
| 维数算出来大于 2 | 纵轴量化过细,噪声被当结构 | 检查盒子行数是否远超 sqrt(n) | 行数压到 sqrt(n) 附近重算 |
| 维数接近 1.0 | 盒子行数太少,结构塌缩成线 | 检查量子化后不同取值的个数 | 行数提高到 sqrt(n) 的 1.5 倍 |
| κ 大于 0.6 | 三层窗口不满足整除关系 | 核对三层采样间隔的倍数 | 重切窗口,保证整数倍 |
| 增益出现负值 | 层间数据错位或周期污染 | 画三层时序叠加图看相位 | 剔除外部周期后重算 |
| Hurst 接近 1.0 | 序列存在单调趋势 | 看原始序列是否有漂移 | 加滑动中位数去趋势 |
| 空隙度异常高 | 存在数据缺口 | 统计缺失率分布 | 剔除或插补缺失窗口 |
| 多尺度熵单调饱和 | r_factor 设置不当 | 看熵值是否贴边 | 按噪声水平重设 r_factor |
| β 回归 R² 低于 0.9 | 尺度点分布不均或点数太少 | 看双对数散点是否成线 | 调整为等比尺度点,补到 7 个 |
这里挑两个展开说。第一个是“增益出现负值”,这是最容易被误判成“系统负复杂”的情况。实际上负增益几乎总是数据问题:要么层间存在相位错位,比如中层窗口的起点比微层晚了半个窗口,聚合出来的序列和微层对不上;要么宏层混进了日周期,而微层和中层没有,导致宏层的维数被周期结构拉低。排查办法很简单,把三层时序画在同一张图上,错位会直接表现为波峰对不齐。
第二个是“β 回归 R² 低”,很多人第一反应是模型不对,其实多半是尺度点选得不合适。尺度点如果太密,相邻点高度相关,回归会高估 R²;太疏的话点数不够,方差大,R² 反而低。我一般要求 7 个点、公比固定,并且把 R² 低于 0.9 的样本直接标记为“不可用”,不强行解释。
5.2 几个只有真跑过才会知道的细节
第一个细节:三层的数据长度必须大致匹配。微层有一万个点、宏层只有二十个点的时候,宏层的维数估计会非常不稳,因为盒计数的尺度点根本凑不齐。我的经验是宏层至少要有 200 个聚合点,中层至少 500 个,微层至少 5000 个。达不到就拉长观测周期,别硬算。
第二个细节:分形维数不是越高越“复杂”。我见过有人拿维数当 KPI,追求高维数,结果把系统结构故意打散,维数上去了但可维护性崩了。维数只描述结构纹理的填充程度,1.8 的系统不一定比 1.4 的系统更难维护,关键看这个维数是怎么来的。如果复杂度集中在协调层,那才是真的麻烦。
第三个细节:跨层增益的符号比大小更重要。g 为正说明复杂度从下层往上递增,这是正常的;g 为负说明上层比下层还“简单”,通常意味着上层做过强聚合,细节被抹掉了,这种系统在宏观指标上看着很健康,实际一查就出问题。我在评估时会把负增益当成危险信号单独列出来。
第四个细节:这套模型不适合高频实时计算。盒计数和多尺度熵的计算量都不小,一万个点的序列跑一遍要几十秒。我的部署方式是离线批量跑,一天一次,结果写进时序库,实时监控还是用常规指标。把分形指标当实时告警用,要么算不过来,要么为了速度牺牲精度,两头不讨好。
最后分享一个我一直在用的小技巧:三层维数算完之后,先把它们画成一张三点折线图,横轴是层级对数尺度,纵轴是维数,看这三点是不是近似一条直线。这条直线的斜率就是整体的自相似强度,三点偏离直线的程度就是各层的独立结构强度。这张图比任何数字都直观,开会的时候拿出来,非技术同事也能一眼看出问题出在哪一层。我在好几个项目里都是靠这张图定位到瓶颈层的,比看一堆指标表快得多。