很多人在做数据体检的时候第一页永远只写均值、标准差、最大最小值然后就直接下结论说这批数据没问题。我见过不止一次这样的评审现场两组数摆在一起均值和方差几乎一模一样可把直方图画出来一个是规规矩矩的钟形另一个是拖着长长右尾巴、中间尖得像根针的形状。方差相同、均值相同为什么会连长得像不像都对不上原因很简单均值和方差分别是一阶、二阶的信息它们只描述了数据的位置和散布对形状这件事一无所知。偏度和峰度就是专门用来补这个缺口的两个指标前者告诉你分布往哪边甩尾巴后者告诉你尾巴有多厚。这篇内容面向已经会用均值方差、但还没系统建立分布形状判断习惯的数据分析从业者也适合做风控、做实验分析、做数据质量的同学当一份速查手册。我会从公式原理一路讲到代码实现、显著性判断和几个容易翻车的地方全部是可复现的操作。1. 均值方差看不住的东西偏度峰度怎么补位1.1 两批数同均值同方差却完全不是一类数据先做一个思想实验。A 组数据是 100 个来自标准正态的采样B 组数据是 95 个来自标准正态的采样再混进 5 个绝对值很大的极端值。这两组数据的均值都接近 0但 B 组因为那几个极端值方差会被抬高所以严格来说方差并不相同。真正让人困惑的场景是调参之后的对比把 B 组的数据做一次线性缩放让它的方差和 A 组对齐此时两组的均值和方差就完全一样了但它们的直方图形态天差地别。这种同均值同方差、不同形态的情况在真实业务里一点都不罕见。比如某电商平台统计用户月消费金额绝大多数人集中在几百到几千少数几个大客户能到几十万再比如某在线教育产品统计用户单次学习时长大部分人停留几分钟极少数人挂机一整天。这些数据的分布都严重右偏而一旦右偏用均值去描述典型用户就会失真——均值会被右侧那几条长尾拉得远远高于中位数。所以判断一批数据能不能用均值加减标准差来概括本质上是在问这批数据的分布形态是否接近对称、尾部是否足够薄。这两个问题正好对应偏度和峰度。我个人的习惯是任何一次描述性统计汇报均值、标准差、中位数、偏度、峰度这五个数必须同时出现缺一个都说明这次体检没做完整。1.2 从矩的角度理解三阶矩管方向四阶矩管尾巴要理解偏度和峰度的本质绕不开矩这个概念。在统计学里围绕均值定义的 k 阶中心矩是$$m_k \frac{1}{n}\sum_{i1}^{n}(x_i - \bar{x})^k$$一阶中心矩恒为 0没信息量二阶中心矩就是方差衡量数据离均值有多散三阶中心矩衡量的是偏离的方向性——正偏差的三次方是正的负偏差的三次方是负的两边不会互相抵消所以它能捕捉到哪一侧的偏差更重四阶中心矩因为四次方抹掉了符号衡量的是偏差的量级有多极端少数超大偏差会在四次方下被极度放大因此它对尾部极其敏感。把三阶、四阶中心矩除以标准差对应的幂次做标准化就得到了无量纲的偏度和峰度。这个标准化的动作很关键如果不除以 $\sigma^3$ 和 $\sigma^4$偏度和峰度就会带着量纲收入数据算出来的偏度和温度数据算出来的偏度根本没法比。标准化之后它们变成纯数字可以跨数据集比较。生活化的类比是这样的把均值想成一群人的重心位置方差想成大家散得多开偏度想成人群往哪一侧拖了一条长长的队伍峰度想成有没有几个跑得特别远的人。重心和散布告诉你队伍大概在哪、有多宽但只有加上后面两个你才知道这队伍是圆的还是拖着尾巴的。1.3 一个常被忽略的事实形状指标不是线性可加的这里要提前埋一个坑后面第 6 节会展开。偏度和峰度都是标准化矩分母里带着标准差它们不是线性可加的统计量。这意味着你把 10 个城市的数据各自算出偏度再取平均得到的数字和把 10 个城市数据合在一起算一个偏度完全是两回事。很多人做分组汇总表时习惯性地对偏度列取平均这在数学上是没有意义的。同样地也不能说整体偏度等于各部分偏度之和。方差好歹还有方差分解公式偏度和峰度没有类似的简单可加性。这一点在做多层级报表时特别容易出错记住一句话就行偏度峰度只能对原始数据算不能对汇总值再算。2. 偏度把往哪边甩尾巴翻译成一个可比的数字2.1 手算一遍公式看清分子分母各自在干什么样本偏度最常用的定义是 Fisher-Pearson 标准化矩系数$$g_1 \frac{m_3}{m_2^{3/2}} \frac{\frac{1}{n}\sum (x_i-\bar{x})^3}{\left[\frac{1}{n}\sum (x_i-\bar{x})^2\right]^{3/2}}$$分子是三阶中心矩负责判断方向分母是方差的 1.5 次方负责把量纲消掉。举个小例子数据是[1, 2, 3, 4, 100]。均值是 22五个偏差分别是 -21、-20、-19、-18、78。把这些偏差立方后前四个加起来大约是 -9261-8000-6859-5832 -29952最后一个是 78³ 474552总和约 444600除以 5 得 88920。方差这边偏差平方和约 4414003613246084 7610除以 5 得 1522取 1.5 次方约 59370。所以 $g_1 \approx 88920/59370 \approx 1.50$。这个 1.50 的含义就是右边那条尾巴比左边重得多。你可以顺手算一下中位数是 3均值是 22均值远大于中位数这正是右偏分布的典型特征。这个均值大于中位数就是右偏的经验判断在单峰分布上非常好用但遇到双峰分布会失效不能当作定理用。需要特别注意的是当 $n$ 较小的时候上面这个 $g_1$ 是有偏的。统计上常用的修正版本是$$G_1 \frac{\sqrt{n(n-1)}}{n-2} \cdot g_1$$这个修正因子在 $n$ 很大时趋近于 1所以大样本下两者几乎没有区别。但如果你在做小样本分析比如每组只有 20 个观测的 A/B 实验用哪个版本就会带来可见的差异。2.2 正偏负偏在业务里的真实含义以及最常见的误读偏度为正叫右偏尾巴拖在右边偏度为负叫左偏尾巴拖在左边。听起来简单但误读率极高。我见过最常见的错误是看到偏度为正就说数据整体偏大。这是完全相反的。右偏的真实含义是大部分观测值集中在较小的区间少数极大的值把均值往上拽。收入、消费金额、页面停留时长、订单金额、城市人口几乎全是右偏。右偏时均值 中位数用均值描述典型值会系统性高估。这时候正确的做法是报中位数或者报截尾均值比如去掉最高的 1% 再算平均。左偏相对少见典型场景是天花板效应一场很简单的考试大部分人考 90 分以上少数人不及格尾巴拖在左边。这时候均值 中位数均值会低估典型水平。把判断规则整理一下方便随时对照偏度符号分布形态均值与中位数关系业务上的典型信号接近 0绝对值小于 0.5近似对称均值约等于中位数数据可用均值描述正大于 0.5右偏长尾在右均值明显大于中位数存在少量超大值考虑用中位数或对数变换负小于 -0.5左偏长尾在左均值明显小于中位数存在少量极小值警惕数据缺失被填成了 0表中的 0.5 这个阈值是经验值不同领域的教材给的数字不一样有的用 0.5有的用 1。我的建议是别把它当硬性标准把它当提示灯超过 0.5 就该去画图看看了至于要不要做变换还得结合业务判断。顺带说一个极端情况如果偏度绝对值超过 2通常意味着数据里有几个非常突出的点这时候第一反应不应该是数据偏斜严重而应该是我是不是有脏数据没清掉。2.3 三种常见算法与一条样本量红线实际动手时你会遇到至少三种偏度值它们在小样本下差别明显原始矩估计scipy.stats.skew(x, biasTrue)直接用 $g_1$有偏但计算简单样本修正估计scipy.stats.skew(x, biasFalse)或pandas.Series.skew()用 $G_1$是无偏估计日常分析推荐用这个分位数偏度Bowley skewness$\frac{Q_3 Q_1 - 2Q_2}{Q_3 - Q_1}$只用三个分位数取值范围固定在 -1 到 1对离群值完全不敏感。分位数偏度这个工具值得单独说一下。它的最大价值是抗干扰如果你怀疑数据里有未被清理的异常值用分位数偏度得到的结论会比矩偏度稳得多。代价是它对分布中段的变化不敏感只能看大方向。样本量这条红线必须强调。偏度的标准误近似为$$SE(g_1) \approx \sqrt{\frac{6n(n-1)}{(n-2)(n1)(n3)}}$$当 $n30$ 时这个标准误大约是 0.43当 $n1000$ 时降到 0.077。也就是说30 个样本算出来的偏度如果是 0.4它连一个标准误都不到完全可能是随机波动不能下数据右偏的结论。经验做法是$n$ 小于 100 时偏度只当参考$n$ 小于 30 时基本别用偏度下结论直接画图更靠谱。3. 峰度判断厚尾风险的那把尺子以及它最大的定义误会3.1 超额峰度与原始峰度的换算以及那个致命的默认参数峰度的定义是四阶标准化矩$$g_2 \frac{m_4}{m_2^2} \frac{\frac{1}{n}\sum(x_i-\bar{x})^4}{\left[\frac{1}{n}\sum(x_i-\bar{x})^2\right]^2}$$对正态分布这个值恒等于 3。为了让正态对应到 0方便判断业界普遍使用超额峰度excess kurtosis$$\text{excess} g_2 - 3$$这里就是翻车事故的高发区。scipy.stats.kurtosis()的默认参数是fisherTrue返回的是超额峰度也就是正态分布会返回 0。而很多人想当然地以为它返回的是原始峰度看到结果是 0 就以为数据没有峰或者看到结果是 3 就以为峰度很高。我见过一份分析报告把正态数据的峰度写成 0 并标注分布完全平坦这就是纯纯的参数误读。正确的写法永远显式指定参数from scipy import stats import numpy as np x np.random.default_rng(42).normal(size5000) print(stats.kurtosis(x, fisherTrue, biasFalse)) # 超额峰度正态约 0 print(stats.kurtosis(x, fisherFalse, biasFalse)) # 原始峰度正态约 3pandas.Series.kurt()同样返回超额峰度且默认无偏修正。记住一条pandas 和 scipy 的默认返回值都是超额峰度看结果先看它是不是在 0 附近。几个常见分布的超额峰度参考值用来建立直觉分布超额峰度形态特征正态分布0基准尾部衰减速度参照均匀分布-1.2平顶无尾极端值几乎不出现拉普拉斯分布3尖顶厚尾比正态更容易出极端值t 分布自由度 56厚尾明显金融收益常用混合分布95% 标准正态 5% 放大 5 倍正态约 17极端厚尾负的超额峰度叫低峰态正叫尖峰态。但这两个词很容易误导人下一节就来讲为什么。3.2 峰度高不等于更尖真正该看的是尾部概率这是峰度理解上最顽固的误区。教科书上经常画三张图把高蜂度的曲线画得又尖又瘦低峰度的画得又扁又宽久而久之大家就形成了峰度 尖不尖的条件反射。但数学上峰度是四阶矩它对离均值远的点的权重是距离的四次方对均值附近的点几乎没有区分能力。峰度本质上衡量的是尾部的重量不是顶端的尖锐度。我可以构造一个反例把这件事说死。取一个混合分布95% 的质量来自标准正态5% 的质量来自标准差为 5 的正态。算一下它的超额峰度方差 $ 0.95 \times 1 0.05 \times 25 2.2$四阶矩 $ 0.95 \times 3 \times 1^2 0.05 \times 3 \times 25^2 2.85 93.75 96.6$标准化四阶矩 $ 96.6 / 2.2^2 \approx 19.96$超额峰度约 17而它标准化之后在均值 0 处的密度大约是 $0.95 \times 0.3989/1.483 0.05 \times 0.3989/5 \approx 0.2595$标准正态在 0 处的密度是 0.3989。也就是说这个分布的峰顶比正态低了一大截但峰度是正态的 17 倍。如果峰度真的是尖锐度这个结果就自相矛盾了。反过来均匀分布的超额峰度是 -1.2是典型的低峰态但标准化之后它在整个区间上的高度是 $1/(2\sqrt{3}) \approx 0.2887$并不比正态矮多少只是平顶而已。还有一个更有说服力的例子双峰分布。两个分离的峰看起来尖得很明显但它的峰度往往接近 0 甚至为负因为质量集中在两个峰附近远离整体均值的点反而不多。所以真正正确的解读方式是超额峰度为正且数值大说明出现远离均值的极端值的频率显著高于正态分布。它是一把衡量尾部风险的尺子。这解释了为什么金融领域对峰度如此执着——收益率的分布超额峰度动辄 5 以上意味着罕见的暴跌出现的频率远高于正态假设给出的预测而所有基于正态假设的风险模型都会在这个地方低估风险。3.3 用分位数和 QQ 图给峰度结论做交叉验证单看一个峰度数字容易误判我习惯用两个工具交叉验证尾部概率对比和 QQ 图。尾部概率对比的做法很直接对数据做标准化减均值除标准差然后统计落在 $|z| 3$ 之外的比例。正态分布下这个比例的理论值是 0.27%也就是 1000 个点里大约 2.7 个。如果你的数据有 1000 个点落在 3 倍标准差外的有 30 个那即使峰度算出来只是 2 或 3你也应该认定这是一个厚尾分布。这个方法的优点是直观、业务方一听就懂我们的数据里极端情况出现的频率是正态预期的 11 倍这种话比超额峰度是 8.3有说服力得多。import numpy as np def tail_ratio(x, k3): z (x - x.mean()) / x.std(ddof1) empirical np.mean(np.abs(z) k) from scipy.stats import norm theoretical 2 * (1 - norm.cdf(k)) return empirical, theoretical, empirical / theoretical rng np.random.default_rng(7) x rng.standard_t(df4, size20000) print(tail_ratio(x, 3))用 t 分布自由度 4 跑一下你会看到尾部比例大约是理论正态值的七八倍这个倍数比峰度数字更容易让非技术同事理解风险。QQ 图则是看整体形态。把数据的分位数和正态分位数画在一起如果尾部明显偏离直线往上翘右尾或往下坠左尾就是厚尾的直接证据。峰度只给你一个数字QQ 图给你形状两者一起看才能确定到底是整体偏移还是只有尾部异常。我的习惯是峰度超过 1 就画 QQ 图图上的尾部偏离如果肉眼可见就把这个结论写进报告如果看不出偏离那就说明峰度是被个别极端点撑起来的应该先去查数据质量。4. 代码实现把偏度峰度算准并做显著性判断4.1 numpy、scipy、pandas 三条路的差异三条路都能算出偏度和峰度但结果在小样本下会有肉眼可见的差别必须搞清楚用的是哪一套。import numpy as np import pandas as pd from scipy import stats x np.array([12, 15, 18, 21, 24, 27, 30, 95]) # 路线一numpy 手写完全可控 n len(x) dev x - x.mean() m2 np.mean(dev**2) m3 np.mean(dev**3) m4 np.mean(dev**4) g1 m3 / m2**1.5 g2 m4 / m2**2 - 3 print(f手写 偏度{g1:.4f} 超额峰度{g2:.4f}) # 路线二scipy显式指定 bias print(fscipy 偏度(有偏){stats.skew(x, biasTrue):.4f}) print(fscipy 偏度(无偏){stats.skew(x, biasFalse):.4f}) print(fscipy 超额峰度(有偏){stats.kurtosis(x, biasTrue):.4f}) print(fscipy 超额峰度(无偏){stats.kurtosis(x, biasFalse):.4f}) # 路线三pandas s pd.Series(x) print(fpandas 偏度{s.skew():.4f} 超额峰度{s.kurt():.4f})用上面这组只有 8 个数的数据跑一遍你会发现手写版本和 pandas 版本差了大概 10% 到 20%。原因是 scipy 的biasFalse和 pandas 用的是同一套样本修正公式$G_1$ 和 $G_2$而手写版本用的是原始矩。样本越小差异越大$n1000$ 以上时基本可以忽略。我的选择原则是做探索性分析、画图、跟同事沟通用 pandas 的默认方法无偏做算法内部的特征工程、需要和训练时完全一致就把公式手写死别依赖库的默认值。后者听起来啰嗦但吃过亏的都懂——换一个库版本默认参数变了特征分布悄悄漂移模型效果掉点却找不到原因。4.2 偏度峰度的显著性检验与 JB 正态性检验算出偏度是 0.6这个数到底算不算显著偏斜光看数值大小是不够的得看它相对于标准误的倍数。import numpy as np from scipy import stats def shape_test(x): x np.asarray(x, dtypefloat) n len(x) s stats.skew(x, biasFalse) k stats.kurtosis(x, biasFalse) se_s np.sqrt(6 * n * (n - 1) / ((n - 2) * (n 1) * (n 3))) se_k np.sqrt(24 * n * (n - 1) ** 2 / ((n - 3) * (n - 2) * (n 3))) return { n: n, skew: round(s, 4), skew_se: round(se_s, 4), skew_z: round(s / se_s, 3), kurt: round(k, 4), kurt_se: round(se_k, 4), kurt_z: round(k / se_k, 3), } rng np.random.default_rng(11) print(shape_test(rng.standard_t(df5, size800)))判断规则很简单$|z| 1.96$ 大致对应 5% 显著性水平$|z| 2.58$ 对应 1%。但要注意这两个公式本身依赖大样本近似$n$ 小于 50 时结论不太可靠别太当真。更系统的做法是直接上 Jarque-Bera 检验它同时把偏度和峰度纳入统计量$$JB \frac{n}{6}\left(S^2 \frac{(K-3)^2}{4}\right)$$其中 $S$ 是偏度、$K$ 是原始峰度$JB$ 在原假设数据来自正态分布下服从自由度为 2 的卡方分布。from scipy.stats import jarque_bera stat, p jarque_bera(x) print(fJB{stat:.2f}, p{p:.6f})用的时候有一个重要前提JB 检验的原假设是数据服从正态分布所以 $p$ 值小才代表拒绝正态。我见过有人把 $p 0.05$ 解读成数据不正态完全反了。另外JB 检验在大样本下极其敏感哪怕偏离正态的程度微乎其微$n$ 上到几万也会给出显著结果。所以大样本时不要只看 $p$ 值要结合偏度峰度的绝对大小一起判断——统计显著不等于业务上重要。4.3 一份可以直接抄走的分布体检脚本把上面这些串起来形成一份每次拿到新数据都能跑的体检脚本import numpy as np import pandas as pd from scipy import stats def profile_distribution(x, namecol): x np.asarray(x, dtypefloat) x x[~np.isnan(x)] n len(x) if n 8: return {name: name, note: 样本过少跳过形状分析} s stats.skew(x, biasFalse) k stats.kurtosis(x, biasFalse) se_s np.sqrt(6 * n * (n - 1) / ((n - 2) * (n 1) * (n 3))) se_k np.sqrt(24 * n * (n - 1) ** 2 / ((n - 3) * (n - 2) * (n 3))) z (x - x.mean()) / x.std(ddof1) tail3 float(np.mean(np.abs(z) 3)) jb_stat, jb_p stats.jarque_bera(x) flags [] if abs(s) 2 * se_s: flags.append(偏斜显著) if abs(k) 2 * se_k: flags.append(峰度显著) if tail3 0.01: flags.append(尾部偏厚3sigma外占比超1%) if jb_p 0.01: flags.append(拒绝正态) return { name: name, n: n, mean: round(float(x.mean()), 4), median: round(float(np.median(x)), 4), std: round(float(x.std(ddof1)), 4), skew: round(float(s), 4), skew_z: round(float(s / se_s), 2), kurt: round(float(k), 4), kurt_z: round(float(k / se_k), 2), tail3_ratio: round(tail3, 5), jb_p: round(float(jb_p), 6), flags: | .join(flags) if flags else 无明显异常, } rng np.random.default_rng(2024) df pd.DataFrame({ normal_like: rng.normal(100, 15, 3000), income_like: rng.lognormal(3, 1.2, 3000), heavy_tail: rng.standard_t(df4, size3000), }) for col in df.columns: print(profile_distribution(df[col], col))跑完之后你会得到一张三行的对照表第一行各项指标接近 0、无明显异常第二行偏度显著为正、均值远大于中位数第三行偏度接近对称但峰度和尾部比例都亮红灯。三种情况对应的处理方式完全不同这正是偏度峰度配合使用才能给出的判断。提示这份脚本里我把biasFalse全部显式写出来了不建议省略。代码是给未来的自己和同事看的默认值依赖是最难排查的问题来源之一。5. 落到业务里偏度峰度的几个实际用法5.1 收益序列的厚尾与阈值设定在某金融数据团队做过一段时间收益分析最深的一个体会是用正态假设去算风险阈值几乎必然出事。日收益率的超额峰度经常在 3 到 8 之间波动这意味着 4 倍标准差的事件在历史上出现的频率可能是正态理论预测的十几倍。具体做法上我的思路是先看峰度决定用哪套方法。超额峰度在 1 以内说明尾部还不算离谱正态假设误差可控超过 2就明确放弃正态假设改用历史分位数法或者 t 分布拟合超过 5则要额外检查是不是混入了不同时期的数据比如把极端行情和常态行情混在一起算因为混合分布本身就会制造高蜂度。举个具体的数字对比一批日收益率数据超额峰度 6.2标准差 1.8%。按正态假设99% 分位对应 2.33 倍标准差也就是 4.19%。但如果用实际分位数去取99% 分位可能是 5.8%。差了 1.6 个百分点在杠杆场景下这个差距足以决定是稳健还是爆仓。还有一点值得说峰度是会随市场状态变化的。平静期的峰度可能只有 1动荡期能冲到 10 以上。所以做滚动计算比看整体值更有意义我在第 6 节会讲滚动窗口的实现细节。5.2 数据清洗环节用偏度峰度做异常筛查这个用法可能没那么广为人知但实测非常好用。做数据质量检查时箱线图的 IQR 规则只能抓单点异常对整体形态的异常不敏感。而偏度和峰度可以当作形态指纹一批本来形态稳定的数据突然某一期的偏度从 0.8 跳到 4.5基本可以断定录入环节出了问题。一个具体的场景是某电商平台的每日 GMV 数据。正常情况下日 GMV 的偏度稳定在 1 左右右偏符合交易金额分布。某天偏度突然变成 8一查发现是后台把一笔大额企业采购也计入了零售口径。这种问题用均值方差根本看不出来——那笔采购只占当天总体的千分之几均值只涨了 2%完全在正常波动范围内但偏度会瞬间爆炸因为它是三次方的。落地时建议给每个关键指标建立一个形态基线连续采集 30 天的偏度和峰度算出均值和标准差之后每天的值偏离基线超过 3 个标准差就告警。这个方法比单纯监控均值的好处是它能抓住数量没变但结构变了的问题这类问题往往影响更大也更隐蔽。要注意的是这个基线必须按业务周期分别建立。周末和工作日的分布形态本来就不一样混在一起做基线会产生大量误报。我的经验是至少按星期几分组节假日再单独维护。5.3 A/B 实验里指标分布异常的早期预警做实验分析的同学应该都遇到过这种情况实验组和对照组的均值差了 1.2%做了 t 检验 p 值 0.03看起来显著但业务方质疑是不是有几个大户带偏了。这个质疑往往是对的。t 检验的前提是大样本下样本均值近似正态这个近似在分布严重偏斜或者厚尾时会打折扣。判断能不能用 t 检验偏度峰度就是一个快速的守门员。我的检查顺序是两组各自的偏度绝对值是否都在 1 以内若超出先做对数变换或缩尾处理两组的超额峰度是否都在 2 以内若超出说明有厚尾t 检验的置信区间可能偏窄两组的形态指标差异是否过大若一组偏度 0.3、另一组偏度 2.1说明实验本身改变了分布结构这时候只看均值差异是不够的得看分位数差异。如果形态检查不过关我会改用 bootstrap 方法估算差异的置信区间。方法不复杂import numpy as np def bootstrap_diff(a, b, n_boot5000, seed0): rng np.random.default_rng(seed) diffs np.empty(n_boot) for i in range(n_boot): sa rng.choice(a, sizelen(a), replaceTrue) sb rng.choice(b, sizelen(b), replaceTrue) diffs[i] sb.mean() - sa.mean() return np.percentile(diffs, [2.5, 97.5]) rng np.random.default_rng(1) a rng.lognormal(1, 1, 2000) b rng.lognormal(1.02, 1.3, 2000) print(bootstrap_diff(a, b))bootstrap 不依赖分布假设代价是计算量大一些5000 次重采样在普通机器上是秒级的事完全可以接受。更重要的是bootstrap 能看出置信区间是否对称——如果上下界严重不对称那说明分布形态确实在影响推断这时候报均值差 1.2%就不如报中位数差 0.8%且分布右尾变厚更准确。6. 几个最容易翻车的细节6.1 小样本下这两个数字的剧烈波动这件事必须反复强调因为我见过太多人在每组只有二十几个样本的实验里把偏度 0.8 当成数据严重右偏的证据。实际上 $n25$ 时偏度的标准误约 0.470.8 还不到两个标准误完全在随机波动范围内。做过一个简单的模拟从标准正态里反复抽 20 个样本算偏度10000 次下来偏度的范围大概在 -1.2 到 1.2 之间峰度的范围更夸张能从 -1.5 到 5。也就是说哪怕数据完全来自正态小样本的峰度也可能看起来像重度厚尾。所以我的处理原则是$n 50$ 时不看偏度峰度直接画直方图或者用分位数描述$50 \le n 200$ 时偏度峰度只作为辅助必须结合图形$n \ge 200$ 时才把数值结论写进正式报告。这个门槛不是死规定但能挡掉大部分误判。6.2 分组汇总再取平均的陷阱前面提过偏度峰度不可加但实际工作里这个坑的变种更多。典型场景是这样一张全国销售表需要按大区汇总很多人算完 8 个大区各自的偏度然后在报表底部加一行平均偏度。这个数字没有任何统计意义。正确做法只有一条拿到原始明细数据对合并后的数据重新计算。如果确实拿不到明细比如只拿到了各区汇总表那就别报偏度峰度改用分位数或者直接说明形态指标无法从汇总数据推算。还有一个更隐蔽的变种分段算完再拼。比如按时间分成 12 个月每月算一次偏度然后想把 12 个月拼成全年的偏度。这也是不行的。全年偏度必须用全年的原始数据算。想要月度偏度和年度偏度同时存在那就分别用对应粒度的原始数据各算一遍。6.3 滚动窗口计算与边界处理做时间序列监控时滚动偏度峰度是必备工具但有几个细节不注意会出错import pandas as pd import numpy as np rng np.random.default_rng(3) s pd.Series(rng.standard_t(df5, size500)) roll_skew s.rolling(window60, min_periods60).skew() roll_kurt s.rolling(window60, min_periods60).kurt() print(roll_skew.isna().sum()) # 前 59 个是 NaN这是正常的 print(roll_kurt.iloc[60:65])几个要注意的点第一前 window-1 个值是 NaN这是设计如此不是 bug。做图的时候要么直接跳过要么在报告里说明前 59 个点无值别让人误以为数据缺失。第二窗口长度的选择直接影响敏感性。窗口 30 对短期异常敏感但噪声大窗口 250约一年交易日平稳但滞后明显。我的经验是用两个窗口并行短窗口20 到 30做异常预警长窗口120 以上做趋势判断两个都亮了才动手排查。第三窗口内的样本量必须足够。min_periods一定要显式设置默认值可能小于 window导致前几个点用极少的样本算出一个噪声极大的值。这个坑我在生产环境里就踩过前面十几个点的滚动峰度冲到 20 多告警响了一整天。第四pandas的rolling().skew()内部用的是无偏修正版本如果你要和另一套系统比如某个用原始矩实现的计算引擎对齐数字必须显式验证。我做过一次跨系统比对同一份数据两边算出来的峰度差了 0.3最后定位就是修正版本不同。这种差异在大样本下无害但在做精确复现时会导致结论不一致。再补一个小技巧做滚动计算前先确认序列里没有缺失值。pandas的滚动窗口遇到 NaN 会按min_periods规则处理如果缺失较多算出来的偏度可能是基于不足一半的样本结果完全不可信。我习惯在滚动之前加一句s s.dropna()或者先做插值明确自己的处理逻辑别让它悄悄发生。
企业数字化 ERP 产品动态
相关推荐
Alist 多存储目录聚合:Docker部署与挂载排错指南 第一次折腾 Alist 的起因很朴素:手上三台设备、两个网盘账号、一块挂在路由器上的移动硬盘,找一份文档得先回忆它到底躺在哪儿。Alist 恰好就是治这个毛病的工具——它本身不存文件,本质是一层“目录聚合”,把本地目录、各类云盘、… · 2026/11/2 16:55:40
Web自动化测试中的元素定位与交互技术详解 1. 页面元素模拟操作的核心概念在Web开发与自动化测试领域,页面元素模拟操作是指通过编程方式对网页中的DOM元素进行识别、定位和交互的技术手段。这种技术最早可以追溯到2004年W3C发布的DOM Level 3事件规范,但直到近年来随着RPA(机器人流程… · 2026/11/2 16:54:38
TongRDS安装部署实战:数据库访问治理中间件配置指南 1. TongRDS不是数据库,而是数据库“管家”——先破一个常见误解刚接触TongRDS时,我翻遍了所有公开文档,第一反应是:这不就是个封装好的MySQL或PostgreSQL安装包吗?直到在某次模拟项目X的压测中,数据库连接池… · 2026/11/2 16:54:38
关键信息基础设施全栈安全防护架构解析 1. 项目背景与核心价值这份73页的PPT方案实际上是一套针对关键信息基础设施保护的完整技术架构设计。在数字化转型浪潮下,能源、交通、金融等行业的核心系统正面临前所未有的安全挑战。去年某大型制造企业因工控系统漏洞导致全线停产的事故,让行业真正意… · 2026/11/3 3:52:38
液氧甲烷火箭任务控制系统的分布式架构与关键技术 1. 项目背景与核心挑战当SpaceX用不锈钢材料颠覆了传统航天器的设计理念时,整个行业都意识到:低成本、高可靠性的重复使用运载器时代已经到来。两级液氧甲烷不锈钢火箭正是这一理念的典型代表,而它的任务控制中心(MCC)… · 2026/11/3 3:52:38
虚幻引擎打包全流程:从Development到Shipping的实战指南 1. 为什么“打包”这件事值得单独拎出来讲刚接触虚幻引擎那阵子,我一度以为把场景搭好、蓝图连好、角色跑起来,这个项目就算“做完了”。直到第一次要把东西发给别人看,才发现自己连一个能双击运行的成品都拿不出来。编辑器里跑得再流畅&… · 2026/11/3 3:52:38
本地大模型部署选型:Ollama、vLLM与Hugging Face 简介:《本地大模型部署利器——Ollama工具解析及应用》是一份面向NLP开发者、运维人员及本地化部署爱好者的PDF技术文档,聚焦数据隐私、云端响应延迟与部署门槛等痛点,系统梳理开源工具Ollama的定位与用法。文档从安装配置、模型管理、自定义… · 2026/11/3 3:52:38
Camera MetaData实战指南:从读取、写入到批量处理避坑 1. 从一张“颜色不对”的照片说起前阵子帮朋友处理一批手机拍摄的素材,同一台设备、同一个场景,导进电脑之后有几张照片明显偏绿,另外几张又偏暖,白平衡像是各拍各的。一开始怀疑是后期软件的色彩管理出了问题,折腾了半… · 2026/11/3 3:52:38
2024年TensorFlow实战指南:从Keras到部署,对比PyTorch 打开PyPI的下载统计页,TensorFlow依然是整个深度学习生态里下载量最大的框架之一。但在很多新手群里,一提TensorFlow总有人觉得这是“老框架”,好像已经被PyTorch全面超越了。我自己的感觉是,这种印象有对的部分,也有很… · 2026/11/3 3:51:38
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18