1. 海洋时间序列数据获取与Python环境搭建
海洋时间序列分析的第一步,不是写模型,而是把"数据"和"工具"两件事同时准备好。海洋观测数据来源多样、格式各异,而Python生态中处理这些数据的库又各有分工。本节围绕三个问题展开:海洋时间序列数据从哪里来、用什么工具读、如何搭好一个能长期使用的科学计算环境,最后以一个真实海洋站点的数据获取任务收尾。
一、海洋时间序列数据的三大来源
按获取方式,海洋时间序列数据大致可分为三类,它们的时间分辨率、空间覆盖和误差特征差别很大,直接决定了后续分析方法的选取。
浮标与锚系观测是最"原始"的现场数据。以全球漂流浮标计划(GDP)的漂流浮标、TAO/TRITON热带大气海洋阵列锚系浮标、以及近岸海洋观测站为代表,它们通常以10分钟到1小时为间隔记录海表温度、盐度、风速、波浪等要素。这类数据时间连续性好、物理意义明确,但存在传感器漂移、生物附着、通信中断导致的缺测,且单点代表性有限。
卫星遥感提供大范围、准同步的海表信息,如AVHRR、MODIS海表温度,高度计海面高度异常,散射计风场。卫星数据的时间序列本质上是"过境采样"——同一位置每天可能只有1~2次有效观测,且受云覆盖影响产生大量空缺。使用前必须理解其重访周期与质量控制标记。
再分析数据(如ERA5、ORAS5、GLORYS)是同化观测与数值模式的产物,具有时空连续、变量齐全的优点,常被用作长时间序列分析的基础数据集。但再分析产品是模式输出而非直接观测,其趋势和极值需谨慎对待。实际工作中,常把浮标作为"真值"检验再分析,或用卫星填补浮标空间代表性的不足。
二、三个核心库的分工
requests负责"把文件拿下来"。多数海洋数据平台(如NOAA NCEI、Copernicus CDS、Argo GDAC)提供HTTP/FTP接口,用requests构造带参数的URL即可下载CSV或NetCDF文件。需要注意设置超时、分块写入和断点续传,避免大文件下载中断后重来。
xarray是处理NetCDF类多维数据的首选。它把数据组织成带命名维度和坐标的DataArray/Dataset,支持按标签索引(如ds.sel(time="2023-06-01"))、自动对齐和惰性加载。对海洋时间序列,xarray的最大价值在于"时间坐标"是一等公民,切片、重采样、分组统计都非常自然。
netCDF4更底层,适合需要直接操作变量、属性、分组,或处理xarray不支持的复杂NetCDF4特性的场景。日常分析中,通常用xarray打开文件,遇到特殊结构时再回退到netCDF4。
三、科学计算环境的搭建
推荐使用conda创建独立环境,避免库版本冲突。一个可用的最小环境如下:
conda create -n ocean_ts python=3.11 -y
conda activate ocean_ts
conda install -c conda-forge numpy pandas matplotlib xarray netcdf4 requests dask -y
其中dask用于让xarray对超大NetCDF文件进行分块并行读取,处理多年再分析数据时几乎是必需的。安装完成后,用一段短脚本验证环境是否可用:
import numpy, pandas, matplotlib, xarray, netCDF4, requests
print("numpy", numpy.__version__)
print("xarray", xarray.__version__)
print("netCDF4", netCDF4.__version__)
若各库均能正常导入并打印版本号,说明环境基本就绪。建议同时固定版本(导出environment.yml),保证分析结果可复现。
四、真实站点数据获取任务
下面以NOAA国家数据浮标中心(NDBC)的一个站点为例,完成一次完整的数据获取。NDBC的实时与历史数据以固定格式的文本文件提供,URL形如:
https://www.ndbc.noaa.gov/view_text_file.php?filename=41001h2023.txt.gz&dir=data/historical/stdmet/
其中41001是站点编号,h2023表示2023年标准气象数据。用requests下载并解析:
import requests, pandas as pd, io
url = ("https://www.ndbc.noaa.gov/view_text_file.php"
"?filename=41001h2023.txt.gz&dir=data/historical/stdmet/")
resp = requests.get(url, timeout=60)
resp.raise_for_status()
# NDBC文件前两行为表头,第二行以#开头
lines = resp.text.splitlines()
header = lines[0].split()
df = pd.read_csv(io.StringIO("\n".join(lines[2:])),
sep=r"\s+", names=header, na_values=["99.0", "999.0", "9999.0"])
df["time"] = pd.to_datetime(df[["#YY","MM","DD","hh","mm"]]
.rename(columns={"#YY":"year"}))
df = df.set_index("time").sort_index()
print(df[["WTMP","WSPD"]].describe())
这段代码做了四件事:下载、跳过注释行、把NDBC的哨兵值(如99.0、999.0)转为缺失、把分散的年月日时分列合并为时间索引。运行后应能看到WTMP(海表温度)和WSPD(风速)的统计摘要。判断获取是否成功,可检查三点:时间索引是否连续、缺失比例是否合理(NDBC常有传感器故障导致的整段缺测)、数值范围是否符合物理常识(如SST在-2~35℃之间)。
五、从文件到可分析对象
对NetCDF格式的再分析或卫星数据,读取方式略有不同。以xarray打开一个假设的月平均SST文件为例:
import xarray as xr
ds = xr.open_dataset("sst_monthly.nc")
sst = ds["sst"].sel(lat=slice(20, 30), lon=slice(110, 125))
ts = sst.mean(dim=["lat", "lon"]) # 区域平均时间序列
ts.plot()
这里sel按经纬度切片,mean沿空间维求平均得到时间序列。实际使用中要留意经度是0~360还是-180~180、纬度是递增还是递减,否则切片会得到空结果。建议在读取后先打印ds查看维度顺序和坐标范围,再决定切片方向。
至此,数据来源、读取工具和环境三件事已经打通。后续所有时间序列分析——趋势、周期、突变、相关——都建立在这一步得到的、时间轴干净且缺测已标记的数据对象之上。把这一步做扎实,比在分析阶段反复修补数据要省力得多。