滚动均值与平均绝对偏差
Running Mean and Mean Absolute Deviation
开始编码某个流式统计服务接收一组数值样本,需要报告两个汇总量:算术 均值,以及 以均值为中心的平均绝对偏差(MAD),其定义为 MAD = mean(|x_i - mean(x)|)。均值是天然的位置估计量,MAD 是它的 L1 偏差搭档——最简单的不加权离散度度量,不对残差取平方。问题在于 MAD 依赖均值,而均值要等所有样本看完才能确定,因此严格意义上的单遍精确 MAD 是不可能的。标准做法是两遍:一遍算均值,第二遍累加绝对偏差。
实现 solution(values: list[float]) -> dict,返回 {"n": N, "mean": mean, "mad": MAD}。第一遍:mean = sum(values) / N。第二遍:MAD = sum(|x - mean| for x in values) / N。因为输入是具体的列表,O(N) 内存可接受——直接对列表迭代两次,只需两个标量累加器。
举例:solution([1.0, 2.0, 3.0, 4.0, 5.0]) 返回 {"n": 5, "mean": 3.0, "mad": 1.2}:均值 15/5 = 3.0,绝对偏差 [2, 1, 0, 1, 2],平均 6/5 = 1.2。再看一例:solution([7.0, 7.0, 7.0, 7.0]) 返回 {"n": 4, "mean": 7.0, "mad": 0.0}——所有偏差为 0。第三例:solution([]) 按约定返回 {"n": 0, "mean": 0.0, "mad": 0.0}。
实践背景
均值与平均绝对偏差是任何时序监控仪表盘上的主力组合:延迟、成交率、单笔 P&L、滑点。它们计算便宜、读起来直观,而且单位正确(MAD 与原始数据同单位,这一点优于方差)。均值版 MAD 是与算术均值配套的通用离散度估计量——它是标准差的 L1 类比,在肥尾不是主要威胁、且希望度量保持原始单位(不取平方根)时,优先于标准差。它与 coding-mad-zscore-cross-section 中用于 1.4826 * MAD 重缩放的中位数版 MAD 不是同一个东西:那个版本是与中位数配套的稳健离散度估计量,一旦样本里出现离群值,两个公式给出的结果就会显著分叉。选哪一个是建模决策,不是编码决策——下面的实现是有意为之的均值版。
约束条件
- 0 ≤ `N = len(values)` ≤ 10^5
- 每个元素都是有限浮点数
- `N == 0` → `{"n": 0, "mean": 0.0, "mad": 0.0}`
- `N == 1` → `{"n": 1, "mean": values[0], "mad": 0.0}`
- 输出键恰好为 `n`、`mean`、`mad`;类型分别是 `int`、`float`、`float`
- 浮点比较容差 `rel_tol = 1e-9`、`abs_tol = 1e-12`
样例
Case 1 · statement-example: 1..5 has mean 3 and mean-MAD 1.2
输入: [[1,2,3,4,5]]
期望: {"n":5,"mean":3,"mad":1.2}
均值 = 15/5 = 3;绝对偏差 [2,1,0,1,2],其均值 6/5 = 1.2 即均值-MAD。
Case 2 · statement-example: all-equal gives MAD = 0
输入: [[7,7,7,7]]
期望: {"n":4,"mean":7,"mad":0}
所有元素相等,均值即元素值,所有偏差均为 0,故 MAD = 0。
Case 3 · statement-example: empty input returns zeros
输入: [[]]
期望: {"n":0,"mean":0,"mad":0}
空输入按约定返回 n=0、mean=0.0、mad=0.0。
Case 4 · boundary: single element has MAD = 0
输入: [[3.5]]
期望: {"n":1,"mean":3.5,"mad":0}
N=1 时均值即该元素值,与自身的绝对偏差为 0,故 MAD = 0。
Case 5 · typical: symmetric mix around zero
输入: [[-2,-1,0,1,2]]
期望: {"n":5,"mean":0,"mad":1.2}
对称样本,均值为 0;偏差等于绝对值 [2,1,0,1,2],平均得 1.2。
Case 6 · adversarial: single outlier inflates mean and mean-based MAD
输入: [[1,2,3,4,1000]]
期望: {"n":5,"mean":202,"mad":319.2}
均值-MAD 与均值一样对离群值敏感:一个 1000 把均值抬到 202,所有偏差都被放大,MAD = 319.2。这正是题面里强调的 mean-based 与 median-based 的差别——median-based MAD 在同一输入上几乎不动。
最近提交
还没有提交记录。
编码区
实现 solution(...)。本地运行当前支持 Python 可见样例;服务端提交会运行可见样例和隐藏测试。
默认展示公开样例。点击「运行样例」后会在这里显示实际输出;点击「提交评测」会进入隐藏测试。
Case 1 · statement-example: 1..5 has mean 3 and mean-MAD 1.2
输入: [[1,2,3,4,5]]
期望: {"n":5,"mean":3,"mad":1.2}
均值 = 15/5 = 3;绝对偏差 [2,1,0,1,2],其均值 6/5 = 1.2 即均值-MAD。
Case 2 · statement-example: all-equal gives MAD = 0
输入: [[7,7,7,7]]
期望: {"n":4,"mean":7,"mad":0}
所有元素相等,均值即元素值,所有偏差均为 0,故 MAD = 0。
Case 3 · statement-example: empty input returns zeros
输入: [[]]
期望: {"n":0,"mean":0,"mad":0}
空输入按约定返回 n=0、mean=0.0、mad=0.0。
Case 4 · boundary: single element has MAD = 0
输入: [[3.5]]
期望: {"n":1,"mean":3.5,"mad":0}
N=1 时均值即该元素值,与自身的绝对偏差为 0,故 MAD = 0。
Case 5 · typical: symmetric mix around zero
输入: [[-2,-1,0,1,2]]
期望: {"n":5,"mean":0,"mad":1.2}
对称样本,均值为 0;偏差等于绝对值 [2,1,0,1,2],平均得 1.2。
Case 6 · adversarial: single outlier inflates mean and mean-based MAD
输入: [[1,2,3,4,1000]]
期望: {"n":5,"mean":202,"mad":319.2}
均值-MAD 与均值一样对离群值敏感:一个 1000 把均值抬到 202,所有偏差都被放大,MAD = 319.2。这正是题面里强调的 mean-based 与 median-based 的差别——median-based MAD 在同一输入上几乎不动。