使用Xarray将含三维变量的CSV转换为NetCDF文件
解决CSV转三维NetCDF(维度time, lat, lon)的问题
我需要把包含year、lat、lon、pressure字段的CSV转换成三维NetCDF文件,要求pressure变量的维度为(time, lat, lon)。但CSV的结构是每个(year, lon, lat)组合对应一个pressure值,示例如下:
year,lon,lat,pressure 1/1/00,79.4939,34.4713,11981569640 1/1/01,79.4939,34.4713,11870476671 1/1/02,79.4939,34.4713,11858633008 1/1/00,77.9513,35.5452,11254617090 1/1/01,77.9513,35.5452,11267424230 1/1/02,77.9513,35.5452,11297377976 1/1/00,77.9295,35.5188,1031160490
我的尝试与问题
最初直接尝试转换,代码如下:
import pandas as pd import xarray as xr csv_file = '.csv' df = pd.read_csv(csv_file) df = df.set_index(["year", "lon", "lat"]) xr = df.to_xarray() nc=xr.to_netcdf('netcdf.nc')
之后尝试相关方法但未成功,我认为需要先把CSV结构整理成唯一经纬度对应多时间点pressure的形式,期望结构如下:
longitude,latitude,1/1/2000,1/1/2001,1/1/2002.... 79.4939,34.4713,11981569640,... 77.9513,35.5452,11254617090,... 77.9295,35.5188,1031160490,...
试过用pd.melt转换,但写法有误:
df = pd.melt(df, id_vars=["year","lon", "lat"], var_name="year", value_name="PRESSURE")
我的目标是实现类似以下代码的效果(但原代码无法正确生成三维结构):
filename = '13.csv' colnames = ['year','lon','lat','pressure'] df = pd.read_csv(filename, names = colnames) df["year"]= pd.to_datetime(df["year"], errors='coerce') xr = df.set_index(['year','lon','lat']).to_xarray() #xr['time'].attrs={'units':'hours since 2018-01-01'} xr['lat'].attrs={'units':'degrees', 'long_name':'Latitude'} xr['lon'].attrs={'units':'degrees', 'long_name':'Longitude'} xr['pressure'].attrs={'units':'pa', 'long_name':'Pressure'} xr.to_netcdf('my_netcdf.nc')
正确解决方案
步骤1:读取并预处理数据
先读取CSV,将year转为datetime类型,确保时间维度解析正确:
import pandas as pd import xarray as xr filename = '13.csv' df = pd.read_csv(filename) # 转换year为datetime,格式匹配CSV中的月/日/两位年 df['year'] = pd.to_datetime(df['year'], format='%m/%d/%y')
步骤2:长表转宽表(核心操作)
使用pivot将长格式数据转为宽格式,让每个经纬度组合对应所有时间的pressure值:
# 以lon、lat为索引,year为列,pressure为值重塑数据 df_wide = df.pivot(index=['lon', 'lat'], columns='year', values='pressure') # 重置索引,让lon、lat回到列便于后续转换 df_wide = df_wide.reset_index()
步骤3:转换为xarray并调整维度
将宽表转为xarray Dataset,整合时间列为time维度,并调整维度顺序为(time, lat, lon):
# 转为xarray Dataset ds = xr.Dataset.from_dataframe(df_wide.set_index(['lon', 'lat'])) # 将时间列转为统一的time维度 ds = ds.to_array(name='pressure').transpose('time', 'lat', 'lon') # 添加变量属性 ds['lat'].attrs={'units':'degrees', 'long_name':'Latitude'} ds['lon'].attrs={'units':'degrees', 'long_name':'Longitude'} ds['pressure'].attrs={'units':'pa', 'long_name':'Pressure'} ds['time'].attrs={'long_name':'Time'}
步骤4:保存为NetCDF
ds.to_netcdf('my_netcdf.nc')
关键说明
- 方法选择错误:之前用
pd.melt是宽表转长表,而我们需要的是长表转宽表,pivot才是正确方法。 - 维度调整:转换为xarray后,需要通过
transpose将维度顺序调整为目标的(time, lat, lon)。 - 日期解析:如果CSV中的日期格式不同,需调整
pd.to_datetime的format参数确保解析正确。
内容的提问来源于stack exchange,提问作者HLGNT
相关产品推荐
相关产品推荐

