1. 课程导入与科学数据全景
在科学计算中,数据格式从来不是无关紧要的“容器”。同一份温度场数据,存成 CSV 可能只有几十兆,存成 HDF5 却能在毫秒级完成切片读取;同一批气象预报结果,用 NetCDF 交付能被气候社区直接复用,用私有二进制交付则往往需要额外写一份解析器。格式选择直接影响存储成本、读取性能、工具兼容性和协作效率。本课程要解决的,正是“不同格式之间如何正确转换、如何保持语义不丢失、如何让异构工具链协同工作”这一组问题。
一、科学数据格式的四个家族
面对众多扩展名,先按“数据如何被组织和解释”归类,比逐个记忆格式更有效。可以分成四个家族:
- 纯文本格式:CSV、TSV、JSON、YAML、PLAIN 文本。优点是通用、可读、易调试;缺点是体积大、解析慢、缺乏类型与维度信息。CSV 甚至不规定缺失值写法,空串、
NA、-9999都可能出现。 - 自描述二进制格式:NetCDF、HDF5、Zarr、Parquet、Arrow。它们把“数据 + 元数据”打包在一起,能表达多维数组、数据类型、维度坐标、单位、缺失值掩码和分块布局。
- 无描述二进制格式:原始
.bin、Fortran 无格式流、自定义结构体转储。只有读写双方约定好字节序、类型宽度和排列顺序才能解析,跨平台极易出错。 - 领域专用格式:FITS(天文)、GRIB(气象)、DICOM(医学影像)、LAS/LAZ(点云)。它们在通用容器之上叠加了行业约定的头段与语义。
需要特别区分“自描述”与“自带坐标语义”。Parquet 是自描述列式格式,擅长表格型数据,但它本身不表达“这个维度是时间、单位是小时”;NetCDF 和 HDF5 则可以通过维度变量、units、scale_factor 等属性承载物理语义。转换时若只搬数值不搬属性,数据看似完整,语义却已经丢失。
二、互操作挑战究竟难在哪里
格式转换的困难很少在“读字节、写字节”这一步,而集中在语义映射。以下五类问题几乎贯穿全部课程:
- 维度顺序约定不一致。NetCDF 习惯
(time, lat, lon),图像库常按(H, W, C),Fortran 内存按列优先而 C 按行优先。转置写错不会报错,只会让结果“看起来像噪声”。 - 缺失值与填充值。NetCDF 用
_FillValue,HDF5 常用属性约定,Parquet 用 null。若把-9999当真实温度参与平均,统计结果会被严重拉低。 - 类型与精度。float32 转 float64 无损,反向则可能溢出;整型无符号与有符号混用、字节序(大端/小端)不一致,都会导致数值错乱。
- 单位与坐标。开尔文与摄氏度、米与千米、时间原点(
days since 1970-01-01与hours since 2000-01-01)必须显式换算,否则数据“正确但含义错误”。 - 分块与压缩。HDF5 的 chunk 布局、Zarr 的分块目录、Parquet 的 row group,决定了随机访问与顺序扫描的性能差异,转换时若忽略会带来数量级的性能变化。
三、一个可操作的转换示例
假设我们有一份 NetCDF 气温数据 tas.nc,变量 tas 形状为 (time=24, lat=180, lon=360),单位 K,含 _FillValue = -9999。目标是把其中第 0 个时刻转成 Parquet 供表格工具分析。关键步骤不是简单写出,而是先做语义处理:
import xarray as xr
ds = xr.open_dataset("tas.nc")
t0 = ds["tas"].isel(time=0) # 取第 0 时刻,形状 (lat, lon)
t0 = t0.where(t0 != ds["tas"].attrs.get("_FillValue", -9999)) # 缺失值转 NaN
t0 = t0 - 273.15 # K → ℃,单位换算
df = t0.to_dataframe(name="tas_c").reset_index() # 展开为 lat/lon/tas_c 三列
df.to_parquet("tas_t0.parquet", index=False)
这段代码体现了三个原则:先按维度切片再展开,避免把三维数组硬塞进表格;显式处理缺失值,不让填充值污染统计;显式换算单位并在列名中标注 tas_c。转换完成后应做校验:行数是否等于 180 × 360 = 64800,tas_c 的取值范围是否落在合理区间(例如 -60 至 50 ℃),NaN 比例是否与原始缺失比例一致。只有这三项都对上,才能认为转换在语义上是可信的。
四、课程目标与学习路径
本课程围绕“看懂格式、正确转换、验证结果、工程落地”四条主线展开。学习路径建议如下:先建立格式分类与元数据模型的基本认知(第 1–6 章),再掌握文本与二进制之间的读写和类型处理(第 7–12 章),随后进入 HDF5、NetCDF、Zarr、Parquet 之间的多维与列式互转(第 13–20 章),最后覆盖大规模数据的分块、并行、云存储与流水线工程化(第 21–30 章)。
学习时请始终带着三个问题:这份数据的维度与坐标是什么?它的缺失值、单位、类型如何表达?转换后我用什么指标验证没有丢信息?把这三个问题变成习惯,比记住任何单一 API 都更有价值。