首页 文章 精选 留言 我的

精选列表

搜索[chart],共1086篇文章
优秀的个人博客,低调大师

AI 预测可视化平台 | 预测 vs 实际对比分析:Waterfall Chart 与偏差分解

# 引言 计划员每天真正要处理的问题是:**这 240 件的偏差,是从哪一天开始失控的?** 预测曲线和实际曲线并排看,只能看到"差了很多";把偏差按时间、特征、误差类型逐层拆开,才能定位"是节前效应没学到位,还是促销假设被推翻"。 这就是偏差分解(Bias Decomposition)要解决的问题。它的核心不是画一张好看的瀑布图,而是**把总偏差变成一组可归因、可排序、可下钻的组成部分**。本文将拆解三种偏差视角(时间累积、特征贡献、误差类型),给出 Waterfall 的完整实现、交互联动方案与性能取舍。 # 一、先统一口径:偏差是什么、单位是什么 偏差的定义不统一,是预测平台最容易吵起来的地方。建议在团队内锁死两套并行口径: |口径|公式|用途| | --- | --- | --- | |绝对偏差|`actual - yhat`|驱动补货决策,有量纲| |相对偏差|`(actual - yhat) / actual`|跨 SKU 排名,无量纲| |累积偏差|`Σ(actual - yhat)`|判断库存水位净漂移方向| ![](https://developer.qcloudimg.com/http-save/audit-10133498/0d6b7ac2531fff287192843c203b9c44.png) **解析**:同一份偏差数据要服务三种推理。按绝对值排序得到"最需要处理的日期",这是工单入口;分组聚合得到"哪个维度在系统性偏置",这是模型改进方向;累积和则直接对应库存——**累积偏差就是库存水位相对计划净漂移了多少**,计划员比任何人都关心这条线。 数据契约建议后端一次算好、前端不再重算: ```javascript { "sku": "SKU-1002331", "baseline": 1200, "totalActual": 128400, "totalYhat": 126980, "netBias": 1420, "mape": 0.142, "wmape": 0.118, "breakdown": { "byFeature": [ { "f": "promo_intensity", "contribution": 860, "share": 0.61 }, { "f": "price", "contribution": -320, "share": -0.23 }, { "f": "holiday", "contribution": 510, "share": 0.36 } ], "byErrorType": [ { "type": "bias", "value": 1180 }, { "type": "variance", "value": 240 } ], "topDays": [ { "ds": "2026-11-11", "actual": 1520, "yhat": 1370, "deviation": 150, "absDev": 150, "relDev": 0.099 } ] } } ``` **解析**:`netBias` 是总偏差的符号化表达,正值=整体低估。`share` 是各因素对总偏差的贡献占比,可正可负,**三个 share 加总为 1 的约束必须校验**,否则前端会画出自相矛盾的图。`byErrorType` 把偏差拆成偏置与方差两部分,这是诊断"模型是不准还是不稳"的依据。 --- # 二、视图一:时间累积 Waterfall 这是主视图。它把每一天的偏差按日期顺序铺开,累计到终点,一眼看出"偏差是慢慢攒出来的,还是某几天集中爆发"。 ![](https://developer.qcloudimg.com/http-save/audit-10133498/486292ff04df45b224d2214a3e32c42a.png) **解析**:框选触发范围筛选、点击某天触发单点归因,是两种不同语义的动作,**必须分治**。框选用防抖(100ms),点击即时响应。累计净值线叠加在瀑布上是关键设计——它能回答"到第几天为止,库存已经偏了多少"。 ```javascript export function DeviationWaterfall({ series, selectedRange }) { const slice = selectedRange ? series.filter(d => d.ds >= selectedRange[0] && d.ds Math.abs(b.deviation) - Math.abs(a.deviation)) let acc = 0 const maxAbs = Math.max(...sorted.map(d => Math.abs(d.deviation))) return ( 区间累计偏差 {acc} 件 日均偏差 {(acc / sorted.length).toFixed(1)} 件 {/* 零轴基准线 */} {sorted.map(d => { const positive = d.deviation >= 0 const h = (Math.abs(d.deviation) / maxAbs) * 100 acc += d.deviation return ( {d.ds} {d.deviation} {/* 悬停浮层:关联 SHAP 与误差 */} 实际 {d.actual} / 预测 {d.yhat} 相对偏差 {(d.relDev * 100).toFixed(1)}% ) })} 累计净值 0 ? 'text-rose-600' : 'text-emerald-600'}>{acc} 件 ) } ``` **解析**:零轴用虚线画在正中,正负偏差分别向上向下延伸,**方向一眼可辨**。柱高按区间内最大绝对偏差做归一,保证最严重的那几天永远是满高,视觉权重正确。悬停浮层把 SHAP 归因和误差口径关联起来,避免用户在两张图之间来回对照。`acc` 累加器在渲染末尾输出累计净值,直接对应库存漂移。 --- # 三、视图二:分解条形图(特征贡献 vs 误差类型) 瀑布讲"什么时候",分解图讲"为什么"。前者找日期,后者找维度,两者是同一份偏差数据的两个投影。 ![](https://developer.qcloudimg.com/http-save/audit-10133498/66a8ce8b34114ba71720eb5782ee691c.png) **解析**:两种分解回答不同的问题。特征贡献告诉你"促销强度贡献了 61% 的正偏差",对应动作是**回去看特征工程**;误差类型告诉你"方差占 240 件",对应动作是**集成或加样本**,而不是调参。**不区分这两类,整改方向一定选错。** ```javascript export function FeatureBiasBreakdown({ byFeature }) { const sorted = [...byFeature].sort((a, b) => Math.abs(b.share) - Math.abs(a.share)) const maxShare = Math.max(...sorted.map(d => Math.abs(d.share))) return ( {sorted.map(d => { const positive = d.share >= 0 return ( {d.f} {d.contribution} 件 / {Math.round(d.share * 100)}% ) })} ) } ``` **解析**:正负贡献从中间向两侧延伸,视觉上是"围绕零轴对称展开"的双向条形图。**条形最长不超过 50%**,因为左右各有半轴,这样最极端的项也不会溢出。悬停显示贡献件数与占比两种口径,件数用于补货判断、占比用于横向对比。 误差类型的堆叠方案则不同,它必须展示"偏置与方差各自多大": ```javascript export function ErrorTypeBreakdown({ byErrorType }) { const bias = byErrorType.find(t => t.type === 'bias')?.value ?? 0 const variance = byErrorType.find(t => t.type === 'variance')?.value ?? 0 const total = bias + variance || 1 return ( {Math.round(bias / total * 100)}% 偏置 {Math.round(variance / total * 100)}% 方差 {bias > variance ? '偏置主导:模型系统性偏离,优先校正基线或加特征' : '方差主导:模型不稳定,优先集成或扩充样本'} ) } ``` **解析**:堆叠条的宽度即占比,文案随主导类型动态切换——**视图必须给出结论,而不是只给数据**。这是偏差分解与单纯图表的本质区别:每张图都要回答"所以呢"。 --- # 四、视图三:对比双线 + 区间覆盖 预测值与实际值并排,看似简单,其实有三个必须处理的细节:**历史与未来要区分线型,区间带是否覆盖实际值要可视化,区间外点位要主动标红。** ![](https://developer.qcloudimg.com/http-save/audit-10133498/eda554d32a85094207fee1a7756bf6b4.png) **解析**:柱状代表实际值、折线代表预测值,是双线对比的经典编码。**柱状给实际、折线给预测**,是因为实际是"已发生的量"、预测是"估计的量",两种本体应编码为两种视觉通道。图中 11 月实际远高于预测,就是典型的区间外异常点,前端应自动标红并加入异常清单。 ```javascript export function ForecastActualChart({ series, onSelect }) { const actuals = series.filter(d => d.actual != null) const forecasts = series return ( {actuals.map(d => { const outside = d.actual > d.yhatUpper || d.actual onSelect(d)} className={`group relative flex-1 ${outside ? 'bg-rose-500' : 'bg-gray-700'}`} style={{ height: `${h}%` }} title={d.ds}> {outside && ( ● )} ) })} {/* 预测折线叠加 */} { const x = (i / (forecasts.length - 1)) * 100 const y = 100 - (d.yhat / 2600) * 100 return `${x},${y}` }).join(' ')} fill="none" stroke="#6366f1" strokeWidth="2" strokeDasharray="6 3" /> ) } ``` **解析**:`outside` 判定是异常检测的第一道闸门,直接复用上一章的标注入口。柱顶的红色圆点是"区间外"的强信号,计划员扫一眼就能定位异常日。**SVG 折线用绝对定位叠在柱图上、并设为 **`pointer-events-none`,保证柱子的点击事件不被遮挡。预测期(无实际值)不渲染柱子,自然形成视觉空白,暗示"此处尚未发生"。 --- # 五、交互联动:从日期到归因的闭环 三个视图必须共享同一个筛选状态,才能构成可推理的工作台: ![](https://developer.qcloudimg.com/http-save/audit-10133498/5c12ff5b05ef81f869528ef73a0f5e60.png) **解析**:框选是筛选、点击是查询,两种动作语义不同,绝不能用同一套状态。**框选要节流**(100ms 防抖),否则每帧都重算分箱会拖死主线程;**点击只加载单点详情**,不应触发全局重算。最终落到 `I` 是整张工作台的价值所在:把"发现了什么偏差"翻译成"该做什么动作"。 范围聚合的纯函数实现: ```javascript // 按选定范围聚合偏差分解 export function aggregateByRange(series, range, groupKey) { const slice = range ? series.filter(d => d.ds >= range[0] && d.ds { const key = groupKey(d) if (!groups.has(key)) groups.set(key, { key, sum: 0, count: 0, absSum: 0 }) const g = groups.get(key) g.sum += d.deviation g.absSum += Math.abs(d.deviation) g.count += 1 }) return [...groups.values()] .map(g => ({ ...g, avg: g.sum / g.count, share: g.sum / slice.reduce((a, b) => a + b.deviation, 0) })) .sort((a, b) => Math.abs(b.sum) - Math.abs(a.sum)) } ``` **解析**:`groupKey` 是可注入的分组函数(按周、按月、按品类、按特征),**这让同一套聚合逻辑复用四种维度**,是减少代码重复的关键。分母用 `slice.reduce` 实时算总偏差,避免缓存值失效导致 `share` 失真。返回结果按绝对偏差降序,保证视图始终从最严重处读起。 # 结语 偏差分解不是给预测加一张图表,而是把"不准"这件事拆成可处理的工单。本文给出了三条互相咬合的推理路径:**时间瀑布图回答偏差是何时累积的,特征贡献图回答它从哪个维度来,误差类型分解则判断该重训还是该降方差。** 读到这里你应当带走四点: - **绝对偏差、相对偏差、累积偏差三种口径必须并存,分别服务补货、排名与库存水位判断;** - **特征贡献与误差类型要分开呈现,否则整改方向必然选错;** - **瀑布图的正负双向编码和零轴基准线是方向可读性的关键,且必须把累计净值落到库存漂移上;** - **20k 点位以上的聚合必须进 Worker 或服务端预计算。**

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册