从 netcdf 文件中获取每个月的每小时平均值
Posted
技术标签:
【中文标题】从 netcdf 文件中获取每个月的每小时平均值【英文标题】:Get hourly average for each month from a netcdf file 【发布时间】:2018-09-12 04:38:42 【问题描述】:我有一个时间维度的 netCDF 文件,其中包含 2 年的每小时数据。我想对其进行平均以获得每个月一天中每个小时的小时平均值。我试过这个:
import xarray as xr
ds = xr.open_mfdataset('ecmwf_usa_2015.nc')
ds.groupby(['time.month', 'time.hour']).mean('time')
但我收到此错误:
*** TypeError: `group` must be an xarray.DataArray or the name of an xarray variable or dimension
我该如何解决这个问题?如果我这样做:
ds.groupby('time.month', 'time.hour').mean('time')
我没有收到错误,但结果的时间维度为 12(每个月一个值),而我想要每个月的小时平均值,即 12 个月的每个月有 24 个值。数据在这里:https://www.dropbox.com/s/yqgg80wn8bjdksy/ecmwf_usa_2015.nc?dl=0
【问题讨论】:
我相信ds
是xarray.Dataset 而不是netCDF4.Dataset,对吗?
请提供一些示例数据,并说明在没有数据的情况下会发生什么。如果要考虑丢失的数据,也需要resample
@SiggyF,你说得对,ds 是通过读取 netCDF 文件生成的 xarray.Dataset
@MaartenFabré,我将尝试获取一个示例数据集(完整的数据集大小为几个 GB)。您可以假设没有丢失数据
一个带有虚拟(例如随机)数据的最小示例通常效果最好。虽然专注于 Pandas,但这个问题/答案可能对此有所帮助:***.com/questions/20109391/…
【参考方案1】:
不是 python 解决方案,但我认为这是在 bash 脚本循环中使用 CDO 的方法:
# loop over months:
for i in 1..12; do
# This gives the hourly mean for each month separately
cdo yhourmean -selmon,$i datafile.nc mon$i.nc
done
# merge the files
cdo mergetime mon*.nc hourlyfile.nc
rm -f mon*.nc # clean up the files
请注意,如果您的数据不是在一月份开始,那么您将在最终文件时间中获得“跳跃”...我认为可以通过在 yhourmean 命令之后设置年份来排序,如果这是一个问题你。
【讨论】:
感谢@Adrian,我正在寻找 python 解决方案,但感谢您的努力【参考方案2】:这个
import xarray as xr
ds = xr.open_mfdataset('ecmwf_usa_2015.nc')
print ds.groupby('time.hour' ).mean('time')
我得到了这样的东西:
尺寸:(小时:24,纬度:93,经度: 281) 坐标:
longitude(经度) float32 230.0 230.25 230.5 230.75 231.0 231.25 ... * 纬度(纬度) float32 48.0 47.75 47.5 47.25 47.0 46.75 46.5 ... * 小时(小时) int64 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ...李>
我想这就是你想要的。
【讨论】:
我也是这么想的。但是这是24 .OP想要24*12【参考方案3】:你得到 TypeError: group
must be an xarray.DataArray or the name of an xarray variable or dimension 因为 ds.groupby() 应该采用 xarray dataset variable or array ,你传递了一个变量列表。
您有两种选择:
1。 xarray bins --> 按小时分组
参考文档分组group by documentation 并将数据集转换为splits
或bins
然后应用groupby('time.hour')
这是因为按月应用 groupby,然后按小时逐一或按在一起应用聚合所有数据。如果您将它们拆分为月份数据,您将按每个月的平均值应用分组。
您可以尝试文档中提到的这种方法:
GroupBy:拆分应用组合
xarray 支持使用与 pandas 相同的 API 的“group by”操作 实施拆分应用组合策略:
将您的数据分成多个独立的组。 => 使用groupby_bins
按月拆分它们 对每个组应用一些功能。 => 申请分组 将您的组重新组合成一个数据对象。 **应用聚合函数mean('time')
2。将其转换为 pandas 数据框并使用 group by
警告:并非所有 netcdf 都可以转换为 panda 数据帧,转换时可能会丢失元数据。
通过df = ds.to_dataframe()
将ds转换成pandas数据框并使用
根据需要使用pandas.Grouper
like 进行分组
df.set_index('time').groupby([pd.Grouper(freq='1M'), 't2m']).mean()
注意:我看到了几个使用 pandas.TimeGrouper
的答案,但它已被弃用,现在必须使用 pandas.Grouper
。
由于您的数据集太大,并且问题没有最小化数据并且处理它会消耗大量资源,我建议您在 pandas 上查看这些示例
-
group by weekdays
group by time
groupby-date-range-depending-on-each-row
group-and-count-rows-by-month-and-year
【讨论】:
【参考方案4】:如果你还没有解决问题,你可以这样做:
# define a function with the hourly calculation:
def hour_mean(x):
return x.groupby('time.hour').mean('time')
# group by month, then apply the function:
ds.groupby('time.month').apply(hour_mean)
这与@Prateek 给出的第一个选项中的策略相同,并且基于文档,但是文档对我来说不是很清楚,所以我希望这有助于澄清。您不能将 groupby 操作应用于 groupby 对象,因此您必须将其构建到函数中并使用 .apply() 使其工作。
【讨论】:
【参考方案5】:使用 xarray 库在 netcdf 文件上检索多时间 groupby 函数的问题的另一个解决方案是使用称为“resample”的 xarray-DataArray 方法和“groupby”方法。这种方法也适用于 xarray-DataSet 对象。
通过这种方法,人们可以检索诸如每月每小时平均值或其他类型的时间聚合(即:年度每月平均值、双年度三个月总和等)之类的值。
以下示例使用每日气温 (Tair) 的标准 xarray 教程数据集。请注意,我必须将教程数据的时间维度转换为 pandas 日期时间对象。如果不应用此转换,重采样功能将失败,并出现错误消息(见下文):
错误信息:
"TypeError: 仅对 DatetimeIndex、TimedeltaIndex 或 PeriodIndex 有效,但获得了 'Index' 的实例"
尽管存在时间索引问题(这可能是 *** 中讨论的另一个问题),但下面的代码为 xarray 对象中的多时间分组问题提供了两种可能的解决方案。第一个使用 xarray.core.groupby.DataArrayGroupBy 类,而第二个只使用普通 xarray-dataArray 和 xarray-DataSet 类中的 groupby 方法。
此致,
菲利普·里斯卡拉·利尔
代码sn-p:
ds = xr.tutorial.open_dataset('rasm').load()
def parse_datetime(time):
return pd.to_datetime([str(x) for x in time])
ds.coords['time'] = parse_datetime(ds.coords['time'].values)
# 1° Option for multitemporal aggregation:
time_grouper = pd.Grouper(freq='Y')
grouped = xr.core.groupby.DataArrayGroupBy(ds, 'time', grouper=time_grouper)
for idx, sub_da in grouped:
print(sub_da.resample('time':'3M').mean().coords)
# 2° Option for multitemporal aggregation:
grouped = ds.groupby('time.year')
for idx, sub_da in grouped:
print(sub_da.resample('time':'3M').mean().coords)
【讨论】:
以上是关于从 netcdf 文件中获取每个月的每小时平均值的主要内容,如果未能解决你的问题,请参考以下文章