Python提取NetCDF4点数据遇闰年维度索引越界报错求助
问题根因
报错本质是时间索引长度硬编码导致的越界,具体原因两点:
- 你循环时间步的上界是自己用
pd.date_range生成的自然日序列长度,闰年时这个长度是366,但新数据集的t2变量实际时间维度长度只有365——CDO读取的是NetCDF文件全局声明的时间维度长度,部分数据集的全局维度和单变量实际存储维度不一致,闰日数据可能被全局属性标记存在,但实际没有写入t2变量的存储数组里。 - 原代码没有主动读取目标变量的真实维度长度,直接用自然年天数做循环上界,遇到闰年时循环到索引365(Python索引从0开始,对应第366天)就会触发
index exceeds dimension bound错误。
另外原代码还有两个隐藏问题:一是硬切割time.units字符串取年份,不同数据集的时间单位字符串格式不一致,很容易读错年份加载错误文件;二是用df.loc[date]['t2']的链式索引写法赋值,pandas会触发SettingWithCopyWarning,大概率出现赋值不生效的问题。
修复后代码
核心修改点:
- 直接通过
num2date解码NetCDF自带的时间变量,不硬切字符串取年份 - 循环时间步时以
t2变量的实际第一维(时间维)长度为上界,完全避免越界 - 按实际日期匹配赋值,不依赖顺序索引对齐
- 修复链式索引赋值问题,新增缺失值插值逻辑适配365天格式数据集
from netCDF4 import Dataset, num2date import numpy as np import glob import pandas as pd # 扫描目录下所有nc文件 nc_file_list = [] for file in glob.glob('*.nc'): print(f"加载文件: {file}") nc_file_list.append(Dataset(file, 'r')) # 解码所有文件的真实时间序列,生成完整日期索引 all_dates = [] for ds in nc_file_list: time_var = ds.variables['time'] ds_dates = num2date(time_var[:], units=time_var.units, calendar=time_var.calendar) all_dates.extend(pd.to_datetime([d.strftime('%Y-%m-%d') for d in ds_dates])) full_date_range = pd.date_range(start=min(all_dates), end=max(all_dates), freq='D') # 读取站点列表 locations = pd.read_csv('Locations.csv') for _, row in locations.iterrows(): site_name = row['Name'] target_lat = row['Latitude'] target_lon = row['Longitude'] # 初始化当前站点的结果df site_df = pd.DataFrame(0.0, columns=['t2'], index=full_date_range) for ds in nc_file_list: # 匹配最邻近格点索引 lat_arr = ds.variables['lat'][:] lon_arr = ds.variables['lon'][:] lat_idx = np.argmin((lat_arr - target_lat)**2) lon_idx = np.argmin((lon_arr - target_lon)**2) # 读取t2变量和对应实际时间 t2_arr = ds.variables['t2'] time_var = ds.variables['time'] ds_dates = num2date(time_var[:], units=time_var.units, calendar=time_var.calendar) ds_dates_pd = pd.to_datetime([d.strftime('%Y-%m-%d') for d in ds_dates]) # 按变量实际时间长度循环,从根源避免越界 for t_idx in range(t2_arr.shape[0]): current_date = ds_dates_pd[t_idx] site_df.loc[current_date, 't2'] = t2_arr[t_idx, lat_idx, lon_idx] # 若数据集为365天格式,闰日缺失值用时间线性插值补全,不需要可注释下行 site_df = site_df.interpolate(method='time') site_df.to_csv(f"{site_name}.csv") # 关闭所有打开的nc文件 for ds in nc_file_list: ds.close()
注意事项
- 处理NetCDF数据时不要依赖工具读取的全局属性判断单变量维度,一定要在代码里打印
变量.shape确认目标变量的各维度真实长度,避免全局属性和实际存储不一致的问题。 - 如果你的新数据集是固定365天的气候态数据集,本身不存储闰日数值,修复后的代码会自动识别变量长度,不会触发越界,闰日位置可以根据业务需求选择插值补全、留空或者用相邻日期数值填充。
内容的提问来源于stack exchange,提问作者Ahmad Bilal
相关产品推荐
相关产品推荐

