使用Xarray resample的map方法应用自定义函数丢失维度坐标
Xarray resample.map 维度坐标丢失问题解决
问题原因
当使用resample.map()时,若自定义函数返回的子Dataset保留了原time维度(比如示例中直接返回输入的子块,每个子块包含窗口内的多个时间点),Xarray在合并结果时会将所有子块的time维度直接拼接。由于各子块的time坐标是窗口内的局部时间,无法直接形成连续的全局坐标,Xarray会自动将time维度替换为从0开始的整数序列索引,导致原时间坐标丢失。
你调试时看到自定义函数能接收到坐标,是因为每个子块本身确实包含窗口内的局部坐标,但合并环节无法将这些局部坐标映射到resample的窗口级全局坐标。
解决方法
根据需求不同,有三种常见处理方式:
1. 对窗口进行聚合操作(返回单值结果)
如果自定义函数是对每个窗口做聚合(比如求均值、求和、取极值),修改函数返回聚合后的标量/一维结果,Xarray会自动将resample的窗口起始时间作为新的time坐标:
import numpy as np import pandas as pd import xarray as xr def custom_fn(ds): # 示例:返回窗口内的均值,可替换为自定义聚合逻辑 return ds.mean(dim='time') if __name__=='__main__': times=pd.date_range( '2000-01-01 00:00', '2000-01-05 23:59:59', freq='5min', ) data1=np.arange(len(times)) data2=data1+1 data=xr.Dataset( data_vars={ 'data1':(['time',], data1,), 'data2':(['time',], data2,), }, coords={'time':times} ) new=data.resample(time='30min').map(custom_fn) print(new) # 此时time坐标为各窗口的起始时间
2. 保留窗口内的所有数据(新增窗口内时间维度)
如果需要保留每个窗口内的所有原始数据,可将原time维度重命名为窗口内的局部时间维度,让resample的窗口时间作为新的顶级time坐标:
import numpy as np import pandas as pd import xarray as xr def custom_fn(ds): # 将原time维度重命名为window_time,保留窗口内的时间点 return ds.rename(time='window_time') if __name__=='__main__': times=pd.date_range( '2000-01-01 00:00', '2000-01-05 23:59:59', freq='5min', ) data1=np.arange(len(times)) data2=data1+1 data=xr.Dataset( data_vars={ 'data1':(['time',], data1,), 'data2':(['time',], data2,), }, coords={'time':times} ) new=data.resample(time='30min').map(custom_fn) print(new) # 此时Dataset包含两个维度: # - time: 各resample窗口的起始时间 # - window_time: 窗口内的5分钟间隔时间点
3. 手动恢复窗口坐标(特殊场景)
如果必须保留原time维度的全局坐标,可先提取resample的窗口时间,再手动赋值给结果(仅适用于每个窗口返回结果长度一致的情况):
import numpy as np import pandas as pd import xarray as xr def custom_fn(ds): return ds if __name__=='__main__': times=pd.date_range( '2000-01-01 00:00', '2000-01-05 23:59:59', freq='5min', ) data1=np.arange(len(times)) data2=data1+1 data=xr.Dataset( data_vars={ 'data1':(['time',], data1,), 'data2':(['time',], data2,), }, coords={'time':times} ) # 先获取resample窗口的时间戳 resampler = data.resample(time='30min') window_times = list(resampler.groups.keys()) # 执行map操作 new = resampler.map(custom_fn) # 手动替换time坐标为窗口时间 new = new.assign_coords(time=window_times) print(new)
内容的提问来源于stack exchange,提问作者RogUE
相关产品推荐
相关产品推荐

