简介:来自Met Office Hadley Centre的全球海水表面温度与海冰浓度数据集,采用NetCDF格式存储,面向需要处理海洋气候数据的初学者与研究人员,配套入门级Python代码,方便快速查看变量情况与数据构造,简单易懂。压缩包为7z格式,共3个文件,包含2个nc数据文件(分别为海温与海冰数据)和1个py处理脚本,总大小约167.98MB。已有4923人学习下载,足见其实用性。读者可通过这份资源直接获得海温与海冰原始观测数据,并参考附带的Python脚本学习读取NetCDF文件、查看维度、变量名和属性信息的方法,理解数据组织逻辑,为后续绘制海温/海冰分布图、做时间序列分析打下基础。整体内容聚焦数据读取与结构探索,省去自行查找和调试的麻烦,适合作为NetCDF与海洋气象数据处理的入门实践材料。 做海洋和极地相关研究的人,一定绕不开两个基础变量:海水表面温度和海冰浓度。不管是验证气候模式、分析北极海冰变化,还是做渔业资源分布预测,拿到一份空间连续、时间一致、已经做好网格化的数据集,能省下大半的预处理时间。我这次用的“全球海水表面温度和海冰浓度数据集(2020a专用)”,就是这样一份体积不大、但能直接进模型和可视化流程的基础数据。它解决的痛点很明确:把散落在不同产品里的海温和海冰拼到一起处理时,坐标系、分辨率、时间戳往往对不齐,而这份数据集把两者放在了同一张网格上,省掉了大量坐标系匹配的繁琐操作。
这个数据集适合几类人:一是刚入门做海洋遥感数据处理的同学,想绕开从原始L2级数据开始下载、拼接、定标的漫长流程;二是做气候诊断分析、需要快速绘制某一年全球海温场和海冰范围图的从业者;三是需要一套标准化数据做模式初始化或验证的数值模拟方向的研究者。不管你是哪一类,只要能熟练读写NetCDF文件,这份数据集就能直接接入你的Python工作流。
1. 数据集整体思路:为什么要让海温和海冰住在同一份文件里
1.1 海温和海冰在物理上就分不开
海水表面温度(SST)和海冰浓度(SIC)看似是两个独立变量,但物理过程决定它们必须成对出现。海冰的生长和消融会直接影响海气之间的感热和潜热交换,而海洋表层的热量变化又会反过来控制冰缘线的进退。特别是在北极海冰边缘区,海温每升高零点几度,冰缘位置就会发生显著摆动。
正因为这种强耦合关系,气候模式和再分析产品在输出变量时,往往会选择“状态场成组输出”的策略。这份数据集进一步把两个变量放进了同一个文件、同一张经纬度网格里,避免了传统流程中最烦人的一步:海温数据来源于A产品,海冰数据来源于B产品,两者的网格起点、分辨率定义、缺测值编码各不相同,需要另外写一套插值和掩膜代码才能对齐。而这里直接就是一套网格两套变量,时间维完全一致,拿到手就能做联合分析。
1.2 “2020a”版本号到底说明什么
数据集的名称里带“2020a”,这是典型的版本管理习惯,类似软件发布里的主版本加修订号。2020代表这个数据集的覆盖版本年份或发布周期,a则代表该年份的第一个修订版本。这类命名的好处在于:当你后续复算或者跟别人对比结果时,能精确知道用的是哪一版数据,避免版本漂移带来的结论不一致。
从实际使用场景看,这份数据非常适合做2020年前后的气候态分析。无论你是要画2020年夏季北冰洋海冰最小范围,还是计算某个月全球海温距平,这份数据集都能提供直接可用的输入。需要说明的是,具体获取渠道可以是欧洲哥白尼计划的气候数据存储门户,也可以是各类提供再分析产品的数据中心,检索“SST and sea ice concentration dataset”时建议带上版本号“2020a”,才能定位到正确的条目。
2. 数据内部结构逐项拆解:拿到NetCDF文件后先看什么
2.1 核心变量与单位
打开文件后,你会看到两个核心变量,它们在命令行或者xarray里都以短名字出现,建议先弄懂各自的物理意义。
我拿到的文件里,海温变量名通常是sosstsst,这是海洋再分析领域常见的标准名称,含义是“sea surface temperature”,单位一般是开尔文(K),少部分产品给的是摄氏度。海冰浓度变量名通常是siconc,含义是“sea ice concentration”,单位是百分比或0到1之间的比例。两者阅读代码习惯不同,后续统计时要特别留意,比如计算海冰面积时,如果变量以百分比存储,需要先除以100再乘网格面积。
坐标维度方面,典型结构是(time, latitude, longitude)。经纬度网格是均匀规则网格,通常是0.25度或者0.5度分辨率。分辨率的含义要理解清楚:在0.25度网格下,赤道附近一个网格大约对应27.8公里见方,而到了高纬度地区,经度方向实际距离会按cos(latitude)急剧缩小,这也是为什么极地研究里经常强调“再投影”的重要性。
2.2 缺失值、陆地掩膜与文件属性
网格化海温海冰数据最大特点是存在大量“无效格点”。陆地是其中一个原因,极地海域在冬季还会出现“数据缺失但并非陆地”的情况。在NetCDF里,这类无效值通常采用两种方式编码:一种是设置_FillValue或missing_value属性,另一种是给变量增加一个辅助掩膜变量。
实操中我的习惯是拿到文件后立刻执行一行代码检查变量的编码信息:
import xarray as xr ds = xr.open_dataset("global_sst_sic_2020a.nc") print(ds["sosstsst"])这一步能快速看到_FillValue、scale_factor、add_offset等关键属性。尤其要注意scale_factor和add_offset,它们通常用于把文件内存储的整型数据还原为真实物理量。如果你发现读出来的数值区间离谱,多半是漏了这两步量纲还原。xarray和netCDF4库在读取时会自动应用编码信息,但如果你使用二进制读取方式或者某些旧脚本,就要手动处理。
3. 从下载到出图的完整实操:一天内的SST与SIC联动可视化
3.1 环境准备与依赖库清单
我的标准环境是Python 3.9以上,核心依赖包括:xarray(数据容器)、netCDF4(NetCDF底层读取)、numpy(数组运算)、matplotlib(绘图)、cartopy(地图投影)。如果只是快速看看数据,前三者就够了,但要做出版级地图,cartopy必不可少。
我建议用conda创建独立环境,避免依赖冲突。实测下来,conda install -c conda-forge xarray netcdf4 cartopy matplotlib一行搞定所有依赖,省去手动解决matplotlib和cartopy的变形投影问题。
3.2 提取特定时次并绘制全球海温场
读取数据时,不要试图一次把整个时间维载入内存。这份数据虽然不太大,但养成惰性加载的好习惯能避免以后处理GB级数据时的内存崩溃。我通常是先按时间切片:
import xarray as xr import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature import numpy as np ds = xr.open_dataset("global_sst_sic_2020a.nc") # 选择2020年7月1日作为例子,method="nearest"避免时间匹配失败 sst_1d = ds["sosstsst"].sel(time="2020-07-01", method="nearest") sic_1d = ds["siconc"].sel(time="2020-07-01", method="nearest") # 将开尔文转为摄氏度,更直观 sst_c = sst_1d - 273.15这里用method="nearest"是个容易被忽略但非常关键的细节。时间维度上不同版本的存储方式可能不同,有时是"2020-07-01T00:00:00",有时是"2020-07-01T12:00:00",精确匹配容易报错,用最近邻匹配最稳妥。
接下来绘图。我需要把海温和海冰画在同一张图上,既能看冰缘位置,又能看海温经向分布:
fig, ax = plt.subplots( figsize=(12, 6), subplot_kw={"projection": ccrs.PlateCarree()}, ) # 海温填色 pcm = ax.pcolormesh( sst_c["longitude"], sst_c["latitude"], sst_c, cmap="coolwarm", vmin=-2, vmax=30, shading="auto", ) # 海冰浓度大于15%的区域叠加上白 sic_masked = sic_1d.where(sic_1d > 0.15) ax.pcolormesh( sic_masked["longitude"], sic_masked["latitude"], sic_masked, cmap="Greys", vmin=0, vmax=1, shading="auto", alpha=0.8, ) ax.add_feature(cfeature.COASTLINE, linewidth=0.5) ax.add_feature(cfeature.LAND, color="lightgray") ax.set_title("SST and SIC on 2020-07-01") plt.colorbar(pcm, ax=ax, label="SST (degC)") plt.show()这段代码里最关键的是海冰浓度掩膜。为什么要设阈值15%?这是海冰遥感分析里常用的一个经验阈值,低于15%的格点通常被认为是开阔水域与浮冰的混合区域,而在净冰面积统计中,15%条约是国际海冰数据比较的标准约定。当然如果你做的是模式验证或局地过程研究,这个阈值可以调整,但不建议低于10%,否则噪声会显著增大。
3.3 区域平均与海冰面积估算
实际研究中光看图不够,还需要定量统计。最常见的需求是计算北极海冰总面积(即所有网格冰浓度加权总面积)。我一般用下面这段代码验证数据自洽性:
# 计算海冰面积,假设网格是规则等经纬度,实际高精度建议用cellsize文件 lat = ds["latitude"].values lon = ds["longitude"].values dlat = np.abs(np.diff(lat)).mean() dlon = np.abs(np.diff(lon)).mean() # 单位转换:1度纬度约111km,经度方向按cos(lat)修正 grid_area = 111e3 * dl at * 111e3 * dlon * np.cos(np.deg2rad(lat)) grid_area = grid_area[None, :, None] # 对齐维度 sic_values = ds["siconc"].sel(time="2020-07-01", method="nearest").values # 如果siconc是百分比需除以100;假设已经是比例存储 total_ice_area = np.nansum((sic_values > 0.15) * sic_values * grid_area)计算面积时有个极容易踩的坑:直接用np.cos(np.deg2rad(lat))修正在所有经度上的统一假设。这个假设只有在规则经纬度网格上成立,并且当网格分辨率较粗时,误差会变大。严谨做法是使用数据自带的质量格点面积文件,但如果只是做一个粗略估算,这个简化方式在0.25度网格下的误差一般可以接受。
在实际处理中,我还喜欢对特定海域做“区域裁剪+时间序列降维”。比如只看挪威海到巴伦支海这段大西洋入口区域的SST变化,这时用xarray的sel(latitude=slice(...), longitude=slice(...))一步到位,再mean(dim="time")得到区域平均时间序列。
4. 高频踩坑点与排查记录:处理全球SST/SIC数据常见的坑
4.1 经纬度顺序和坐标朝向:网格一翻转就全错
这是所有NetCDF数据处理里最容易翻车的一环。不同来源的数据,latitude可能从小到大排列,也可能从大到小;longitude可能用 -180到180,也可能用 0到360。如果不检查就pcolormesh,你只会看到一张上下颠倒或者横向撕裂的图。
排查方法很简单,打开文件后看一眼变量数值边界:
print(ds["latitude"].values[0], ds["latitude"].values[-1]) print(ds["longitude"].values[0], ds["longitude"].values[-1])如果发现纬度递减,手动ds = ds.sortby("latitude")即可。如果经度范围是0到360而你习惯 -180到180,可以用ds.assign_coords(longitude=(ds.longitude + 180) % 360 - 180).sortby("longitude")来转换。有个细节:经度转换后可能要循环移动数组,这时roll方法比重新索引要更高效。
4.2 海冰浓度0值、缺测值与无冰区要分清楚
海冰浓度变量里,0、100、NaN看起来很简单,但在统计时如果不加区分会造成严重偏差。0代表该网格没有海冰,是有效值;NaN或_FillValue代表该网格未参与反演,可能是陆地、湖泊、或因为云覆盖导致的传感器盲区。如果直接对含有NaN的数组求和,结果为NaN;如果直接全量统计,又可能把巨大的陆地掩膜区域当成了0%海冰面积,导致总面积严重偏大。
我的经验是建立三层掩膜逻辑:第一层排除陆地(通常使用数据集自带的地海掩膜变量);第二层把NaN替换为0;第三层再按阈值提取冰区。这三步缺一不可,否则面积统计会出现系统性偏差。
4.3 海表温度的垂直定义:SST不是随便一个表面温度
SST听起来直观,但不同产品测量的深度其实是不同的。有的红外遥感反演的海表温度是“皮肤温度”,代表海面几十微米内的温度;有的微波数据代表的是海面下约1厘米的水温;而锚定浮标测的则可能是水下1米甚至更深的水温。在昼夜温差大的低风区,皮肤温度和次表层温度差值可以达到0.3到0.5摄氏度。
所以,如果你用这份数据集跟现场浮标数据做对比验证,人为设定严格的阈值(比如要求误差低于0.1度)往往不现实。我更建议关注空间梯度和季节变化的对应关系,尤其在极地融冰期,SST在冰缘附近通常在零下1.8度左右波动,而开阔水域可能已经到2度以上,这种对照关系比绝对值的精确匹配更具物理意义。
4.4 北极夏季海冰范围接近最小值时,边缘噪声严重
2020年北极海冰范围在9月份达到年度最小值,这一时期的冰缘附近会出现大量“碎冰带”,海冰浓度在15%到50%之间跳变,格点间的空间连续性很差。这时如果做平滑或者等值线提取,经常会看到破碎的等值线片段。我建议提取冰缘线前先做一次轻微的高斯平滑,或者直接改画海冰浓度填色图,而不是一味依赖冰缘等值线。
顺带分享一个我自己常用的小技巧:为了快速了解数据质量,画一条早夏(6月)和一条晚夏(9月)的海冰浓度剖面线,沿某个固定经度从80度往北看到底,如果出现剧烈的锯齿状跳变,基本可以判断数据存在反演噪声。这种剖面图比平面图更能定位异常区。
5. 数据应用的实际体验与进一步扩展思路
用了这份数据大概几个月后,我的整体感受是:它在做全球尺度的快速诊断时非常顺手,省去了海温和海冰拼接的时间成本。对于一个需要经常出图、跑统计、写报告的分析工作来说,这节省的不仅仅是几分钟,而是整个流程的复杂度。特别是当你要同时关注北半球海冰和副热带海温的关系时,统一网格的优势就会充分体现。
我在实际使用中发现,这套数据还有一个很有价值的扩展方向:可以做月平均场距平分析。数据的时间维足够长时,你完全可以把气候态和某个特定年份做差,再配合海冰浓度距平,检查海冰异常区是否对应海温异常暖核或冷核。这种相互作用分析不需要额外配准,因为底层坐标本来就是一套。
最后再分享一个小技巧:尽量把预处理封装成函数,比如读取变量、经度归一化、NaN转0、掩膜提取四个步骤打包成load_sst_sic(path, time)。这样每次拿到新月份或新版本数据时,一行就能完成标准化操作。数据集本身的版本变化、网格细节可能给你带来意外惊喜,但标准化的预处理流程能让你的分析结论永远建立在可控的数据基础上。
本文还有配套的精品资源,点击获取