从netcdf文件获取每月的每小时平均值

时间:2018-04-02 23:27:24

标签: python netcdf xarray

我有一个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

5 个答案:

答案 0 :(得分:5)

您正在获取 TypeError:group必须是xarray.DataArray或xarray变量或维度的名称,因为ds.groupby()应该采用xarray数据集变量或数组,你传递了一系列变量。

您有两种选择:

1。 xarray箱 - >按小时分组

按文档group by documentation推荐分组,并将数据集转换为splitsbins,然后应用groupby('time.hour')

这是因为在一个月或一个小时后逐个或一起应用groupby会聚合所有数据。如果您将它们拆分为月份数据,则可以按每月的平均值进行分组。

您可以尝试使用文档中提到的方法:

  

GroupBy:split-apply-combine

     

xarray支持使用与pandas相同的API进行“分组依据”操作   实施split-apply-combine策略:

     
      
  • 将您的数据拆分为多个独立的组。 => 使用groupby_bins
  • 将它们拆分数月   
  • 将一些功能应用于每个组。 =>
  • 分组   
  • 将您的组合并回一个数据对象。 **应用汇总函数mean('time')
  •   

2。将其转换为pandas数据帧并使用group by

警告 :并非所有netcdfs都可以转换为panda数据帧,转换时可能会丢失元数据。

通过df = ds.to_dataframe()将ds转换为pandas数据帧并使用     根据需要使用pandas.Grouper

进行分组
df.set_index('time').groupby([pd.Grouper(freq='1M'), 't2m']).mean()

注意:我在pandas.TimeGrouper看到了几个答案,但已弃用,现在必须使用pandas.Grouper

由于您的数据集太大且问题没有最小化数据并且正在消耗大量资源,我建议您在pandas上查看这些示例

  1. group by weekdays
  2. group by time
  3. groupby-date-range-depending-on-each-row
  4. group-and-count-rows-by-month-and-year

答案 1 :(得分:1)

万一您还没有解决问题,可以按照以下方式进行:

# 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()使其起作用。

答案 2 :(得分:1)

使用xarray库在netcdf文件上检索多时间groupby函数问题的另一种解决方案是使用称为“ resample”的xarray-DataArray方法和“ groupby”方法。这种方法也可用于xarray-DataSet对象。

通过这种方法,人们可以检索诸如每月每小时平均值或其他类型的时间汇总(即:每月每月平均值,半年两次的三个月总和等)之类的值。

下面的示例使用标准xarray的每日气温(Tair)教程数据集。注意,我必须将教程数据的时间维度转换为pandas datetime对象。如果未应用此转换,则重采样功能将失败,并会显示一条错误消息(见下文):

错误消息:

“ TypeError:仅对DatetimeIndex,TimedeltaIndex或PeriodIndex有效,但有一个'Index'实例”

尽管存在时间索引问题(这可能是StackOverFlow中讨论的另一个问题),但是下面的代码提供了xarray对象中多时间分组问题的两种可能的解决方案。第一个使用xarray.core.groupby.DataArrayGroupBy类,而第二个仅使用普通xarray-dataArray和xarray-DataSet类中的groupby方法。

真诚的,

Philipe Riskalla Leal

代码段:

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)

答案 3 :(得分:0)

不是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

请注意,如果您的数据未在1月开始,那么您将在最终文件时间内获得“跳转”...我认为可以通过设置yhourmean命令之后的年份进行排序,如果这是一个问题你。

答案 4 :(得分:0)

这是什么

import xarray as xr
ds = xr.open_mfdataset('ecmwf_usa_2015.nc')
print ds.groupby('time.hour' ).mean('time')

我得到这样的事情:

  

尺寸:(小时:24,纬度:93,经度:   281)坐标:

     
      
  • 经度(经度)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 ...
  •   

我认为这就是你想要的。