
先说明一个很多人在看天气模型时容易忽略的事实模型输出的地图再漂亮也只代表“依据某个数值方案计算出来的预测”它到底准不准要等预报时间真正过去之后拿实况回来比才知道。这个项目做的正是这件事——把各家天气模型的历史预报和实况做对比按误差大小滚动排出名次让大家不用靠印象或者厂商宣传判断“哪个天气模型更靠谱”。从工程角度看它不是一个普通的天气展示站而是一条完整的数据管线预报采集、实况对齐、误差计算、滚动排名。适合看这篇内容的人主要有三类想自己做模型评估的开发者、关注数值天气预报验证方法的爱好者以及需要在业务里搭建同类评估系统的数据工程师。如果让我拉一遍这类项目的核心工作我会分成四块搞清评估口径、搭数据管线、算误差做排名、把结果解释得让人不误读。下面按这个顺序拆。1. 天气模型排名到底在排什么1.1 评估对象不是“模型”本身而是某次预报在某天的表现数值天气预报模型比如大家经常听到的 ECMWF、GFS、ICON、UKMO每天会在固定时次发布起报的预报场。一次完整评估要同时锁定四个维度起报时间、预报时效、变量、区域。举个例子“2025年1月1日00时起报的GFS72小时时效预测2米气温在中国东部地区的平均绝对误差是多少”。只有把评估对象切到这种颗粒度排名才有可比性。很多人第一次做会犯一个错误直接拿“今天模型的预报结论”和“今天的实况”去比中间完全忽略起报时间和时效。比如早上看到今天最高温预报等到晚上拿实况一比发现差了3度。这其实是一个跨了十几个小时的混合样本不能说明模型好坏只能说明你比较的方式不对。1.2 为什么不能直接拿几家模型的地图放一起比把 ECMWF 和 GFS 的预报温度图并排放肉眼觉得“这张更接近实况”这种比较最多算感受不能当结论。要客观排名前提是把各家输出放到同一个坐标系里。这里有四个绕不开的问题分辨率不同。有的模型是 0.25 度格点有的是 0.5 度有的区域模式只有几公里。必须插值到统一网格或统一站点排名的误差计算才有共同基准。起报时次不同。各家模型发布频率不一样GFS 这类全球模式通常一天多次起报ECMWF、ICON 也有各自的节奏。比较时要按同一有效时间对齐而不是简单按同一起报时间硬比。变量定义和单位不同。有的模型直接给地面气温有的给近地面层气温单位可能是摄氏度也可能是开尔文降水可能是累计量也可能是小时率。转换不统一误差公式再严谨也白搭。模型版本会变。同一个模型系统上游更新了物理参数或分辨率之后历史预报的风格可能明显变化。如果不记录版本排名里混着新旧模型的成绩解释起来会非常困难。这四点不是细节问题是做整个评估系统的前置约束。我一般会先写一张“模型元信息表”把每个模型的网格、变量名、单位、发布周期、归档路径都登记进去后面所有计算都依赖这张表。1.3 核心指标怎么选排名需要误差指标。指标不是越多越好要跟评估对象匹配。常见的选择如下指标适用场景判断方式MAE平均绝对误差气温、风等连续变量越小越好单位直观RMSE均方根误差需要惩罚大偏差时对大误差更敏感Bias平均偏差判断模型是否有系统性偏冷偏暖越接近 0 越好正负说明偏差方向距平相关系数大尺度气压场形势对比越接近 1 越好TS 评分 / 命中率降水落区或是否超过阈值兼顾漏报和空报CRPS / Brier 分数集合预报概率输出越小越好温度这种变量用 MAE 和 Bias 就足够解释。降水必须用事件类指标否则全是接近 0 的小误差看不出模型到底是漏报了还是空报了。如果只是做城市气温排名一张 MAE 表最直观如果要做完整模型评估建议至少保留 MAE、RMSE、Bias、降水命中率四类指标。2. 数据管线是排名的地基这一节最不性感但最容易决定项目生死。排名算法再简单只要数据进不来或者对不齐结果就是一堆无效数字。2.1 预报数据从哪里来各家模型都有公开的数据渠道比如 GFS 的公开下载服务、ECMWF 的开放数据、DWD 的 ICON 开放数据、UKMO 的部分开放数据。具体细节我不在这里列因为访问方式和访问政策会随机构更新而变做的时候一定要按当时官方文档确认。更关键的是你要的不是某一天的预报而是连续几个月甚至几年的历史预报归档。这意味着两种做法自己从今天开始持续抓取慢慢积累。从已有归档库或第三方数据集回补历史。实操里回补历史比新增采集麻烦很多。如果从零开始做我更建议第一版就把“每天自动归档原始文件”这个任务加上不要等排名系统做完了再回头补数据。数据没有积累后面所有统计都缺样本。2.2 实况数据从哪里来实况数据有两个层级站点观测。气象站上报的实测气温、风速、降水。优点是真实缺点是覆盖稀疏很多区域没有站。网格分析场。比如再分析资料或业务分析场是全球网格化的“最接近实况的估计”。优点是可以和预报网格直接对比缺点是我们等于拿另一个模型的输出结果来验证模型。具体怎么选取决于排名粒度。如果只评测北京、上海、广州这些城市的气温排名直接拉站点观测最清楚如果评整个区域的气温场用分析场更合适。很多项目会混合使用区域准确率用站点大尺度形势用分析场。2.3 时空对齐是最大的坑我见过不少系统误差公式完全没问题最后结果却很奇怪问题基本都出在“对齐”上。对齐分三层。第一层是时间对齐。天气预报里有一个概念叫有效时间valid time它等于起报时间加上预报时效。比如 1 日 00 时起报的 72 小时预报有效时间就是 1 日往后推 72 小时的位置。比较时要按有效时间把预报和实况配成一对而不是按起报时间。第二层是空间对齐。要把模型原始网格插值到比较网格或站点位置。温度场用双线性插值通常够了降水场因为空间变率大直接双线性插值容易把单点强降水抹平最好先做邻域平均或区域平均再比。第三层是序列对齐。每个模型的起报次数、发布时间和延迟不一样。写任务时要处理“今天要结算哪些有效时间”这个逻辑别让数据还没发布完就进入评分。宁可晚两个小时出分也不要拿到不完整的预报就开始算。3. 落地流程从采集到排名把整个流程拆成几步每一步都有明确的输入输出这样出了问题也能快速定位。3.1 先做原始预报归档原则很简单所有拿到的原始预报文件先原样存下来再去做提取和转换。不要只保存抽出来的“北京气温预报值”因为一旦后面发现处理逻辑有 bug或者想换一个新指标原始文件还在就能重算。目录结构可以按模型、起报日期、起报时次来组织forecast_archive/ gfs/ 2025-01-01/ 00/ f024.grib2 f072.grib2 icon/ 2025-01-01/ 00/ f024.grib2 f072.grib2这只是一种示例实际命名可以按模型特性调整但原则是路径里必须能反推出模型、起报时间和时效。避免把所有预报塞到一个大文件里否则后面分类、重试、补数据都非常难受。3.2 逐时效计算误差计算按“一次预报记录”为单位流程大致是这样的定时任务检查有哪些新预报文件 解析 grib2 或 netCDF提取目标变量 把网格预报插值到统一站点或统一网格 按有效时间匹配实况 计算 MAE、RMSE、Bias 等指标 写入按模型、日期、时效、变量、指标组织的数据表用伪代码表达就是这样# 示意代码具体库和 API 以你的数据源为准 for model in [gfs, icon, ecmwf]: for init in get_available_inits(model, today): for lead in [24, 48, 72, 120, 168]: fc load_forecast(model, init, lead) # 读取原始预报 valid_time init timedelta(hourslead) # 计算有效时间 obs load_observation(valid_time) # 读取实况 error compute_metrics(fc, obs) # 插值后计算误差 save_scores(model, init, lead, valid_time, error)写这一层的时候计算逻辑要尽量做到“幂等”同一条预报记录重跑多次结果应该完全一致。这样后面修复 bug 或者换实况源时可以整批重算不会污染排名。3.3 滚动汇总排名单次误差不是排名依据。排名要用统计窗口汇总常见的是“近 30 天”“近 90 天”“近一年”。为什么要滚动因为模型会上游更新季节也在变固定截断的年度排名会越来越陈旧。滚动窗口能让排名反映模型最近的表现。实现上要注意两个细节样本量要标注。某模型最近 90 天只有 40 个有效样本另一个有 90 个样本直接比 MAE 对样本少的那家不公正。分季节或分区域汇总。有的模型夏季表现好有的冬季表现好有的在温带误差小在热带反而差。只出一个总榜会掩盖这些差异。3.4 展示层做什么最基础的展示就是一张排名表模型、变量、时效、区域、样本数、MAE、RMSE、Bias、排名。再加一个误差随时间变化的折线图能直观看到谁最近在变好。筛选条件至少要有变量、区域、预报时效、统计窗口。不要一开始就做复杂的交互地图。先让排名表能正确筛、正确排再考虑可视化。很多项目死在第一步就疯狂堆图表最后数据质量没跟上页面再漂亮也撑不住。4. 排名结果怎么解读榜单不代表每次都对这部分容易被低估。做了排名系统之后最难的不是算出名次而是让读者正确理解名次。4.1 排名表有自己的适用边界总排名只代表“统计平均意义上的胜负”不代表每次预报都赢。几个重要的分层维度和隐含边界值得单独说明短时效和长时效要分开看。有的模型在 72 小时内和对手接近但到了 168 小时差距才明显拉开。区域差异比整体差异更值得关注。一个模型全球总误差低但在你所在城市可能不是最好。不同变量的排名不能合并。气温的误差小不代表降水的落区预报就准。降水误差不能只看总量。还要看落区、强度、极值总量接近可能是很多位置误差互相抵消的结果。4.2 领先不等于永远正确需要反复强调一个统计常识排名第一名只意味着在已统计样本里平均误差最小不等于下一次预报一定最准。天气系统的演变本身就是混沌过程个别事件里排名靠后的模型反而更贴近实况是完全正常的。所以展示侧不要做“今天哪个模型赢了”这种单日冠军榜。单日对比的样本只有一两个噪声极大容易让读者产生错误判断。更合理的做法是给出滚动 30 天或 90 天的误差曲线让趋势说话。4.3 对外公布时需要交代清楚口径如果这个系统是公开站点至少要交代以下内容用的是哪段统计窗口有效样本数量实况数据来源插值方式是否排除了模型更新前后的版本差异评分公式的具体定义如果这些不写读者没办法判断排名是否可信。更稳妥的做法是在页面上加一个“口径说明”区块把评分逻辑讲清楚而不是让用户自己去猜。5. 常见问题和排查链路真正做过这类系统的人大概率都踩过下面这些坑。每条都给出对应的排查顺序。5.1 典型异常现象和优先排查方向现象最可能原因下一步确认某模型最近几天没有新排名数据未归档或抓取任务中断看抓取日志和文件列表某天所有模型误差同时突然暴涨实况数据源异常或有效时间对齐错误检查实况文件和 valid time单个模型误差突然变得特别好可能采样区域不对或样本数太少确认插值范围和样本量降水评分长期接近 0降水指标选择错误换成阈值类事件指标排名经常倒挂样本量太少或统计窗口太短拉长窗口看折线趋势5.2 通用排查顺序遇到异常不要急着改参数。按这个顺序查先看数据层。原始文件有没有缺、路径是否规范、解析是否报错。再看对齐层。有效时间是否算对、插值网格是否一致、单位是否统一。再看计算层。误差公式实现是否正确、有没有用错变量。再看统计层。样本量、滚动窗口、有没有把不同模型版本混在一起。最后才是排名算法本身。大多数“排名诡异”的问题最后都出在前三层而不是评分公式。先看数据再看对齐再改参数这个顺序能省下大量排查时间。6. 做成公开服务还需要考虑的事情6.1 存储与算力网格预报文件不小持续积累几年就是非常大的体量。个人项目没必要全量存所有变量可以在归档原始 grib 文件后只抽取目标变量保存成轻量格式比如 NetCDF 或压缩子集。计算量上单台机器每天算几个模型的几十个时效完全够用主要瓶颈在网络下载带宽和磁盘 IO不在 CPU。6.2 版本管理和可复现性模型上游几乎每年都会有更新。建议每次接入新版本时单独记录版本名和生效日期。排名系统内部要能区分“旧版预报”和“新版预报”否则用户问“为什么最近突然变准了”你只能猜是模型更新还是季节变化。同时把整个评分流程固化成带参数的脚本或任务输入是数据日期范围输出是评分表。这样要做复盘、修 bug、或者换实况源重算时可以一键复现不会因为手动操作留下不可复现的结果。6.3 这个项目适合做到什么程度如果只是想验证“GFS 和 ECMWF 哪个在本地更靠谱”不需要做全球排名。只需要抓两家的数据算两个城市的气温 MAE两三天就能跑通。如果想做一个面向公众的模型排名站点重点不是炫技而是把口径写清楚、把数据更新维护好。公开数据源的访问政策、更新延迟、字段变化都要持续关注这部分最耗时也最容易被低估。我个人会把项目控制在一套“数据采集 滚动评分 简单榜单”的闭环里先把一个变量、一个区域、一个时效做扎实再横向扩展。功能列表多不一定是好事能让人看完榜单之后看懂“为什么这么排”才是这类项目真正的价值。