2. 海洋盐度数据获取与格式解析

海洋盐度数据在进入质控流程之前,必须先完成“读得进、看得懂、对得上”三件事:把文件读成内存中的数组,把元数据与坐标解析清楚,再对数据完整性做初步评估。盐度观测来源多样——CTD剖面、Argo浮标、走航ADCP附带温盐、卫星遥感反演、再分析产品——它们落地的格式也各不相同。本节以最常见的 NetCDF、CSV、JSON 三类格式为主线,讲清楚读取方法、元数据检查要点、时间与空间坐标系解析,以及完整性初评的判断依据。

一、三类格式的定位与读取方式

NetCDF 是海洋盐度数据的主力格式,Argo、WOA、CMEMS、HYCOM 等产品几乎都以它分发。它的核心优势是“自描述”:变量、维度、单位、缺测值、坐标轴都写在文件头里。Python 中常用 netCDF4 或 xarray 读取。以 Argo 盐度剖面为例,典型读取代码如下:

import xarray as xr
ds = xr.open_dataset("R5900001_001.nc")
print(ds)                      # 查看维度、变量、坐标
psal = ds["PSAL"]              # 实用盐度,单位 PSU
print(psal.dims, psal.attrs)   # ('N_LEVELS',) 及 units、_FillValue
print(ds["TIME"].attrs)        # 时间单位与参考历元

CSV 多用于台站观测、航次摘录、教学数据集或质控后导出表。它没有自描述能力,列名、单位、缺测标记全靠约定,因此读取时必须显式声明缺测值并检查列名一致性:

import pandas as pd
df = pd.read_csv("station_salinity.csv",
                 na_values=["-999", "NaN", ""],
                 parse_dates=["time_utc"])
print(df.dtypes)
print(df["salinity_psu"].describe())

JSON 常见于浮标实时上报、API 接口返回和部分业务系统交换。它天然嵌套,坐标与观测值可能分层存放,需要先展开再转成表结构:

import json, pandas as pd
with open("buoy_2024.json") as f:
    raw = json.load(f)
records = raw["observations"]          # 列表,每项含 time/lon/lat/salinity
df = pd.json_normalize(records)

三种格式的读取难点不同:NetCDF 难在维度语义与坐标轴识别,CSV 难在单位与缺测约定,JSON 难在结构展开与字段命名不统一。读取完成后都应立即打印形状、类型和属性,而不是直接进入计算。

二、元数据检查:先看“说明书”再看数据

盐度数据的元数据检查至少覆盖五项:变量单位(PSU、1e-3、g/kg 还是无量纲)、缺测值(_FillValue 或 missing_value)、有效范围、坐标轴定义、数据来源与版本。单位混淆是盐度质控中最常见的隐性错误——把 1e-3 当 PSU、把 g/kg 当 PSU,数值上差异虽小,但在异常判定阈值附近足以改变结论。缺测值若未声明,-999 会被当作真实盐度参与统计,直接污染均值与极值。

检查顺序建议:先读全局属性(来源、版本、创建时间),再读变量属性(units、_FillValue、valid_range),最后读坐标变量属性(axis、positive、calendar)。任何一项缺失,都应在质控日志中记录为“元数据不完整”,而不是默认按常规处理。

三、时间与空间坐标系解析

时间坐标最常见的坑是“单位字符串 + 参考历元”的编码方式,例如 units = "days since 1950-01-01 00:00:00 UTC"。数值 27000 本身没有意义,必须结合 units 才能还原为真实时刻。xarray 通常能自动解码,但遇到非标准 calendar(如 360_day、noleap)或缺失 units 时,需要手动处理。此外要区分观测时间与剖面浮标的上浮时间、卫星过境时间,避免把不同时间基准混用。

空间坐标要确认三件事:经纬度范围与正负号约定(东经为正、北纬为正)、经度是否 0–360 与 -180–180 混用、深度轴方向(positive="down" 表示数值向下增大)。盐度剖面若深度轴方向搞反,表层与底层会被颠倒,异常识别将完全失效。对网格产品还要确认经纬度是格点中心还是格点边界。

盐度数据读取与解析流程 数据格式 NetCDF(自描述) CSV(约定列名) JSON(嵌套结构) 读取与展开 xarray / pandas 声明缺测值 嵌套字段转表 元数据检查 单位 / 缺测值 有效范围 / 版本 来源与创建时间 坐标解析 时间历元 经纬正负号 深度轴方向 数据完整性初步评估 缺测比例 · 时间连续性 · 空间覆盖 · 剖面层数 · 重复记录 输出:完整性标记(通过 / 存疑 / 退回) 异常信号 缺测率 > 20% / 时间断档 坐标越界 / 单位可疑 进入质控 元数据齐全、坐标一致 完整性标记为“通过” 不满足 满足

四、数据完整性初步评估

完整性初评不是精细质控,而是在进入异常识别前先筛掉“明显不可用”的数据。建议至少计算四项指标:一是缺测比例,按变量统计 NaN 或 _FillValue 占比,盐度剖面缺测率超过 20% 通常应标记存疑;二是时间连续性,检查相邻记录时间间隔是否出现异常断档(如 Argo 剖面间隔远超 10 天);三是空间覆盖,确认经纬度是否落在合理海域且无越界值(经度 > 360、纬度 > 90 均为非法);四是重复记录,按“时间 + 位置 + 深度”组合键去重,避免同一观测被重复计入统计。

一个可直接套用的初评检查表如下,字段按盐度数据实际需要设定:

检查项判断依据(示例阈值)处理建议
盐度缺测率> 20% 标记存疑,> 50% 退回记录比例,保留原始标记
单位一致性units 为 PSU 或 1e-3缺失或异常时暂停后续计算
时间断档相邻剖面间隔 > 30 天标记为时间不连续
经纬度合法性纬度 [-90,90],经度统一到 [-180,180]越界值置为缺测并记录
深度轴方向positive 属性与数值趋势一致方向不符时翻转深度轴
重复记录时间+位置+深度完全重复保留首条,其余标记

完成上述步骤后,应形成一条可追溯的记录:文件来源、读取时间、元数据缺失项、坐标解析结果、完整性标记。这条记录是后续盐度异常识别与质控结论的依据——没有它,任何“异常”判断都缺少可复核的起点。实践中常见的问题是跳过元数据检查直接画剖面图,图形看似正常,但单位或深度方向已经错了,异常识别自然失去意义。因此,读取、解析、初评三步应作为固定动作串联执行,而不是可选项。