气温是任何一款天气 APP 都要首要展示的信息,它的重要程度不言而喻。通常发生一次气温的异常显示,都会给 APP 带来严重的负面影响和经济损失。这么重要的数据,为什么还会时不时发生异常?对它做质量控制的难点在哪里?我们应该如何保证它的可靠性?那么今天我们就带着这些问题一起来聊一聊气温质量控制的话题。

气温质控的现状及难点

首先我们必须了解一个事实,那就是气象数据的生产和传输的过程,通常是一个很长的流水线。我们在 APP 上看到的最终天气数据,一般是经过了多次的传递和加工的过程,当其中某一个环节出现了异常值以后,如何能够快速地识别出来并采取相应的拦截行动(比如删除、替换等)以减少损失,就是天气数据质量控制流程所需要做的事情。

目前行业内在工程上对气温的异常识别的主流方法还比较原始,可以称之为单一阈值过滤,也就是简单根据变量的特点人为设置一个固定的阈值,例如根据一些先验知识,假设我们认为中国地区的气温都应该在 -55°C 到 50°C 之间,然后在流水线代码里加入一个气温的判断逻辑,对于超过该数据范围的进行修改。

这种直接阈值过滤的方法是一种非常简单直观的方法,事实上它对于像相对湿度这一类有明确硬性取值范围(0% ~ 100%)的要素来说是非常实用的,但是对于像气温这种无硬性范围的要素,这种方法就会有一些问题,举例来说,前面提到的 -55°C 和 50°C 在我国是一种相对极端的情况,对于超出该范围的我们可以比较有把握地认为气温是出了问题的。但是如果数据中出现一条没有超出该界限的异常值,这种方法就爱莫能助了。比如海南省海口市在 8 月出现了-25°C 这种值,它并没有超出 -55°C 和 50°C 的界限,但是很明显它是异常的,类似的还可以举例黑龙江漠河在 12 月出现 45°C 的气温。

如果阈值范围非常的宽,那就会很容易遇到上述的问题,从而让质量控制形同虚设。那我们可以把阈值范围收得很窄吗?答案是不可以,因为哪怕只是中国地区来说,全国全年范围内真实气温的界限值也是非常宽的,根据一些资料显示,我国的最低气温记录是-53°C,最高气温记录是 49°C。而如果从全世界的角度来看,这个范围只会更宽。所以如果将气温的范围收窄,那么势必就会将一些真实的极端天气排除在外。事实上,在《中华人民共和国气象行业标准:气象观测资料质量控制 地面》(QX/T 118-2020)中,对地面气温界限值的规定更宽,为 -80°C ~ 60°C。

众所周知,气温带有很明显的季节和地理变化特征,在同一时间的不同地区或者同一地区的不同时间都会有不同的合理阈值范围,而且这个范围的跨度可能还很大,显然直接用一个单一的阈值是无法有效识别天气数据的异常的。这也是当前天气数据质量控制所遇到的一个难点。如果想要克服这种粗犷的质控方式,用相对精细化的方案去识别异常数据,就必须要将时间和空间对天气要素的影响考虑在内,在不同的时间和空间下给出特定的阈值范围。如果还是用人工手动的方式去配置一个阈值列表,那么从可操作性上来说就不太现实了。

当然除了工程上的实践以外,学术界在气温质量控制上也提出过一些方案设计,例如基于空间和时间一致性的拟合分析或者聚类分析,但由于此类方案倾向于过度设计,以至于在真实工程化实践中往往难以实施或者性能不足,目前尚未了解到有基于此类方案大规模工程化实现并运行良好的先例。

解决思路

在尝试解决气温阈值随时空变化的问题时,我们会优先考虑借助于统计学的方案。机器学习是一种可选的方向,但成本较高。而我们还可以选择用一些更经济实惠且性能优秀的统计质控方案,那就是概率分布函数。

根据一些资料显示,如果将某个固定地区一年中所有时间的气温数据聚集在一起做概率分布分析,最终气温将会是一个双峰的分布。这是由于高低温季节长度不均等而导致的,如果我们在历史观测数据的时间序列上借助一些重采样的技巧,可以剔除掉季节对气温概率分布的特殊影响,让它重新符合正态分布。

根据正态分布的理论,我们可以计算历史观测数据的统计均值和标准差,再根据待检查数据与均值(数学期望)之间的偏差及其所落的 ± 标准差区间来判断数据是否属于离群点及其离群程度,当其离群程度超过一定的容忍度时,将被判定为异常值。

数据处理过程

历史数据集及预处理

为了实现基于历史气象数据的概率统计,我们收集了全国 2000 多个国家级气象站(包括台湾地区的 35 个有人观测站)从 2010 年到 2020 年十年间的逐小时气温数据和相应时间的中国区 ERA5 格点数据。

在选择长周期历史格点观测数据时,我们首先考虑的数据集是 ERA5 再分析数据,因为 ERA5 是目前公开的高质量长周期再分析数据中唯一一个时间分辨率能达到小时级的。但是仅有 ERA5 数据还是不够,因为经过我们的测评,ERA5 在中国区的数据与气真实象观测站的观测数据还是有明显的差距,如果直接使用 ERA5 数据,那么最终检验结果会有较为明显的失真,并不是最优的解决方案,因此需要使用气象观测站的数据对其进行融合订正。

我们的融合订正方案是:利用高斯径向插值方法将站点气温数据插值到与 ERA5 相同的格点坐标系中,再使用相同的插值方法将 0-1 的站点权重插值到格点坐标系中,令有观测站的坐标的测站初始权重为 1,经过高斯插值后测站权重从测站中心点向周围扩散递减,从而得到格点的融合权重矩阵,最后结合站点插值后的矩阵、权重矩阵及 ERA5 矩阵进行加权平均计算,从而融合两套数据作为更高质量的格点版历史观测数据集供后续的采样和统计计算。

统计采样方案

由于我们拿到的历史观测数据只有 10 年,如果把这 10 年中每个小时的数据合并采样为 1 组,那么每个小时的统计样本仅为 10 个,显然 10 个样本是无法获得具有统计学意义的结论的,因此我们需要扩充样本数量,同时又要保证样本集能代表该小时点的概率分布。这需要一些采样技巧,在这里我们将使用一种略显复杂的采样方法以支撑后续的统计计算。

首先从时间维度上,我们需要做两层跨周期的时间分组平滑采样,每次采样需要先采集目标时间点及前后两个相邻小时的时间点作为一个小时级采样组,再用相同的方法在目标采样点所在天的前后 3 天范围内采集同周期样本作为天级别采样组,最后再以相同的方法纵跨 10 年采集所有年份中对应天和小时的样本合并作为代表该目标时间的跨 10 年的历史统计样本集。在完成时间采样之后,为了缓解由于地形等因素造成气温梯度剧烈变化进而导致样本不稳定的问题,我们还会在空间上进行一次平滑采样,也就是将空间中每一个点与周围相邻的 8 个点采样为同一组,以提高后续拟合结果的稳定性。

以 6 月 15 日 12 时为例,我们将该时间点视为目标采样点,将 6 月 15 日 12 时前后两个小时并入小时级采样组,即 6 月 15 日 11 时、6 月 15 日 12 时、6 月 15 日 13 时作为小时级采样组(3 个)。然后我们开始进行跨天采样,向前向后各取 3 天对应的小时级采样组并入天级采样组,即 6 月 12 日 11 时、6 月 12 日 12 时、6 月 12 日 13 时、6 月 13 日 11 时、6 月 13 日 12 时、6 月 13 日 13 时 …(以此类推)… 6 月 17 日 11 时、6 月 17 日 12 时、6 月 17 日 13 时、6 月 18 日 11 时、6 月 18 日 12 时、6 月 18 日 13 时(3 _ 7 天 = 21 个)。最后以类似的方法,将这些时间片段扩展到从 2010 至 2020 年的范围中(21 _ 10 年 = 210 个)。这样的采样操作以后,目标采样点既得到了足以获得统计结论的样本数量,又避免了由于季节特征影响概率分布的问题,同时还尽量平滑了短时极端天气带来的统计失真问题。此外,单个采样点在时间维度上采集的 210 个样本的基础上,我们再加上空间的临近平滑采样的 8 个样本,样本数将进一步扩大 9 倍(210 * 9 = 1890 个),也就是单一时间单一空间点将获得 1890 个样本用于概率分布拟合,这样的样本集规模足以拟合出具有统计学意义的概率分布了。

计算统计参量

根据前面提到解决思路,我们的统计目标是构建一个正态分布的概率密度函数,而根据正态分布的定义,我们只需要计算出样本集的均值和标准差即可。因此,我们在前面提到的复杂采样的基础上,可以很方便的计算出样本矩阵的均值和标准差矩阵,最终我们得到一套包含 8760 个时间点(1 个平年中的小时数量)的气温的均值和标准差格点数据集。

气温质控系统

在得到了均值和标准差矩阵以后,我们就可以构建一套气温质控系统了。为了让这套质控系统更易于使用,我们定下几个预定目标:

  1. 使用时与编程语言无关,以 Restful API 的形式实现。

  2. 支持按经纬度点和时间对气象要素进行精细化判定,给出明确的 True/False 判断。

  3. 支持以不同容忍度进行查询,宽严程度由使用者自定义调节。

基于该目标,我们构建了一个纯后端的 API 系统,系统可以根据用户传入的经纬度坐标和时间信息查找最近格点对应时间的参数数据,并根据用户传入的容忍度参数来判断待检验值是否处于可容忍的区间范围内,并明确返回是否可接受的布尔值(True/False),同时给出历史均值及所处容忍度下的界限值。

让我们看一下这套质控系统是如何使用的。

质控系统基于 HTTP GET 方法,本地部署以后对于基于经纬度查询气温合理性检查的路由是:

http://localhost:8000/v1/rationality/latlon/tmp/

调用时需要传入的参数包括:

参数含义是否必须默认值
lon经度-
lat纬度-
value待检验值-
timestampUnix 时间戳-
tol容忍度0.99999

我们先以北京的坐标(116.400244,39.912943)为例,检查一下 26°C 这个气温在北京时间 2023 年 10 与 10 日 08 点是否合理。

curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=116.400244&lat=39.912943&value=26&timestamp=1696896000"

返回的结果显示:

{
  "accepted": false,
  "varname": "tmp",
  "longitude": 116.400244,
  "latitude": 39.912943,
  "datetime": "2023-10-10T00:00:00+00:00",
  "input_value": 26.0,
  "tolerance": 0.9999,
  "max": 24.62,
  "min": -0.2,
  "mean": 12.21
}

可以看出来质控系统认为 26°C 在 2023 年 10 月 10 日 08 点的北京地区出现是不合理的(accepted 参数为false),事实上根据中央气象台的数据,该时间北京地区的实际观测温度是 12.5°C,与检查结果返回的平均值 12.21°C 非常接近。

我们再看一下如果把这个温度放在 15 点会怎么样。

curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=116.400244&lat=39.912943&value=26&timestamp=1696921200"

返回的结果是:

{
  "accepted": true,
  "varname": "tmp",
  "longitude": 116.400244,
  "latitude": 39.912943,
  "datetime": "2023-10-10T07:00:00+00:00",
  "input_value": 26.0,
  "tolerance": 0.9999,
  "max": 31.79,
  "min": 6.45,
  "mean": 19.12
}

可以看出来相同的地点相同的气温如果放在下午 15 点,系统将判定为合理,给出的合理值范围是 6.45°C ~ 31.79°C 之间,平均值为 19.12°C,而真实的观测结果是 23.4°C。所以质控系统在小时级分辨率上对数据的质控是非常有效的,它可以识别出一天中气温在不同阶段的范围。

那它在不同季节上的判断效果如何呢?我们一起来看一下,相同地点相同气温值我们再分别去对 8 月 10 日和 12 月 10 日 08 点做一次检查:

# 2023 年 8 月 10 日 08 时
curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=116.400244&lat=39.912943&value=26&timestamp=1691625600"

# 2023 年 12 月 10 日 08 时
curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=116.400244&lat=39.912943&value=26&timestamp=1702166400"

输出的结果

{
  "accepted": true,
  "varname": "tmp",
  "longitude": 116.400244,
  "latitude": 39.912943,
  "datetime": "2023-08-10T00:00:00+00:00",
  "input_value": 26.0,
  "tolerance": 0.9999,
  "max": 33.8,
  "min": 16.42,
  "mean": 25.11
}
{
  "accepted": false,
  "varname": "tmp",
  "longitude": 116.400244,
  "latitude": 39.912943,
  "datetime": "2023-12-10T00:00:00+00:00",
  "input_value": 26.0,
  "tolerance": 0.9999,
  "max": 10.68,
  "min": -17.98,
  "mean": -3.65
}

可以看出来 26°C 在 8 月 10 日 08 时的检验通过了,而在 12 月的检验被拒绝了,这也是符合我们的认知的。可以看出来质控系统在不同季节的异常识别也是符合预期的。

我们再来检验两个极端一点的例子:海口市和漠河市的气温对比。在北京时间 2023 年 10 月 10 日 08 时,漠河和海口的气温分别是 -2°C 和 23.9°C。我们先将两个真实观测的气温带入质控系统系统检查:

漠河:

curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=122.543217&lat=52.994585&value=-2&timestamp=1696896000"

返回结果:

{
  "accepted": true,
  "varname": "tmp",
  "longitude": 122.543217,
  "latitude": 52.994585,
  "datetime": "2023-10-10T00:00:00+00:00",
  "input_value": -2.0,
  "tolerance": 0.9999,
  "max": 12.06,
  "min": -16.27,
  "mean": -2.11
}

海口:

curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=110.203841&lat=20.041518&value=28.9&timestamp=1696896000"

返回结果:

{
  "accepted": true,
  "varname": "tmp",
  "longitude": 110.203841,
  "latitude": 20.041518,
  "datetime": "2023-10-10T00:00:00+00:00",
  "input_value": 28.9,
  "tolerance": 0.9999,
  "max": 31.85,
  "min": 18.49,
  "mean": 25.17
}

漠河和海口的真实气温都通过了检查,那么我们把二者错位一下再看看结果。

先把海口的气温带入同时间的漠河经纬度检查:

curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=122.543217&lat=52.994585&value=28.9&timestamp=1696896000"

返回结果:

{
  "accepted": false,
  "varname": "tmp",
  "longitude": 122.543217,
  "latitude": 52.994585,
  "datetime": "2023-10-10T00:00:00+00:00",
  "input_value": 28.9,
  "tolerance": 0.9999,
  "max": 12.06,
  "min": -16.27,
  "mean": -2.11
}

再把漠河的气温带入同时间的海口经纬度检查:

curl "http://localhost:8000/v1/rationality/latlon/tmp/?lon=110.203841&lat=20.041518&value=-2&timestamp=1696896000"

返回结果:

{
  "accepted": false,
  "varname": "tmp",
  "longitude": 110.203841,
  "latitude": 20.041518,
  "datetime": "2023-10-10T00:00:00+00:00",
  "input_value": -2.0,
  "tolerance": 0.9999,
  "max": 31.85,
  "min": 18.49,
  "mean": 25.17
}

可以看出来错位以后的气温都没能通过质控系统的检验。因此,针对相同时间不同位置气温范围的检查结果也是符合预期的。

此外,我们还可以根据自己的实际需要来调整容忍度参数,如果我们希望能够以一种更宽松的检查尺度去检查数据的合理性,则可以调大 tol  参数的值(但不能大于或等于 1),更大的容忍度会得到更宽的范围边界值,反之亦然。这样这套质控系统就有能力适应多种不同的应用场景。

目前该质控系统已经在我们的后端系统中正式运行,每天对来自上游推送的数据进行数以百万次的数据检查,守护着我们的数据安全,也让我们从此告别了气温焦虑。

我们目前这套系统除了支持通过经纬度的方式检查以外,还支持仅通过国家气象站站号的方式进行查询和质控,还拿介绍开头的例子,检查 26°C 在北京时间 2010 年 10 月 10 日 08 时 54511(北京)站出现的合理性:

curl "http://localhost:8000/v1/rationality/sid/tmp/?sid=54511&value=26&timestamp=1696896000"

返回结果:

{
  "accepted": false,
  "varname": "tmp",
  "sid": 54511,
  "datetime": "2023-10-10T00:00:00+00:00",
  "input_value": 26.0,
  "tolerance": 0.9999,
  "max": 24.89,
  "min": 1.21,
  "mean": 13.05
}

可以看到也是没有通过检查,与之前的结果一致。除了气温以外,目前该系统还支持了气压和风速的合理性检查,后续我们还计划支持更多的要素。

系统的局限性与未来展望

根据上述的介绍,可以看出该质控系统能做到对不同位置、不同时间的气温合理性检查,且时间粒度能达到小时级,已经可以满足业务上大部分的数据质量检查的需求。但是由于空间分辨率的限制,对于一些地形起伏比较大的地区,还是容易出现误判。如果要提高系统在起伏地形上的质控效果,未来可能还需要考虑增加更高密度的历史地面观测数据,并加入对不同海拔高度的气温质控能力。