在python中使用NetCDF4库将时间序列数据处理为统一格式数据详细流程
文章目录
概要
NetCDF4格式因其自描述性、多维数组支持和平台独立性等特点,特别适合存储和处理科学数据,尤其是那些涉及时空变化的大型、复杂数据集。
在气象和气候数据、海洋学数据、地球系统科学、遥感等领域都有广泛应用
本文用一个海洋浮标自动采集上来的NetCDF4格式数据来详细说明一下数据处理过程,最终得到可供深度学习模型输入的标准数据格式。
示例数据集
本次处理流程使用的数据集是海浪浮标采集的NetCDF4格式数据,该数据集从位于挪威Sulafjorden的挪威气象研究所收集,记录了挪威Sulafjorden峡湾附近的海面浪高、海浪周期以及海浪传播角度等多项数据。该数据集涵盖了从2017年1月1日到2020年2月29日的三年数据。这里我们只选取其中一个数据集作为演示,即2017年1月1日浮标记录数据集。
数据集放在文章顶部,大家可以直接下载拿去复现下处理流程。
相关库:NetCDF4
在Python中,netCDF4 是一个用于读取和写入 NetCDF 文件的库,它支持所有版本的 NetCDF 格式(包括经典的 NetCDF 3 和现代的 NetCDF 4),并且能够处理基于 HDF5 的 NetCDF4 文件。这个库是 Unidata 组织开发的 netCDF 库的一个 Python 接口,提供了与 C 库类似的功能。
使用pip命令来安装NetCDF4库:
pip install netCDF4
或者使用conda来安装:
conda install -c conda-forge netcdf4
处理过程
NetCDF 4数据通常以.nc后缀的文件保存,首先我们导入代码相关库
import pandas as pd
import netCDF4 as nc
下面我们逐项介绍一下对NetCDF4数据的处理流程
首先从文件中提取一下记录时间,确定一下精确的时间序列表,毕竟我们是做时间序列为主的数据格式处理,时间序列自然就成为重中之重。
#这里我们的数据地址是:
#file_path = ./201701_E39_D_Breisundet_wave.nc
# 从文件名中提取年和月
file_name = file_path.split('\\')[-1]
year = int(file_name.split('_')[0][:4])
month = int(file_name.split('_')[0][4:6])
# 确定每个月的天数
days_in_month = pd.Timestamp(year=year, month=month, day=1).days_in_month
# 创建完整的时间序列
# 这里是因为数据记录就是用十分钟为时间间隔,所以我们也把最终处理好的数据时间间隔设置为10min
time_freq = '10min'
full_time_range = pd.date_range(
start=f'{year}-{month:02d}-01 00:00:00',
end=f'{year}-{month:02d}-{days_in_month} 23:50:00',
freq=time_freq
)
这样处理好后,full_time_range就是当月从1日00:00:00开始到最后一天23:50:00结束的以十分钟为间隔的时间序列空表,方便我们后面将想要的数据以时间为索引来填充进去。
至于要这样大费周章创建一个时间序列表的原因是因为,NetCDF4数据格式的时间计量方式是以据某一个指定时间点过的秒数来计算的,我们使用debug就可以在数据格式中看到这一点。如下图:
读取数据集,把NetCDF4里的时间转换成正常的时间序列表。顺便把我们需要的浪高、海浪周期、海浪方向数据都给读取出来,代码如下:
with nc.Dataset(file_path, 'r') as ds:
# 获取时间变量
time_var = ds.variables['time'][:] # 假设时间变量名为 'time'
time_units = ds.variables['time'].units # 获取时间单位
time_calendar = ds.variables['time'].calendar if hasattr(ds.variables['time'], 'calendar') else 'standard'
# 转换为标准的 Python datetime
file_time = nc.num2date(time_var, units=time_units, calendar=time_calendar)
file_time = pd.to_datetime([t.isoformat() for t in file_time]) # 转换为 ISO 格式后解析为 pandas 时间戳
Hs = ds['Hm0'][:] # 数据中波高数据变量名为 'Hm0'
Tm = ds['tm02'][:] # 数据中平均周期数据变量名为 'tm02'
dirm = ds['mdir'][:] # 数据中波向数据变量名为 'mdir'
其中使用的 nc.num2date(time_var, units=time_units, calendar=time_calendar) 函数是一个很好用的时间格式转换方式。
把时间格式转换过来之后,我们就可以开始把提取到的所需数据填充进去,代码如下:
# 创建填充后的时间对齐数据框架
filled_data = pd.DataFrame(index=full_time_range)
# 将每个数据对齐到完整时间序列,并填充缺失数据为 NaN
hs_df = pd.DataFrame({'Hs': Hs}, index=file_time)
tm_df = pd.DataFrame({'Tm': Tm}, index=file_time)
dirm_df = pd.DataFrame({'dirm': dirm}, index=file_time)
# 使用 join 对齐数据
merged_data = filled_data.join(hs_df).join(tm_df).join(dirm_df)
# 打印填充后的形状
print("填充后的形状:", merged_data.shape)
# 返回填充后的数据
return merged_data
最终我们得到清理好的数据格式,以时间序列为索引记录浮标采集的各类数据,方便后面进行数据嵌入。数据格式如下图:
完整代码
这里直接把可执行完整代码放在下面,大家运行时记得下好数据集,把数据放在指定文件地址下面即可运行。
import netCDF4 as nc
import os
import pandas as pd
import numpy as np
import wave_filed_data_prepare
def fill_time_and_data(file_path):
# 从文件名中提取年和月
file_name = file_path.split('\\')[-1]
year = int(file_name.split('_')[0][:4])
month = int(file_name.split('_')[0][4:6])
# 确定每个月的天数
days_in_month = pd.Timestamp(year=year, month=month, day=1).days_in_month
# 创建完整的时间序列
time_freq = '10min'
full_time_range = pd.date_range(
start=f'{year}-{month:02d}-01 00:00:00',
end=f'{year}-{month:02d}-{days_in_month} 23:50:00',
freq=time_freq
)
# 读取文件中的时间数据和其他数据
with nc.Dataset(file_path, 'r') as ds:
# 获取时间变量
time_var = ds.variables['time'][:] # 假设时间变量名为 'time'
time_units = ds.variables['time'].units # 获取时间单位
time_calendar = ds.variables['time'].calendar if hasattr(ds.variables['time'], 'calendar') else 'standard'
# 转换为标准的 Python datetime
file_time = nc.num2date(time_var, units=time_units, calendar=time_calendar)
file_time = pd.to_datetime([t.isoformat() for t in file_time]) # 转换为 ISO 格式后解析为 pandas 时间戳
Hs = ds['Hm0'][:] # 数据中波高数据变量名为 'Hm0'
Tm = ds['tm02'][:] # 数据中平均周期数据变量名为 'tm02'
dirm = ds['mdir'][:] # 数据中波向数据变量名为 'mdir'
# 创建填充后的时间对齐数据框架
filled_data = pd.DataFrame(index=full_time_range)
# 将每个数据对齐到完整时间序列,并填充缺失数据为 NaN
hs_df = pd.DataFrame({'Hs': Hs}, index=file_time)
tm_df = pd.DataFrame({'Tm': Tm}, index=file_time)
dirm_df = pd.DataFrame({'dirm': dirm}, index=file_time)
# 使用 join 对齐数据
merged_data = filled_data.join(hs_df).join(tm_df).join(dirm_df)
# 打印填充后的形状
print("填充后的形状:", merged_data.shape)
# 返回填充后的数据
return merged_data
#注意这里换成你放数据集的文件地址!
file_path = 'A:\\pycharmproject\\OW-DGM\\Dataset\\buoy\\Breisundet_wave\\201701_E39_D_Breisundet_wave.nc'
if __name__ == '__main__':
fill_time_and_data(file_path= file_path)
结语
本文是一个项目复现中的小知识节点,完整的项目复现会很快跟大家见面!
本文仅在个人学习过程中所写就,难免有错误与疏漏,请大家不吝赐教。
如果这篇文章对你有所帮助,请点赞收藏!
作者:听风知秋