DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

Matplotlib 箱线统计遇到全 masked 数据,报空数组 IndexError

Matplotlib 3.11.2 仍在去除 mask 前检查数组长度。可先按组取得未掩码数据,让空组走空数据统计,保留标签;填零或回退到忽略 mask 的实现会改变结果。

一组数据全部被 mask 后,matplotlib.cbook.boxplot_stats() 没有返回空组统计,而是在 NumPy 分位数计算中报 IndexError: index -1 is out of bounds for axis 0 with size 0。先检查的是去掉掩码后还剩几个观测值,而不只是原数组的长度。

Matplotlib 3.11.1 有这条具体失败路径,当前正式 3.11.2 仍先检查 len(x),再排除 masked 值。原数组含两个位置时,第一次检查认为非空;两个位置都被排除后,后面的百分位计算收到空数组。

进入统计前先得到有效观测

对于一组一维数值数据,可以先使用掩码数组的 compressed(),再把结果作为一组输入交给统计函数。下面是保留空组位置的说明例:

import numpy as np
from matplotlib import cbook

sample = np.ma.masked_array([10.0, 20.0], mask=[True, True])
visible = np.ma.asarray(sample).compressed()
stats = cbook.boxplot_stats([visible], labels=["sample"])
assert len(stats) == 1
assert np.isnan(stats[0]["med"])

这里的外层列表明确表示一个组,即使其中没有有效值,也保留这组标签。统计结果中的中位数等字段应按空数据得到 NaN;是否在图上标注“无有效数据”,由报表自己的缺失值规则决定,不能把 NaN 当成真实的零。

compressed() 会返回未被 mask 的一维数据。多组或二维输入应按各组的原分界处理,不能把整张表一次压平,让不同分组混在一起。它也不会自动排除未被 mask 的 NaN 或无穷值;项目若还有这些缺失约定,需要单独核对,不能在这次修正中顺手改变样本范围。

不要用填零或旧版忽略掩码恢复绘图

移除 mask、对底层 .data 直接统计,会把明确排除的值重新放回样本。把 masked 值填为 0 也会改变均值、四分位数和须线。旧实现即使没有抛异常,也可能忽略掩码而得到错误统计,回退到它不能证明结果正确。

如果业务决定不展示全空组,要同时保留原分组标识与缺失记录,再显式调整标签和横轴位置。只过滤掉一个数组而不调整其余信息,会让图中的值和名称错位。

验收应包含全空、全 masked、部分 masked 和普通有效组,比较每组的有效样本数、标签、中位数与四分位数,再检查实际保存的图。不要用关闭 NumPy 警告或捕获 IndexError 后返回零来隐藏问题。保留原数组及 mask;已经导出的错误统计,需要按原分组重算,不能只重新打开旧图片。