从 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 x​​array.DataArray or the name of an x​​array variable or dimension 因为 ds.groupby() 应该采用 xarray dataset variable or array ,你传递了一个变量列表。

您有两种选择:

1。 xarray bins --> 按小时分组

参考文档分组group by documentation 并将数据集转换为splitsbins 然后应用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.Grouperlike 进行分组

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 文件中获取每个月的每小时平均值的主要内容,如果未能解决你的问题,请参考以下文章

获得每小时平均值

如何获取具有多列的时间序列数据框中的每小时平均值

如何使用ggplot2为两列获取每个月的平均昼夜

如何将信息附加到 R 中 netCDF 文件中的数组

查询从会话表中获取高峰时段

多维数组netcdf图的python平均值