DEBUG.WIKI
OnlineSIM:在线接收短信,虚拟号码租用
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
阿里云;从建站到云上业务;云服务器 · 数据库 · 对象存储;查看产品 →

relfreq 加权后总和不是 1:核对频数权重与分母

把重复样本压缩成值和频数后,旧 relfreq 可能仍按压缩后的行数归一化。说明 SciPy 1.18.1 正式实现及区间外样本的影响。

把 100 个样本压缩成 10 个不同取值,再把各值出现的次数传给 stats.relfreq(..., weights=counts),输出之和却是 10。若加权直方图的每个箱已经累加频数,再除以压缩后的 10 行,就不会得到原始 100 个样本的相对频率。

这里要先确认 weights 表达的是出现次数。旧计算路径无论有没有权重都除以样本数组长度,压缩前后会得到不同结果。SciPy 1.18.1 的正式实现已经在有权重时使用权重总和作为分母;非加权输入则仍按观测数量处理。

保持相同分箱,再比较展开与压缩输入

压缩前后的分箱边界应相同。否则,频数归一化正确,也可能因为箱位置改变而比较失败。下面用明确的频数权重说明对照关系:

import numpy as np
from scipy import stats

values = np.array([1.0, 2.0, 3.0])
counts = np.array([2, 3, 5])
expanded = np.repeat(values, counts)
kwargs = {"numbins": 3, "defaultreallimits": (0.5, 3.5)}
a = stats.relfreq(expanded, **kwargs)
b = stats.relfreq(values, weights=counts, **kwargs)
np.testing.assert_allclose(a.frequency, b.frequency)

预期三箱为 0.2、0.3、0.5。频数应有限、非负,总和大于零,且与值一一对应。调查抽样权重、负权重或其他加权统计任务,不能仅凭“结果应加起来等于 1”就改写其统计定义。

需要显式控制时,先累计箱权重再归一化

无法调整旧环境、且任务确实需要频数相对频率时,可使用明确边界的加权计数:

edges = np.array([0.5, 1.5, 2.5, 3.5])
weighted, _ = np.histogram(values, bins=edges, weights=counts)
frequency = weighted / counts.sum()

这段接在前面的输入定义后,density 保持默认 False。np.histogram(..., density=True) 返回的是概率密度:箱高乘箱宽之后的积分为 1,箱高直接相加不必为 1,不能将它当作不分箱宽的相对频率。

分母也不能一律换成已入箱的权重和。如果显式区间排除了部分样本,以全部权重为分母时,箱内频率总和小于 1 是合理的;改按箱内权重重新归一化,表达的是“已知落入此区间”的条件分布。两种问题应由业务定义决定。

不能用一次求和掩盖分箱错误

验收同时比较每箱频率、边界、箱宽、区间外数量以及总权重。还应覆盖单位权重、压缩频数和部分观测落在区间外的情况。空输入或零总权重需要单独政策,不能让除零产生的 NaN 作为正常概率流入后续判断。

更新依赖后应回到同一份输入和边界复查。已经生成的占比、阈值或报表不会因库更新而自动重算,保留原权重定义与输出批次,避免把旧归一化和新归一化结果混在同一比较中。