信息速览
GHCNd 是气候数据里最像「基础设施」的那一个:不漂亮、没有论文配图、下载下来是一堆没有扩展名美感的定宽文本,但几乎所有关于「某地某天到底多少度」的严肃工作,最后都会落到它身上。它的正式名字是全球历史气候学网络逐日数据集,由 NOAA 国家环境信息中心维护,收录十三万个地面站的逐日观测。
它最容易被低估的地方是结构。一行数据不是一天,而是一个站、一个要素、一整个月:269 个字符里塞着 31 组「数值 + 三个标志位」。理解这一点,才谈得上用它;不理解这一点,任何按行切的脚本都会得到三十倍的错误。
它最容易被高估的地方是覆盖。十三万个站听起来是全球密网,实际三分之二的站没有温度,美国一国占了六成,真正每年还在更新的只是一小部分。这篇条目要做的,是把「它有多大」和「它有多全」这两件事分开讲清楚。
| 项目 | 数值 | 依据 |
|---|---|---|
| 站点数 | 133,041 | ghcnd-stations.txt 行数 |
| 站×要素记录 | 791,313 | ghcnd-inventory.txt 行数 |
| 要素代码 | 144 种 | 同上去重 |
| 单行宽度 | 269 字符 | readme.txt 第 III 节 |
| 时间范围 | 1763-01 至 2026-10 | 清单最早起点 + 最新文件 |
| 全量包体积 | 3,818,113,068 字节 | HTTP 头 Content-Length |
| 更新节奏 | 每日增量追加,全量重算不定期 | ghcnd-version.txt |
| 许可 | 公有领域,仅要求引用 | NCEI 元数据记录 |
§1 速览:它是什么,也不是什么
§1.1 一句话定义
GHCNd 是一批按站点切分、按月成行、带三组标志位的逐日地面气候观测值,要素核心是五个:降水量、降雪量、雪深、日最高温、日最低温。
它不是格点产品,不是再分析,不是卫星反演,也不是「全球均匀覆盖的气候场」。它是一份观测台账:哪个站、哪个月、哪一天、量到了多少、这条数是谁报的、有没有通过检查。
§1.2 三个数字先把口径摆平
初学者最容易在三个数字上栽跟头,而这三个数字各有各的口径。
十三万三千是站点元数据的行数。这个数每天都在变,因为志愿雨量站还在增加。官方页面用的是「十万以上」,这是一句留了余量的话。
七十九万是站与要素的组合数,也就是清单文件的行数。同一个站如果有温度和降水,就占两行;有一百五十年记录的站和有三年记录的站,在这里都只占一行。它衡量的是「覆盖的广度」,不是「数据量」。
269 是一行的字符宽度。这个数字决定了所有解析代码的形状:21 个字符的头部,加 31 组 8 字符的日值块。
三个数字分别回答「有多少站」「有多少种观测」「一行多长」,混着用就会得出「有十三万天数据」这类结论。
§1.3 三十秒决策卡:你的处境,它能帮你什么
| 你的处境 | 它能帮你什么 |
|---|---|
| 要做「某地高温与死亡/发病」的时间序列分析 | 提供站点级日最高温,粒度与健康结局的日粒度天然对齐,不需要降尺度 |
| 要验证一套再分析或模式产品在某地准不准 | 站点观测是少数可以直接当参照的地面真值之一 |
| 要建农业气象指标,比如积温、霜冻日、无霜期 | 日最高最低温齐全,且部分站有百年以上记录,能算气候态 |
| 要研究极端降水的历史变化 | 降水站最多,但四成是志愿雨量站,必须先筛网型和记录长度 |
| 要做气候数据的工程练习:解析定宽文本、处理标志位 | 格式极简、无依赖、单文件可读,是最好的入门材料 |
| 要找一份能商用的全球观测数据 | 公有领域,没有授权谈判,只需要写清引用 |
| 要全球格点场、要海洋、要高空 | 给不了,见 §6 |
这张表里第一行对应本文的贯穿案例:一个虚构但典型的小组,做城市热浪与超额死亡的时间序列研究,代号 HWMort-Study。它需要在同一座城市拿到 1991 年至今的逐日最高温,与本地死亡登记按日对齐。这个需求看起来简单,实际会撞上本文后面反复出现的四个问题:站点从哪年起、要素缺哪几个月、日界怎么定、来源标志换过几次。
§1.4 不适合谁
如果需求是全球均匀的格点场,GHCNd 给不了。站点是点,格点是面,把点插值成面是另一件事,且插值方法的差异往往大于数据本身的差异。这类需求应该去看再分析产品,或者用它自带的 HadGHCND 网格版(3.75 度乘 2.5 度,7,002 个格点,只给温度距平)。
如果需求是逐小时或分钟级,也不合适。GHCNd 是日摘要,同门的 GHCNh 才是逐时与天气报时刻观测,两者共用站点编号,但要素、质控和文件结构完全不同。
如果需求是城市内部的热岛分布,同样不合适。一个城市在库里通常只有一个到几个站,站址还会迁移,城市内部的街区级温差它表达不了。
如果需求是因果推断里的「随机暴露」,需要格外小心。站点的选址、迁移、仪器更换、观测时次变化都会在长序列里留下不连续的台阶,这些台阶与人口、城市化高度相关,不处理就会被误读成气候变化。
§2 数据构成:十三万个站从哪来
§2.1 四条来源,四种性格
官方把源数据分成四类,这个分类比任何统计都更能解释数据的样子。
美国收集是最大的一块,来自十几个美国本土档案,从十九世纪覆盖大半个世纪的美国要塞站与志愿观测者记录,到实时自动地面观测系统,再到气候参考网。这一块的特点是记录长、要素全、更新快,且质量档案(DSI-3200 一类)有几十年积累。
国际收集是历史主体,约两万个美国以外的站点,来自一百多个国家,大体沿袭了前身全球逐日气候学网络的家底。这一块的特点是「历史而不实时」:官方自己举例,巴西与南非的降水记录大体止于 1990 年代末,印度止于 1970 年。
政府交换是通过 GCOS 与双边协议拿到的整库数据。加拿大提供七千五百多个站,澳大利亚提供一万七千多个站,这两国因此成为美国之外站点最密的地方。也有国家只提交其辖区内的 GCOS 基本站,于是只有几个站。
逐日全球摘要是从 GTS 交换的逐时天气报派生的,readme 对这条链路有一句罕见的直白提醒:由此得到的日值可能与真正的日观测相差很多,降水尤其如此,使用需谨慎。
这四条链路解释了为什么同叫「全球站网」,北美与欧洲的记录密度、要素完整度、更新及时性会比非洲、南美高出整整一个量级。
§2.2 站点码是十一字符的三段式
任何一条记录的第一列都是 11 个字符,读法固定:
| 位置 | 长度 | 含义 | 例子 |
|---|---|---|---|
| 1–2 | 2 | FIPS 国家或地区码 | US、CA、CH、AS |
| 3 | 1 | 网络码,说明站号体系 | 1、C、M、N、W |
| 4–11 | 8 | 站号本体 | 00094728 |
网络码有十个取值,其中几个决定了这个站是什么性格:1 是美国 CoCoRaHS 志愿雨量站,C 是美国合作观测站,M 是 WMO 站号,N 是各国气象部门自编站号,W 是 WBAN 站号,E 是欧洲 ECA&D 编号,S 是美国雪水当量遥测站。
这套编码有一个直接后果:同一个物理站点可以有多个编号。一个机场站可能既有 WMO 号体系下的编号,也有 WBAN 号体系下的编号,历史上还可能因为归档系统更换而换过号。做长序列拼接时,先按坐标与站名去重,比按编号拼接安全。
§2.3 站点构成的真实比例
把站点元数据按网络码和国别统计,会得到一张与「全球均匀覆盖」直觉相差很远的图:
| 维度 | 数量 | 占比 |
|---|---|---|
| 美国站点 | 78,570 | 59.0% |
| 其中 CoCoRaHS 志愿雨量站 | 53,167 | 40.0% |
| 澳大利亚站点 | 17,088 | 12.8% |
| 加拿大站点 | 9,906 | 7.4% |
| 巴西站点 | 5,989 | 4.5% |
| 墨西哥站点 | 5,249 | 3.9% |
| 印度站点 | 3,807 | 2.9% |
| 有 WMO 编号的站 | 8,096 | 6.1% |
| GCOS 基本网(GSN)站 | 985 | 0.7% |
| 美国历史气候网(HCN)站 | 1,218 | 0.9% |
| 美国气候参考网(CRN)站 | 234 | 0.2% |
这张表最有信息量的是两行。一行是「志愿雨量站占四成」:全世界 GHCNd 站点里有五万三千多个是美国家庭后院的自愿观测者,一天报一次雨量筒读数。这解释了为什么降水站的数量远多于温度站,也解释了为什么这些站的记录断点多、时次不统一。
另一行是「有 WMO 编号的只有八千」。真正参与全球天气交换的站点规模,比「十三万」小一个数量级。剩余十二万多个站是各国自建网、区域网、志愿网,它们的元数据、质控、更新节奏各不相同。
§2.4 要素是 144 种,但只有 5 种撑起全部
清单文件里出现的要素代码有 144 种,从常见的五个核心要素,到平均云量、平均露点、蒸发皿蒸发、土壤温度、天气现象编码。readme 明确定义了五个核心要素:
| 代码 | 含义 | 单位 | 有记录的站数 |
|---|---|---|---|
| PRCP | 日降水量 | 0.1 毫米 | 130,727 |
| SNOW | 日降雪量 | 毫米 | 83,926 |
| SNWD | 雪深 | 毫米 | 68,983 |
| TMAX | 日最高气温 | 0.1 摄氏度 | 40,940 |
| TMIN | 日最低气温 | 0.1 摄氏度 | 40,831 |
剩下的一百三十九种要素大多是局部补充:多日累计降水(MDPR)覆盖七万四千多个站,但它是把若干天的总量记在某一天上,配一个「包含天数」的伴随要素(DAPR);天气现象编码(WT01 至 WT22)只在有天气报的站出现;平均气温(TAVG)有一万五千多个站,且要到 2015 年 6 月才作为正式要素加入。
这里有一个反复出现的误读:TAVG 不是核心要素。它不是 TMAX 与 TMIN 的算术平均,而是各站按自己的观测时次或逐时值算出来的,来源不同、算法不同。想要日均温,最稳妥的做法是自己从 TMAX 与 TMIN 算,而不是取 TAVG。
§2.5 站与要素的交叉:七十九万行
把站点与要素交叉,得到 791,313 行清单记录。这个数字是理解「数据量」的关键中间量:它既不是站点数,也不是观测值数。
清单文件每行给定一个站的某个要素的起止年份,格式是固定列宽:
ACW00011604 17.1167 -61.7833 TMAX 1949 1949
GM000010962 47.8017 11.0117 PRCP 1781 2026
第一行说的是:这个加勒比站只有 1949 年一年的日最高温。第二行说的是:德国霍恩派森贝格站的降水从 1781 年一直记到 2026 年。
清单的价值在于「先查后用」。想知道某个城市有哪些站、各有什么要素、记录多长,读这一个 36 MB 的文本文件就够,不必下载 3.56 GB 的全量包。先清单、后数据,是使用这份数据最基本的节俭原则。
§2.6 站点元数据也是定宽的
介绍数据的人常常只讲数据文件,不讲元数据,结果是使用者对着 133,041 行坐标无从下手。站点元数据 ghcnd-stations.txt 同样是定宽格式,每行 85 个字符,九个字段:
| 字段 | 列 | 说明 |
|---|---|---|
| ID | 1–11 | 与数据文件同名,可直接对应 |
| LATITUDE | 13–20 | 十进制度,四位小数 |
| LONGITUDE | 22–30 | 十进制度,负值表示西经 |
| ELEVATION | 32–37 | 米,缺测写 -999.9 |
| STATE | 39–40 | 美国州码或加拿大省码,其余为空 |
| NAME | 42–71 | 站名,30 字符,超长会被截断 |
| GSN FLAG | 73–75 | 值为 GSN 表示属 GCOS 基本网 |
| HCN/CRN FLAG | 77–79 | 值为 HCN 或 CRN |
| WMO ID | 81–85 | 五位 WMO 站号,多数为空 |
几个从文件里能直接读出的事实:纬度范围从南极点附近的负九十度到北纬 83.65 度,经度覆盖整圈;高程从低于海平面 350 米到 5,033 米;有 4,737 个站的高程是缺测值。
站名这一列值得单独提醒:30 个字符的宽度装不下完整的机构名,很多站名被截成「ST JOHNS COOLIDGE FLD」这样的缩写,靠站名做模糊匹配会漏掉大量同名不同地的站。稳妥的匹配键是坐标,站名只做人工核对。
§2.7 案例:HWMort-Study 怎么选站
回到那个做热浪与死亡研究的 HWMort-Study 小组。它的第一步不是下载数据,而是在清单里回答三个问题:目标城市有没有站、站的记录是否覆盖研究期、要素是否含 TMAX。
以上海为例,选中的是 CHM00058362,坐标北纬 31.40、东经 121.467、海拔 4 米,属于 GCOS 基本网,带 WMO 编号 58362。它的记录从 1991 年 1 月开始,到 2026 年 10 月,站点文件 457,920 字节。
打开这个文件,会看到四件事同时发生:TMAX 只有 390 个月,TMIN 有 429 个月,PRCP 412 个月,另有一小段雪深 36 个月。同一个站、同一段时间,不同要素的覆盖并不一致。这就是清单文件只能给到「年份」粒度、而真实缺口要到日级才能看见的原因。
§3 记录层:一行 269 个字符
§3.1 一行是一个月,不是一天
这是整份数据里最贵的一课。
.dly 文件用定宽格式,每行 269 个字符,结构是:
ID(1-11) YEAR(12-15) MONTH(16-17) ELEMENT(18-21)
然后 31 组:(VALUE 5 字符)(MFLAG 1)(QFLAG 1)(SFLAG 1)
21 加 31 乘 8,正好 269。
拿纽约中央公园站 USW00094728 的第一行来看:
USW00094728186901TMAX -17 Z -28 Z 17 Z 28 Z 61
拆开读:站号 USW00094728,1869 年 1 月,要素 TMAX,1 日零下 1.7 摄氏度,测量标志空白,质量标志空白,来源标志 Z;2 日零下 2.8 摄氏度;3 日 1.7 摄氏度;4 日 2.8 摄氏度;5 日 6.1 摄氏度。
来源标志 Z 指「Datzilla 的正式增补或替换」,也就是说这一行 1869 年的数据不是原始档案直出,而是经过一次档案修订流程后写回的。
§3.2 逐字段解剖
| 字段 | 列 | 取值与陷阱 |
|---|---|---|
| ID | 1–11 | 定长 11,不足不补空格,前两位是国家码 |
| YEAR | 12–15 | 四位年份,最老 1763 |
| MONTH | 16–17 | 两位月份,注意是 01 至 12,不是 1 至 12 |
| ELEMENT | 18–21 | 四位要素码,大写 |
| VALUE | 每 8 字符的前 5 位 | 整数,右对齐补空格;缺测为 -9999 |
| MFLAG | 第 6 位 | 测量标志,空白或一个大写字母 |
| QFLAG | 第 7 位 | 质量标志,空白或一个大写字母 |
| SFLAG | 第 8 位 | 来源标志,空白或大小写字母、数字 |
四个字段里,最容易出错的是 YEAR 与 MONTH 的边界。因为 ID 是定长的 11 位、YEAR 紧接其后,用空格分列的思路解析必然错位。用固定列切片,或者用正则 ^(.{11})(\d{4})(\d{2})(.{4}),都可以;用 split() 不行,因为值字段内部有空格填充。
还有一个更隐蔽的细节:三个标志位的「空白」是一个空格字符,不是空字符串。直接和 "" 比较,会把所有通过质控的值判成异常——一套按白名单过滤的代码可能在无声无息中把一万多个温度值滤成零个。
§3.3 缺测是 -9999,而 0 有两种意思
缺测统一写 -9999。以纽约中央公园站为例,17,803 行、每行 31 格,共 551,893 个格位,其中 86,330 个是 -9999,占 15.6%。这些缺口不是随机分布的:早期年份缺得多,某些要素在某些年代整段缺失。
比缺测更容易误判的是 0。同一个文件里有 8,403 个格位的值是 0、测量标志是 T。T 表示微量:确实发生了降水或积雪,但量小于记录精度,于是按惯例记 0。
这意味着两件事。第一,把 0 当作「没下雨」会把「有雨但极小」和「无雨」混为一类,在算干旱日数、连续无雨日时会把天数算多。第二,把 0 参与平均是对的,把 0 参与「最大日降水」统计也是对的,但把 0 参与「降水的条件均值」就必须先筛掉 T。
§3.4 单位是整数标度,不是浮点
四个核心要素的单位都带缩放:
| 要素 | 存储单位 | 换算 | 例子 |
|---|---|---|---|
| PRCP | 0.1 毫米 | 除以 10 得毫米 | 值 46 即 4.6 毫米 |
| TMAX / TMIN | 0.1 摄氏度 | 除以 10 得摄氏度 | 值 -36 即 -3.6 摄氏度 |
| SNOW | 毫米 | 直接用 | 值 25 即 25 毫米 |
| SNWD | 毫米 | 直接用 | 值 130 即 13 厘米 |
降水与温度除以 10,雪的两个要素不除。这个不对称大概是历史遗留:积雪观测本来就以厘米级精度为主,不需要 0.1 毫米的刻度。写解析器时把它写成一张映射表,比在代码里到处写判断可靠。
另外,值字段宽度是 5,能容纳的最大整数是 99999,对应降水 9999.9 毫米、温度 9999.9 摄氏度,远超物理可能。质控里有一项「世界纪录检查」,专门拦超出地球极值的数据,但被拦下的值仍留在文件里,只是加了质量标志。
§3.5 三组标志位各管一件事
测量标志(MFLAG) 说明这个数是怎么来的。空白表示没有附加信息;T 表示微量;A 至 G 是各种时长报文累加的组合(六小时报、十二小时报、二十四小时报,以及它们的求和);H 表示温度取的是逐时极值或逐时平均;K、O、W 表示单位换算(节转米每秒、八分量云量转百分比、十六方位转角度);P 表示原始档案里标为「缺测但推定为 0」;L 表示观测时刻疑似滞后。
质量标志(QFLAG) 说明这个数在质控里出了什么事。空白表示全部检查通过;D 重复检查失败;G 间隙检查失败;I 内部一致性失败;K 连续同值或高频值检查失败;O 气候离群检查失败;S 空间一致性失败;X 越界失败;Z 表示经 Datzilla 调查后修订。共十四种取值。
来源标志(SFLAG) 说明这个数从哪条链路来。共三十种取值,包括数字 0、1、2、6、7 与大写、小写字母。小写与大写常常是同一国家的不同渠道:s 是中国气象局国家气象信息中心,S 是 GTS 逐时报文派生的逐日摘要;a 是澳大利亚气象局,A 是美国实时自动地面观测。
readme 还给了一张来源优先级表,当同一天同一要素有多个来源时,按 Z、R、W、D、d、1、0、6、C、X、K、7、F、B、M、f、m、r、E、z、u、b、s、a、G、Q、I、A、N、T、U、H、2、S 从高到低取舍。这张表解释了一个常见困惑:为什么同一个站的历史数据在两次下载之间会变。答案往往不是观测改了,而是更高优先级的来源补齐了同一天,把低优先级的值替换掉了。
§3.6 同一份数据有四种排布
库里的东西不是只有一种形态,选错形态会让工作量翻倍。
| 形态 | 路径 | 一行是什么 | 适合 |
|---|---|---|---|
| 定宽月表 | all/<ID>.dly |
一个站一个月一个要素 | 逐站深挖、长期归档 |
| 打包 | ghcnd_all.tar.gz |
同上,十三万个文件打成一包 | 全量离线 |
| 长表 CSV | by_station/<ID>.csv.gz |
一个站一天一个要素 | 直接入库、按日连接 |
| 超级表 | superghcnd/ |
全库一天一个要素,逗号分隔 | 全量分析、增量比对 |
长表与定宽表的信息并不完全等价:长表多一个观测时次(OBS-TIME)字段,取自 NCEI 的站点历史库,格式是四位时分,例如 0700。定宽表里没有这个字段。要做日界校正的研究,长表比定宽表省事。
还有一个文件名陷阱:长表的文件名以 .csv.gz 结尾,直接请求 USW00094728.csv 会返回 404。目录列表里成千上万个文件,肉眼扫一遍很容易看漏那个 .gz。
§3.7 一个月不满 31 天怎么办
不足 31 天的月份,剩余格位统一填 -9999,标志位留空。于是 2 月永远有 3 个假缺口(闰年 2 个),4、6、9、11 月各有 1 个。
这带来一个隐蔽的统计偏差:如果一律用 31 作分母求月均值,2 月会被稀释约一成,4、6、9、11 月各被稀释约百分之三。正确做法是先按年月构造日历,用当月实际天数作分母,而不是对整行做固定宽度切分。
§3.8 多日累计:一格里可能装着七天
有一类要素天生违反「一格一天」的直觉。
美国志愿雨量网 CoCoRaHS 的观测者不一定每天读数。有人出差三天,回来把三天的雨量一次性报上来。这类数据在库里表示为两个要素:MDPR 记总量,DAPR 记这段总量包含几天。全库有 74,955 个站出现 MDPR,67,763 个站出现 DAPR,规模与核心要素同量级。
问题在于落位。一笔「三天共 26.4 毫米」的记录按惯例挂在最后一个观测日,于是日序列里会出现一个虚构的尖峰:那天下了 26.4 毫米,前两天记 0 或缺测。对月总量没影响,对日极值、连续干旱日、暴雨日数全都有影响。
处理办法有三种,各有代价:
| 办法 | 做法 | 代价 |
|---|---|---|
| 标记不摊分 | 认出 DAPR 大于 1 就把该日标为累计值 | 保留原始信息,但日序列仍有尖峰 |
| 按天数均摊 | 把总量除以天数,均分到各日 | 制造了不存在的均匀降水,压低极值 |
| 整段剔除 | 遇到累计值就把这几天一起删掉 | 干净,但会系统性丢失雨季数据 |
readme 还定义了 DWPR,表示这段累计期里有几天真正下了雨。它的价值在判断「三天 26.4 毫米」到底是「每天 8.8 毫米」还是「一天 26.4 毫米加两天没下」。真正严谨的处理要用到它,但它在库里的覆盖远不如 MDPR 广。
对 HWMort-Study 这类只关心温度的团队,这一节可以跳过;对任何做降水极值、农业干旱、洪水的研究,这是必须先处理干净的一层。
§4 时间层:从 1763 到 2026,以及「活的站」其实很少
§4.1 官方页面写错了最早年份
官方产品页有一句话,说数据集中最早的观测是 1832 年 1 月 1 日澳大利亚帕拉马塔的日降水总量(站号 ASN00066046,总量 0.0 毫米)。这句话有问题,而且是两层问题。
第一层是排版。页面原文写成 January 1,17321832,「1732」和「1832」粘在一起,说明这段文字被改过而旧年份没删干净。任何照抄这句话的二手资料,都可能把 1732 当成答案。
第二层是事实。清单文件里,降水的起点最早是德国霍恩派森贝格站 GM000010962,1781 年;温度更早,米兰 Brera 站 ITE00100554 的日最高温从 1763 年 1 月开始,布拉格 Klementinum 站 EZE00100082 从 1775 年 1 月开始。三个文件的第一行都能直接看到非缺测数值:米兰 1763 年 1 月 1 日是零下 3.6 摄氏度,霍恩派森贝格 1781 年 1 月 4 日是 4.6 毫米降水。
所以正确的最早边界是 1763 年 1 月,比官方那句话早了六十九年。这不算官方出错得离谱——那句话大概率指的是某个子集,或者写于这些欧洲长序列入库之前——但它确实是过时的,不能作为引用依据。
§4.2 长记录的真实分布
把清单里每个站×要素的起止年拿出来,会看到一条很陡的曲线:
| 口径 | 数量 | 占全部站×要素记录 |
|---|---|---|
| 记录延续到 2026 年 | 166,445 | 21.0% |
| 记录在 1999 年或之前终止 | 271,855 | 34.4% |
| 跨度满 100 年 | 26,271 | 3.3% |
| 其中 TMAX 满 100 年 | 2,857 | — |
三成四的记录已经死了,只有两成还活着。这两个数字合起来才是这份数据的真实性格:它更像一座档案馆,而不是一个监测网。做当代分析时,第一步永远是按终止年份筛选;做历史分析时,第一步永远是按跨度筛选。两个方向用的是同一张清单,但筛法相反。
§4.3 日界不是午夜
这是气候暴露研究里最容易被忽略的一处系统性误差。
GHCNd 的日值是「观测日」的值,观测日由观测员或自动站的观测时次决定。美国合作站传统上在早晨观测,于是「7 月 1 日」的记录实际覆盖的是 6 月 30 日早晨到 7 月 1 日早晨。而健康结局、死亡登记、急诊记录用的是日历日。两者错开若干小时,在热浪这种以「连续高温日」定义的暴露里,会直接影响归因结果。
数据里能拿到的线索有两个:长表的 OBS-TIME 字段,以及定宽表里的 TOBS 要素——后者记录观测时刻的气温,全库有 15,752 个站,不到总站数的一成二。OBS-TIME 的覆盖没有单独统计,只能按站去查。两者都拿不到的站,只能回到站点历史库里找。
对 HWMort-Study 这类研究,稳妥的做法是:优先选观测时次接近当地午夜或固定的站;若做不到,就在敏感性分析里给出「日界前后各偏移一天」的对照结果,而不是假定日界就是午夜。
§4.4 版本时间是两套时钟
版本文件里写着这样一句:当前版本 3.35-upd-2026102717,即在 2026 年 10 月 27 日 17 时(UTC)启动的一次更新,它把近期可用的数据追加到上一个完整重算版本 3.35-por-2026102323 之上。
也就是说,库里同时跑着两套时钟:por 是周期性全量重算,会把所有历史记录按最新质控规则重新走一遍;upd 是每日增量,只追加新到的数据。两套时钟的日期不同,文件时间戳也就不同——同一天去看,站点元数据、清单文件、全量包的最后修改时间可以相差几个小时,而版本串还停在两天前。
实践含义是:不要用版本串判断数据新鲜度,用文件头的 Last-Modified 和最后一行的年月。
§4.5 案例回扣:上海站的时间边界
回到 HWMort-Study。它最终拿到的上海站序列覆盖 1991 年 1 月到 2026 年 10 月,共 430 个可能月份,其中日最低温有 429 个月的行,日最高温只有 390 个月、11,105 个日值,最后一个有效值停在 2026 年 9 月 22 日——站点文件写到了 10 月,温度却还没跟上。这个起点不是随意选的:中国在库里的 228 个站,最早的起点是 1942 年(昆明),1950 年及以前开始的只有 22 个,绝大多数站在 1951 年之后才开始,而上海站本身要到 1991 年。
这直接限制了研究设计:想做「1980 年代以来热浪变化」,用这一个站做不到;想扩到全国,会立刻遇到 §6 要讲的要素不均匀问题——印度有 3,807 个站,但只有 201 个站有温度。
时间边界和空间边界在这份数据里是同一个问题的两面。
§4.6 长序列的断点从哪来
一份记录了一百五十年的序列,看起来像一条连续的线,实际是由许多段拼起来的。断点至少有四个来源,而数据文件本身只记录第一个。
站址迁移是最常见的一种。城市扩张会把观测站从市中心推到郊区,一次迁移可能带来一两度的台阶。长序列站里极少有从未搬过的,有的甚至在同一个公园内换过几处位置。迁移日期不在 GHCNd 里,而在 NCEI 的站点历史库中。
仪器与遮蔽变化是第二种。百叶箱换成通风式、水银温度计换成电子传感器、雨量筒加装防风圈,都会改变读数。这类变化往往没有明确日期,只能从序列的方差结构里推断。
观测时次变更是第三种,也是最容易被忽略的。一个站从每天早八点观测改成逐时自动观测,日最高温的定义就从「早八点前后 24 小时内的最高值」变成「整点或分钟级的最高值」。后者系统性偏高,因为人工观测每 24 小时只取一个瞬时值,容易错过真正的峰值。
质控规则变更是第四种。全量重算会把历史上的值按新规则重标,被标为离群的值仍然保留,但标志位变了。同一段序列在两个版本里看起来不同,原因可能仅仅是检查变严了。
这四种断点里,只有第三种能在数据里找到间接证据:TOBS 要素的出现与消失,或者观测时次字段的变化。其余三种必须外查。任何声称「用 GHCNd 单站序列做了百年趋势」的研究,都应该交代断点处理方式,否则那条趋势线里混着搬迁与换仪器的贡献。
§5 获取层:五条路径与一条校验纪律
§5.1 路径总表
| 路径 | 地址 | 要不要注册 | 适合 |
|---|---|---|---|
| HTTPS 目录 | ncei.noaa.gov/pub/data/ghcn/daily/ | 不要 | 默认选项,文件最全 |
| 全量打包 | 同上,ghcnd_all.tar.gz | 不要 | 一次拿全库 |
| 子集打包 | ghcnd_gsn.tar.gz / ghcnd_hcn.tar.gz | 不要 | 只要 GCOS 网或美国历史网 |
| S3 镜像 | noaa-ghcn-pds.s3.amazonaws.com | 不要 | 程序化拉取、按站取 |
| 在线接口 | ncei.noaa.gov/cdo-web/api/v2 | 要免费 token | 按条件检索、少量取数 |
§5.2 全量包:3.56 GiB,每次重打体积都不同
ghcnd_all.tar.gz 是把十三万个站点文件打成一个 gzip 包。写作当日的 Content-Length 是 3.56 GiB,精确字节数见附录 D,正文不再重复引用。
这个数字不稳定。目录页上显示的数值与 HTTP 头返回的数值相差 5.7 MB,两者都对,只是时刻不同。原因有两个:目录列表页面有缓存,显示的可能是上一版;打包会被周期性重做,而新增的观测会让包变大一点,历史修订也会让它变小一点。
实践含义:做容量规划时按 4 GB 留余量,不要按某一次的精确值;做自动化脚本时,用 HEAD 请求拿当场的大小,不要写死。
包里是平铺的 .dly 文件,解压后得到十三万个单站文件,单站文件从几百字节到几兆不等。纽约中央公园站是 4,806,810 字节,上海站是 457,920 字节。
§5.3 单站:先查清单,再取一个文件
只需要一个城市的数据时,最快的路径是三步:在站点元数据里按站名或坐标找编号,在清单里确认要素与年份,然后直接取 all/<编号>.dly。
BASE=https://www.ncei.noaa.gov/pub/data/ghcn/daily
STN=CHM00058362
curl -sS -o stations.txt "$BASE/ghcnd-stations.txt"
curl -sS -o inventory.txt "$BASE/ghcnd-inventory.txt"
grep "$STN" stations.txt
grep "$STN" inventory.txt
curl -sS -o "$STN.dly" "$BASE/all/$STN.dly"
wc -c "$STN.dly"
最后那行 wc -c 不是多余的。下一步会解释为什么。
§5.4 S3 镜像:给程序用更顺手
noaa-ghcn-pds 这个公开桶把同一批数据按 csv.gz/by_station/ 的路径重排了一遍,支持 Range 请求,取单站比逐个建连更快。它的长表格式与官方 by_station 一致:
USW00094728,18690101,TMAX,-17,,,Z,
八列分别是站号、日期、要素、值、测量标志、质量标志、来源标志、观测时次。空字段连着两个逗号,解析时要按位置取,不能用「跳过空字段」的写法。
镜像与主站不是严格的同一时刻:主站每天下午(美国东部时间)跑更新,镜像同步有延迟。做可复现研究时,要么固定日期,要么记录两边的文件哈希。
§5.5 打包子集:GCOS 网与美国历史网
如果研究只需要「有全球交换地位」的站,用 ghcnd_gsn.tar.gz(180,312,748 字节,985 个站)。如果只做美国长序列,用 ghcnd_hcn.tar.gz(316,479,967 字节,1,218 个站)。
这两个子集的站点是元数据里的两个标志位筛出来的:GSN 标志由 WMO 号与官方 GSN 名录比对生成,HCN 与 CRN 标志则标出美国历史气候网与气候参考网站点。它们的好处是记录长、质控严、维护稳定,代价是空间覆盖极稀。
§5.6 接口:要 token,而且只适合少量取数
在线检索接口(CDO v2)在没有 token 时返回的是一句明确的拒绝:Token parameter is required.。token 免费申请,但要走邮件流程——这与「GHCNd 免费直下」并不矛盾,因为接口是另一条链路:批量下载走 HTTPS 或 S3,完全不需要注册;按条件查询走接口,需要 token。
接口适合「给我纽约中央公园站 2020 年的日最高温」这类小请求,不适合全库拉取:它有每日调用上限,且返回的是 JSON 包裹后的结果,比直接读文本重得多。
§5.7 一条校验纪律:截断的文件看起来完全正常
这不是假设,而是一次真实发生的下载事故。
用 60 秒超时下载纽约中央公园站的 .dly,得到 765,120 字节。文件能被正常打开,每行都是 269 个字符,最后一行以换行结束,wc -l 给出 2,833 行,一切看起来都对。但服务端声明的大小是 4,806,810 字节。少了 84%。而 curl 的退出码是 0。
原因很简单:定宽文本没有文件头、没有结束标记、没有校验和。截断发生在任意一个换行处,结果仍然是一份完全合法的文件,只是提前结束。用这份文件统计年份范围,会得出「该站止于 1923 年」的结论——一个彻底错误、但看起来很有说服力的结论。
正确的纪律是三步:先 HEAD 拿 Content-Length,再下载,再比对本地字节数。
URL=https://www.ncei.noaa.gov/pub/data/ghcn/daily/all/USW00094728.dly
EXP=$(curl -sI "$URL" | tr -d '\r' | awk 'tolower($1)=="content-length:"{print $2}')
curl -sS -o nyc.dly "$URL"
GOT=$(wc -c < nyc.dly)
test "$EXP" = "$GOT" && echo "size ok $GOT" || echo "TRUNCATED $GOT of $EXP"
gzip 包没有这个问题:截断的 gzip 解压时会报错。所以「用打包文件更安全」不只是省事,也是一种隐式的完整性保护。
§5.8 一次最小解析
下面这段代码把一个月表读成按日的记录,可以直接跑:
from pathlib import Path
def parse_dly(path):
rows = []
text = Path(path).read_text(encoding="ascii")
for line in text.splitlines():
if len(line) != 269:
continue
sid = line[0:11]
year = int(line[11:15])
month = int(line[15:17])
element = line[17:21]
for day in range(31):
base = 21 + day * 8
raw = line[base:base + 5].strip()
if raw in ("", "-9999"):
continue
rows.append({
"id": sid,
"date": (year, month, day + 1),
"element": element,
"value": int(raw),
"mflag": line[base + 5],
"qflag": line[base + 6],
"sflag": line[base + 7],
})
return rows
recs = parse_dly("CHM00058362.dly")
tmax = [r for r in recs if r["element"] == "TMAX"]
print(len(recs), len(tmax), tmax[0]["date"], tmax[0]["value"])
日期用元组而不是 datetime,是因为 2 月 30 日、31 日在文件里以 -9999 存在,构造 datetime 会抛异常;先过滤缺测再转日期,顺序不能反。
§5.9 按年目录:做跨站同年分析时更省事
除了按站切分,库里还有一个 by_year/ 目录,把日值按年份重排,并附带观测时次。它的用途很具体:当你需要「1998 年所有站的 7 月」而不是「某个站的 1998 年」时,按年取比按站取快得多。
代价是文件粒度粗,而且年际差异极大:1763 年的文件只有 3,358 字节,1900 年是 20,522,423 字节,1980 年是 152,870,525 字节,2020 年是 172,394,187 字节。同一个目录里,最早与最近的年份可以差出三个数量级。做单城市分析时按年取反而更慢。
三种切分各有各的最优场景,选错会白等:
| 切法 | 目录 | 最优场景 |
|---|---|---|
| 按站 | all/ 、by_station/ | 单城或单站深挖 |
| 按年 | by_year/ | 跨站同期比较、事件年复盘 |
| 全量差分 | superghcnd/ | 每日增量入库 |
superghcnd 目录每天提供两个文件:全量的逗号分隔版本,以及两次更新之间的差量版本。做增量同步时只取差量,比每天重下 3.56 GiB 划算得多;但差量文件的结构与全量一致,仍然需要自己按日期去重。
§5.10 本地怎么存:先定主键再谈库
这份数据落到本地之后,最容易犯的错是把它当成「一张表」直接塞进数据库。
按行的原始结构,主键是「站号 + 年月 + 要素」,一行存 31 天。按日的展开结构,主键是「站号 + 日期 + 要素」。两种都不适合直接做分析,因为分析时最常按「站号 + 要素 + 时间范围」检索,而这两种结构都需要范围扫描。
实践上比较稳的存法是三层:
| 层 | 内容 | 主键 | 用途 |
|---|---|---|---|
| 原始层 | 原样保存 .dly 与清单 | 文件名 | 可追溯、可重放 |
| 展开层 | 按日一行,保留三组标志 | 站号+日期+要素 | 查询、连接 |
| 聚合层 | 按站按月或按站的统计 | 站号+年月 | 建模、绘图 |
原始层不能省。展开层一旦写错列切片,错误会被永久固化,而原始文件是唯一能回滚的依据。留一份原样文件,成本是几个 GB 的磁盘,收益是任何解析 bug 都能重来。
展开层的存储量需要预估:单站一个要素一百五十年约五万四千个日值,全库按清单的七十九万条站×要素记录折算,量级在十亿行上下——这个数字是按压缩包体积与行宽粗估的,不是官方统计。这个规模用单机数据库可以处理,但必须按站或按年分区,否则任何一次全表扫描都会让人怀疑硬盘。
§5.11 缓存与增量:别每天重下全量
如果只是持续跟踪,不需要每天拿全量包。合理的策略是三步:首次下载全量,之后每天只取 superghcnd 的差量文件,每月做一次全量校验。
差量文件的价值在于它足够小——每天新增与修订的记录,量级是几万到几十万条,压缩后通常在几十 MB。全量包则是 3.56 GiB,每天下载既费带宽也费时间。
校验的意义在于防止差量累积出错。差量是按顺序叠加的,中间漏了一天,后面全对不上,而且不会报错。每月拿一次全量,比对随机抽样的若干站,能低成本地发现这类静默错位。
§6 边界:它能回答什么,不能回答什么
§6.1 空间边界:站点密度是政治与历史的产物
| 现象 | 数字 | 后果 |
|---|---|---|
| 美国占全部站点 | 59.0% | 全球平均会被北美权重主导 |
| 美国占全部温度站 | 19,633 / 40,940,约 48% | 半球平均的南北权重严重失衡 |
| 印度站点 | 3,807 个,其中 201 个有 TMAX | 南亚温度分析几乎无站可用 |
| 巴西站点 | 5,989 个,其中 170 个有 TMAX | 有温度的站不到全部巴西站点的 3% |
| 南非站点 | 1,166 个,其中 79 个有 TMAX | 南部非洲仅能做大尺度平均 |
| 澳大利亚站点 | 17,088 个,其中 1,658 个有 TMAX | 降水密、温度稀,同为「站多要素少」 |
同一个国家内部也有落差:印度有三千八百多个站,但绝大多数只有降水,来自国家降水网的历史档案。这不是数据造得不好,而是各国的观测传统不同——雨量筒便宜、易维护、布点密;温度计需要遮蔽、需要校准、需要连续值守。
于是任何「全球平均气温」的算法,用 GHCNd 原始站点做等权平均都会严重偏向北美。正规做法是先格点化再加权,或者直接用已经格点化好的产品。
§6.2 要素边界:三分之二的站没有温度
130,727 个站有降水,40,940 个站有日最高温。有降水但没有温度的站是 91,837 个,占全部有数据站点的 69.1%。
这个比例解释了为什么「GHCNd 有十三万个站」和「GHCNd 能给我这个城市的温度」经常不能同时成立。使用者拿到一个站号后,第一件事应该是查它有没有 TMAX,而不是直接读文件然后疑惑为什么全是 -9999。
§6.3 时间边界:1960 年代最密,两头都稀
官方给出的图景是:1890 年以前有记录的站点很少,温度站数量约为峰值的 2.5%,降水站约为 8.9%;温度网与降水网的密度都在 1960 年代达到顶峰,之后缓慢下降。
这条曲线的形状对趋势估计有直接影响:如果直接对「所有可用站」求平均,1960 年代会出现一个由站点数量变化造成的假台阶。这也是气候学界长期使用「异常值 + 固定基准期 + 格点加权」这套繁琐流程的原因——它不是为了好看,而是为了消掉站网变化带来的偏差。
§6.4 四件它做不到的事
做全球格点场。 站点是点,要做面必须插值。库里的 HadGHCND 网格版是一种官方插值,但只给温度距平、只到 3.75 度乘 2.5 度、只有 7,002 个格点,且基准期固定为 1961 至 1990 年。
做城市内部分析。 一个城市通常一个到几个站,站址迁移与城市化热岛叠加在同一条序列里,无法分离。
做极端值的重现期估计。 单站日值序列有断点、有观测时次变化、有仪器更换,直接拟合极值分布会把非气候的不连续当成气候信号。
做因果归因。 站点的选址与人口分布相关,暴露不是随机分配的。要做因果推断,需要额外的识别策略,不能只靠这份数据。
§6.5 与相邻资源的分工
| 资源 | 单元 | 与 GHCNd 的关系 |
|---|---|---|
| ERA5 等再分析 | 格点、逐时 | 空间连续但为模式与观测混合;常以 GHCNd 为真值做检验 |
| GHCNh | 站点、逐时/天气报时刻 | 同一批站编号,时间分辨率更高,要素更多,取代 ISD |
| HadGHCND | 格点、日、距平 | GHCNd 的官方网格化产物,只含温度距平 |
| 各国气象局原始库 | 站点、日或更细 | GHCNd 的上游;要素更全、质控档案更细,但需单独申请 |
| 卫星反演地表温度 | 格点、晴空 | 测的是地表皮温,不是气温,二者不可互换 |
判断规则可以压成一句:要站点真值与长历史,用 GHCNd;要连续场与逐时,用再分析或 GHCNh;要某国最全的观测,去找该国气象局。
§6.6 把点连到人:空间连接的三种做法
气候暴露研究真正的工作量不在读气象数据,而在把气象数据接到人群上。这一步有三种做法,误差量级各不相同。
最近站法是最简单的:每个行政单元取最近的站。它的误差在平原地区可以很小,在山区会非常离谱——两个相邻县可能共用同一个站,而它们海拔差了一千米。判断风险的办法是看高程差:站点元数据有高程,行政单元也有平均高程,差三百米以上就该警惕。
反距离加权是折中:取周围若干站,按距离的倒数加权。它的问题是权重完全由几何决定,不考虑地形与气候区。在海岸带与内陆的交界,它会把海洋性气候摊到内陆。
先格点化再取格点是最稳的:用官方的 HadGHCND,或者自己按固定网格做插值。代价是空间分辨率被网格尺寸锁死,HadGHCND 的格点是 3.75 度乘 2.5 度,在东亚大约是几百公里见方,做城市研究会太粗。
三种做法都可以用,但必须在论文里写清楚用了哪一种。同样一份死亡数据,配最近站法和配格点法,热浪归因的结论可以相差几个百分点——这个差距不是数据的问题,是连接方式的问题。
§6.7 不确定性至少来自四层
用这份数据做暴露评估,误差不是一个数字,而是四层叠加。
观测误差来自仪器精度与读数习惯。温度计的标称精度在零点一摄氏度量级,人工读数的舍入往往到半度。对日最高温这类量,单日误差可以忽略,对三十年均值就会被平均掉。
代表性误差来自站点与目标区域的空间错配。一个站在机场,目标是市中心三公里外的居民区,两者的夜间温差可能有两度。这层误差通常比观测误差大一个量级,却最常被忽略。
日界误差来自 §4.3 讲的时次问题,量级取决于当地观测习惯,在美国合作站可以到几个小时。
抽样误差来自站点集合的变化。用不同数量的站求区域平均,结果会不同;用固定站集与用逐年在册站集,趋势估计会差出可观的量。
四层里,只有第一层可以通过增加样本量减小。后三层必须靠设计解决:选代表性好的站、固定站集、做日界敏感性分析。把它们合并成一个「±0.5 摄氏度」写进论文,是最常见的偷懒,也是最容易被审稿人抓住的地方。
§7 质量评估:它不该按什么标准评价
§7.0 阅读本节前需要知道的一件事
用「数据完整率」「缺失率」「一致性」这类通用指标去评价 GHCNd,很容易得出「质量很差」的结论:十五个百分点的缺测、三成四的记录已终止、四成站点是志愿观测。但这些指标在这里没有意义,因为 GHCNd 的设计目标不是「造一份干净的数据」,而是「把散落在各国各年代的观测汇总成一份可追溯的台账」。
它的质量体现在别的地方:每个值都带来源标志,每次修订都能追到 Datzilla,每条质控失败都保留原值而不删除。评价它,应该问「我能不能判断这个值可不可信」,而不是「这个值缺不缺」。
§7.1 三种最常见的误判
把缺测当零。 -9999 是一个显式的哨兵值,但很多脚本在整数转换后忘了过滤,于是 -9999 参与平均,把月均值拉到零下几百摄氏度。这类错误在快速原型里极常见。
把质控标志当过滤条件。 QFLAG 非空表示「这项检查没过」,不表示「这个值是错的」。官方保留原值并打标,是让使用者自己决定。把带标志的值全部删掉,在个别站会删掉相当比例的数据;全部保留,又会把明显的录入错误带进模型。合理做法是按检查类型分级:越界(X)与重复(D)通常可删,气候离群(O)与空间一致性(S)应保留但降权。
把站点当格点。 用最近站点代替城市,在站网稀疏地区会把几十公里外的观测当成城市观测。官方的站点坐标精确到 0.0001 度,但那只说明元数据精细,不说明代表性。
§7.2 按 DAIMS 的六组维度对照
| 维度 | 这份数据的表现 | 备注 |
|---|---|---|
| 可发现性 | 强:产品页、目录、DOI、S3 镜像四条入口都在 | 目录页有缓存,时间戳可能滞后 |
| 可访问性 | 强:无需注册、无需 token、支持 Range | 主站限速明显,全量包下载耗时长 |
| 可理解性 | 中:格式说明详尽,但要素与标志位分散在 29 KB 的 readme 里 | 没有机器可读的数据字典 |
| 可链接性 | 中:站点有稳定编号,但编号会随版本变更 | 2026 年 10 月加拿大站点编号整体改过 |
| 可互操作性 | 中:定宽文本需自写解析器,无 Parquet、无 NetCDF | 社区有多个第三方转换器 |
| 可复用性 | 强:公有领域,仅要求引用 | 上游源国条款需另行注意 |
§7.3 逐条局限
记录会变。 同一个站同一天的值,在两次下载之间可能不同:更高优先级的来源补齐了,或者 Datzilla 修订了。想复现,必须锁定下载日期与版本串。
编号会变。 3.35 版把加拿大站点的编号从网络码 0 改为 N,以与 GHCNh 对齐。任何以站号为键的历史数据库,在这次升级后都会对不上。
要素会增。 TAVG 是 2015 年 6 月才加入的;相对湿度、气压、露点等七个要素是 2022 年 6 月加入的,一次增加约一千八百万个值。用旧版本训练的模型,换新版本后特征维度会变。
质控会重跑。 por 全量重算会把历史值按新规则重新检查,标志位可能从空白变成非空。这不代表当初的观测错了,只代表检查规则变了。
§7.4 该追问什么、不该追问什么
该追问的是:这个站的观测时次是什么、站址迁移过几次、这段序列的来源标志换过没有、质控在这段记录上触发了哪些检查。这些都能从数据与站点历史库里查到。
不该追问的是:为什么这个站缺了 1962 年 3 月。答案通常是原始档案就缺,或者该月的报文没进交换网。GHCNd 是汇总者,不是原始观测者,它无法补一份从未存在过的记录。
§7.5 九项质控检查各自拦什么
readme 列出的质控检查有十余项,常用的九项列在下表,第三列是失败时留下的质量标志:
| 检查 | 拦什么 | 典型标志 |
|---|---|---|
| 微量一致性 | 标了微量但数值非零 | 不单独打标 |
| 世界纪录超出 | 超出地球极值的离谱数字 | X |
| 间隙检查 | 同站同月内与其余值差出十摄氏度以上 | G |
| z 分数气候离群 | 偏离十五天气候均值六个标准差 | O |
| 百分位气候离群 | 降水超过二十九天 95 百分位的若干倍 | O |
| 内部温度一致性 | 最高、最低、观测时刻三者矛盾 | I |
| 滞后温差 | 与前后一天的最低温差超过四十度 | R |
| 空间一致性 | 与邻近站的距平差超过十摄氏度 | S |
| 重复检查 | 超过五成记录与另一站完全相同 | D |
这张表里最值得记住的是最后一行。重复检查不是查同一天两遍,而是查整站级别的复制:如果某个站有一半以上的记录与另一个站一字不差,它就被判为重复站并被标 D 或直接拒收。这条规则解释了为什么库里同一个城市有时会出现两个站名不同、数据却高度相似的记录——其中一个是另一个的转抄,质控只能标出来,不能替你决定删哪个。
第二值得记住的是间隙检查的阈值:同站同月内温度差十度、降水差三百毫米。这两个数字看起来宽松,实际对城市站很严——一次寒潮就可能触发。看到 G 标志不要立刻删数据,先看它落在哪个月。
§8 生态与版本:它为什么还能被用下去
§8.1 版本串怎么读
版本号形如 3.35-upd-2026102717。三段分别是主版本、时钟类型、时间戳。主版本从 3.00 起算,每次新增数据源或改变处理规则就进位;时钟类型有两种,por 表示全量重算,upd 表示增量追加;时间戳是 UTC 的年月日时。
引用时应写明「Version 3.35」,并按 readme 的引用模板补一句「使用子集」——因为全库与单站子集的差异太大,不写子集等于没写。
§8.2 版本时间线里藏着使用风险
近十年的几次升级,每一次都改变了数据结构:
| 版本 | 时间 | 变化 |
|---|---|---|
| 3.21 | 2015-06 | 新增 TAVG 要素 |
| 3.22 | 2015-09 | 雪水当量遥测数据换源,新增 191 个站 |
| 3.26 | 2019-04 | 新增墨西哥约五千站,值总量增加约一亿五千万 |
| 3.27 | 2019-05 | 新增 CoCoRaHS 多日降水要素 |
| 3.29 | 2022-06 | 新增七个美国机场站要素,值增加约一千八百万 |
| 3.33 | 2026-01 | 引入逐日天气报摘要二代,作为 GSOD 的后继 |
| 3.35 | 2026-10 | 加拿大站点编号从网络码 0 改为 N |
对使用者的含义很直接:跨版本比较数据量没有意义,跨版本用站号做主键会出错,跨版本比较「有多少个站有某要素」也会变。
§8.3 谁在依赖它
气候趋势研究、极端事件归因、农业气象服务、能源负荷预测、保险精算、公共卫生的暴露评估,都把它当作地面真值的默认选项。它的地位不是因为技术先进,而是因为三点:免费、无授权摩擦、有 DOI 可引用。
这三点在学术出版里权重极高。一份数据只要能给出稳定的 DOI 与明确的引用格式,就能进入方法学部分;反之,再精确的私人观测也难被引用。
§8.4 它为什么能持续
它靠的不是商业模型,而是制度安排:美国联邦政府作品不受版权保护,NCEI 有法定职责长期归档气象记录,各国气象部门通过 GCOS 与双边协议持续提交数据。三件事合起来,构成了一条不依赖单一机构的供给链。
这条链也解释了它的脆弱处:加拿大环境部的日更新源在 2024 年 4 月意外中断,直到 2026 年 10 月才以新方式恢复;政府停摆期间更新照跑但无人值守;NCEI 的计算资源故障曾让更新停摆数日。这些都在状态页里留下记录,也是做自动化流水线时必须容忍的不确定性。
§8.5 许可与引用
许可这件事要说准确。NCEI 的元数据记录里,「存取约束」一栏是空的,「使用约束」一栏只写了一条引用格式。作为美国联邦政府作品,它依 17 U.S.C. §105 不受版权保护。官方页面没有给 SPDX 标识,也没有给 Creative Commons 协议。
需要留意的是上游:GHCNd 里的国际数据由各国气象部门依双边协议提交,readme 提到有一批非洲国家的数据曾被「隔离」,直到获得相应气象部门许可才公开(来源标志 Q)。这意味着「GHCNd 可自由使用」成立,但「从 GHCNd 反推出某国气象局的原始产品并再分发」未必成立。
引用格式按官方模板:
- Menne, M.J., I. Durre, R.S. Vose, B.E. Gleason, and T.G. Houston, 2012: An overview of the Global Historical Climatology Network-Daily Database. Journal of Atmospheric and Oceanic Technology, 29, 897–910. DOI 10.1175/JTECH-D-11-00103.1
- Menne, M.J., I. Durre, B. Korzeniewski, S. McNeill, K. Thomas, X. Yin, S. Anthony, R. Ray, R.S. Vose, B.E. Gleason, and T.G. Houston, 2012: Global Historical Climatology Network - Daily (GHCN-Daily), Version 3. NOAA National Climatic Data Center. DOI 10.7289/V5D21VHZ
§9 使用指引:三条路径与一份最小实现
§9.1 三种角色,三条路
| 角色 | 目标 | 推荐路径 |
|---|---|---|
| 单人分析一个城市 | 拿到该城市长序列 | 元数据找号 → 清单确认 → 单站 .dly |
| 建数据管道 | 每日增量入库 | S3 长表按站取,或 superghcnd 的差量文件 |
| 全库研究 | 一次拿全 | 全量包 + 本地解析,配清单做筛选 |
三条路的共同前提是:先把清单读进来。清单 36 MB,比全量包小两个数量级,却包含了「哪个站有什么要素、覆盖哪些年」的全部信息。跳过清单直接下载全量包,是这类数据上最常见的浪费。
§9.2 在 AI 流水线中的位置
GHCNd 在机器学习流水线里的角色通常是标签源而不是特征源:用它构造「某日某地是否高温」「某月降水是否偏少」这类监督信号,再用再分析或遥感提供空间连续的输入特征。
这个分工有物理依据:站点观测是点上的真值,再分析是面上的估计。让模型学「从面到点」的映射,是统计降尺度;让模型直接吃站点数据做空间预测,则要面对站点极不均匀带来的采样偏差。
一个务实的最小流水线是四步:按清单筛站、按日展开成表、按质控标志分级过滤、按站点坐标与外部数据连接。四步里最容易被跳过的是第三步,而它恰恰决定了模型学到的是气候信号还是录入错误。
§9.3 一份最小可跑的实现
下面这段把单站文件展开成按日的表,并做基础质检,不依赖任何第三方库:
from pathlib import Path
from collections import Counter
def load_station(path):
out = []
for line in Path(path).read_text(encoding="ascii").splitlines():
if len(line) != 269:
continue
sid, year, month, el = line[0:11], int(line[11:15]), int(line[15:17]), line[17:21]
for d in range(31):
b = 21 + d * 8
raw = line[b:b + 5].strip()
if raw in ("", "-9999"):
continue
out.append((sid, year, month, d + 1, el, int(raw),
line[b + 5], line[b + 6], line[b + 7]))
return out
rows = load_station("CHM00058362.dly")
def to_celsius(v):
return v / 10.0
tmax = [r for r in rows if r[4] == "TMAX"]
clean = [r for r in tmax if r[7] in (" ", "O", "S")]
print("TMAX 天数", len(tmax), "过滤后", len(clean))
print("质量标志分布", Counter(r[7] for r in tmax).most_common())
print("来源标志分布", Counter(r[8] for r in tmax).most_common())
print("首末日期", tmax[0][1:4], tmax[-1][1:4])
print("最高气温", max(to_celsius(r[5]) for r in clean))
在同一份上海站文件上跑一遍,输出是:11,105 个日最高温日值,其中 11,088 个未触发质控、17 个带 I 标志,最大值 40.0 摄氏度,最后一天是 2026 年 9 月 22 日。
这段代码刻意保留了两个看起来「不干净」的做法。日期存成年月日三元组而非 datetime,是因为文件里 2 月的第 29 至 31 格永远占位填 -9999,一旦漏过滤就会构造出 2 月 30 日这种不存在的日期。质量标志按白名单保留而非全部删除,是因为离群与空间一致性失败往往对应真实的极端事件。
§9.4 报告结论时最少要写四件事
| 要写的 | 为什么 | 怎么写 |
|---|---|---|
| 站号与站名 | 同名城市可能有多个站,坐标差几十公里 | 给 11 位站号与经纬度 |
| 覆盖年份与缺口 | 「1991 至 2026」不等于「每月都有」 | 给出实际月份数与缺失月份 |
| 质控处理规则 | 删与不删会改变结论 | 写明按哪些标志过滤 |
| 下载日期与版本 | 数据会变,不锁定无法复现 | 写版本串与下载日 |
这四件事里,第二件最常被漏。一个站名义上有三十五年记录,实际可能缺了三年,而这三年恰好是研究期里最热的三年——这种缺口在图上完全看不出来,在结论里却是决定性的。
§9.5 评估时怎么划分才不泄漏
GHCNd 不是分类数据集,没有现成的训练测试划分,但泄漏同样存在,形式不同。
空间泄漏最常见:相邻站的气候高度相关,若随机按站划分,测试集的站往往紧挨着训练集的站,模型实际上是在插值而不是外推。正确做法是按空间分块划分,例如按经纬度划成若干格,整格进出。
时间泄漏次之:按日随机划分会让同一天的相邻站在两集合里同时出现,模型能记住「那天整个区域都热」。正确做法是按年划分,或留出连续的年份段做外推测试。
站点泄漏最隐蔽:同一物理站因编号变更在库里出现两次,一个进了训练集,一个进了测试集。检查办法是按坐标聚类后再划分,而不是按站号。
这三件事在再分析数据上不那么突出,因为格点本来就是均匀的;在站点数据上,它们是决定模型分数的第一因素,比换模型架构重要得多。
§10 AI 使用声明
| 项目 | 内容 |
|---|---|
| 数据集性质 | 公开地面气象观测,非个人数据,不含可识别个体 |
| 建议用途 | 暴露评估、模型检验、气候态统计、教学示例、数据工程练习 |
| 不建议用途 | 直接当作格点场使用、未经质控就做趋势估计、把站点值当作城市代表值 |
| 伦理注意 | 站点坐标精确到万分之一度,与人口数据连接时可能间接定位住址,发布时应做聚合 |
| 引用要求 | 同时引用方法论文与版本 DOI,并注明所用子集 |
| 版本锁定 | 引用时写 3.35 与下载日期,避免跨版本混用站号 |
| 页面状态 | 已发布,最后核对 2026-10-29 |
常见误读
| 常见说法 | 实际情况 | 证据 |
|---|---|---|
| 「一行是一天的观测」 | 一行是一个站一个要素一个整月,31 组值 | readme 第 III 节列定义到第 269 列 |
| 「有十三万个站就有十三万条温度序列」 | 只有四万多个站有 TMAX,三分之二的站没有温度 | 清单文件按要素统计 |
| 「最早的数据是 1832 年」 | 最早是 1763 年 1 月米兰 Brera 的日最高温 | 清单起点年份,且该站文件首行有非缺测值 |
| 「降水 0 就是没下雨」 | 0 可能带微量标志 T,表示有降水但量太小 | 单站文件里有数千个 0 带 T |
| 「TAVG 就是最高最低温的平均」 | TAVG 按各站观测时次或逐时值算,算法不一 | readme 对 TAVG 的注释;2015 年才加入 |
| 「站号是永久的」 | 版本升级会改编号,3.35 改了全部加拿大站 | 状态页 2026 年 10 月条目 |
| 「下载完就能用,文件不会坏」 | 定宽文本被截断后仍然完全合法,不报错 | 服务端声明 4.8 MB,短下载仍可解析 |
| 「它是全球均匀的站点网」 | 美国占 59%,志愿雨量站占 40% | 站点元数据按国别与网络码统计 |
| 「有 CC BY 许可」 | 无 SPDX 标识,属美国联邦政府公有领域,仅要求引用 | NCEI 元数据记录的约束字段 |
| 「它能替代 ERA5」 | 站点是点,再分析是面,二者互补而非替代 | 数据单元与生成方式不同 |
| 「缺失值会被自动跳过」 | 缺测是 -9999,不处理会污染均值 | 值字段定义 |
| 「做降水研究选择最多,所以质量最好」 | 选择确实最多,但其中四成是志愿雨量站,断点与时次问题最重 | 要素站数与网络码统计 |
附录 A 要素与单位速查
| 代码 | 含义 | 单位 | 备注 |
|---|---|---|---|
| PRCP | 日降水总量 | 0.1 毫米 | 含微量标记 T 的 0 |
| SNOW | 日降雪量 | 毫米 | 北美站为主 |
| SNWD | 雪深 | 毫米 | 观测时点的积雪厚度 |
| TMAX | 日最高气温 | 0.1 摄氏度 | 覆盖约四万站 |
| TMIN | 日最低气温 | 0.1 摄氏度 | 与 TMAX 基本同集 |
| TAVG | 日平均气温 | 0.1 摄氏度 | 2015 年加入,算法因源而异 |
| TOBS | 观测时刻气温 | 0.1 摄氏度 | 判断日界的关键线索 |
| MDPR | 多日累计降水 | 0.1 毫米 | 配 DAPR 表示包含天数 |
| AWND | 日平均风速 | 0.1 米每秒 | 仅千余站 |
| WT16 | 天气现象:雨 | 布尔 | 编码出现即表示当日有该现象 |
附录 B 标志位速查
| 组 | 位数 | 取值数 | 关键取值 |
|---|---|---|---|
| MFLAG | 1 | 十余种 | 空白、T 微量、A–G 报文累加、H 逐时极值 |
| QFLAG | 1 | 14 种 | 空白通过、D 重复、G 间隙、O 离群、S 空间、X 越界、Z 修订 |
| SFLAG | 1 | 30 种 | s 中国气象局、C 加拿大、E 欧洲 ECA&D、S 报文派生、a 澳大利亚 |
附录 C 术语表
| 术语 | 含义 |
|---|---|
| GHCNd | 全球历史气候学网络逐日数据集,本文主角 |
| GHCNh | 同门的逐时与天气报时刻数据集,共用站号 |
| GSN | GCOS 基本网,全球约千站,承担气候监测基准职责 |
| HCN | 美国历史气候网,记录长、质控严 |
| CRN | 美国气候参考网,仪器与站址高度受控 |
| CoCoRaHS | 美国社区志愿雨量观测网,站点占全库四成 |
| 定宽格式 | 每字段占固定列位、不用分隔符的文本格式 |
| 哨兵值 | 用特定数值表示缺失,此处为 -9999 |
| 冻结期 | 数据在发布后不再改动的时段,本库没有严格冻结期 |
| 全量重算 | 把所有历史记录按新规则重新处理一遍 |
| 增量追加 | 只把新到的数据并入现有库 |
| 日界 | 一个观测日覆盖的时间区间,由观测时次决定 |
| 站址迁移 | 观测站从一个位置搬到另一个位置,会造成序列不连续 |
| 再分析 | 用模式与观测融合生成的格点历史场 |
附录 D 下载清单
| 文件 | 体积 | 用途 |
|---|---|---|
| ghcnd-stations.txt | 11,441,526 字节 | 站点坐标、高程、站名、网络标志 |
| ghcnd-inventory.txt | 36,400,398 字节 | 站×要素起止年 |
| ghcnd-countries.txt | 3,659 字节 | 219 行 FIPS 国家码 |
| ghcnd_all.tar.gz | 3,818,113,068 字节 | 全站月表 |
| ghcnd_gsn.tar.gz | 180,312,748 字节 | GCOS 网子集 |
| ghcnd_hcn.tar.gz | 316,479,967 字节 | 美国历史网子集 |
| ghcnd.grid.tar.gz | 894,731,876 字节 | 网格化温度距平 |
编辑说明
核验时间 2026-10-29。方法:直接读取 NCEI 产品页与 readme.txt 全文,取格式定义、要素单位、三组标志位取值与来源优先级;下载 ghcnd-stations.txt(133,041 行)、ghcnd-inventory.txt(791,313 行)与 ghcnd-version.txt,按列切片统计站点网络码、国别、要素覆盖、起止年;下载纽约中央公园、米兰 Brera、布拉格 Klementinum、霍恩派森贝格、上海、帕拉马塔六个站的月表文件,逐行核对首末日期、行宽、缺测与微量标志;用 HEAD 请求读取各打包文件的 Content-Length 与 Last-Modified;用无 token 请求验证在线接口的鉴权要求;读取 GHCNh 产品页确认两者分工;读取 NCEI 元数据记录确认存取与使用约束两栏的内容。
未覆盖:没有解压全量包,因此未统计全库观测值总数与逐元素的值分布;未做站点级代表性分析;未核对各国上游档案的完整性;未验证 Datzilla 修订记录的具体条目。文中「约 4 GB」为按 3.56 GiB 留余量的工程建议,不是官方表述。
与常见二手资料的主要差异:最早年份常被写成 1832(官方产品页那句话含「1732」与「1832」粘连的排版错误,且已被清单与文件推翻,实际为 1763);站点数常被模糊成「十万以上」,元数据行数是 133,041;有温度的站常被写成「两万五千以上」,实际 40,940;TMAX 是五个核心要素之一,TAVG 才是 2015 年才加入的扩展要素;「每行 ID YEAR MONTH ELEMENT VALUE MFLAG QFLAG SFLAG」漏掉了 31 天重复结构,是二手介绍里最容易导致解析错误的遗漏;「无需注册」只对批量下载成立,在线接口需要免费 token;全量包体积会随重打漂移,任何固定数值都会过时。
相关数据集导航
以下为站内 AI-Ready 数据集百科中与本词条共享多个主题标签的相关数据集,按相关度降序排列:
- our-world-in-data — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- wpp — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- usgs-comcat — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- mswep-v3 — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- cmip6-esgf — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- wri-global-power-plant — 共享标签:公共卫生与流行病学 / 全球健康 / 多模态
- era5-single-levels — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- oisst-v2-1 — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- ibtracs — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
- argo-gdac-floats — 共享标签:公共卫生与流行病学 / 时序数据 / 全球健康
导航说明:本章节由全站统一标签体系自动计算生成(标签重合度算法),双向可达;点击链接可跳转至对应数据集词条。

