квантильный метод для группировки набора данных xarray

У меня есть классический набор данных xarray. Это месячные данные (38 лет месячных данных).

Меня интересует расчет значений квантилей для каждого месяца отдельно.

<xarray.Dataset>
Dimensions:        (lat: 26, lon: 71, time: 456)
Coordinates:
  * lat            (lat) float32 25.0 26.0 27.0 28.0 29.0 30.0 31.0 32.0 ...
  * lon            (lon) float32 -130.0 -129.0 -128.0 -127.0 -126.0 -125.0 ...
  * time           (time) datetime64[ns] 1979-01-31 1979-02-28 1979-03-31 ...
Data variables:
    var1         (time, lat, lon) float32 nan nan nan nan nan nan nan nan ...
    var2         (time, lat, lon) float32 nan nan nan nan nan nan nan nan ...
    var3         (time, lat, lon) float32 nan nan nan nan nan nan nan nan ...
    ......

Например, если мне нужно среднее значение за каждый месяц, который я использую:

ds.groupby(‘time.month’).mean(dim=‘time’)

Но если я попытаюсь

ds.groupby(‘time.month’).quantile(0.75, dim=‘time’)

я получил

AttributeError: 'DatasetGroupBy' object has no attribute 'quantile'

однако, основываясь на документации Pandas, quantile работает с объектом groupby.

На самом деле, я пробовал следующее:

df_ds = xr.Dataset.to_dataframe(ds)
df_ds = df_ds.reset_index()
df_ds = df_ds.set_index('time')
df_ds.groupby(pd.TimeGrouper(freq='M')).quantile(0.75)

и это работает; конечно, это гораздо более простой пример, потому что у меня есть только один индекс, и действительно, если я не reset_index/set_index только для одного индекса, я получаю сообщение об ошибке от pandas, что он не может обрабатывать мультииндекс.

Итак, может ли xarray это сделать? возможно, используя некоторую комбинацию применения/лямбда?

Я нашел очень не элегантный способ обойти это. Это возможно, потому что у меня есть 4 переменные (и я мог бы просмотреть имена переменных, но не здесь):

Data_clim_monthly_75g = ds.where(iok_conus_xarray).groupby('time.month')
Data_clim_monthly_75 = ds.where(iok_conus_xarray).groupby('time.month').mean(dim='time')

v1 = Data_clim_monthly_75['var1'].values
v2 = Data_clim_monthly_75['var2'].values
v3 = Data_clim_monthly_75['var3'].values
v4 = Data_clim_monthly_75['var4'].values
for k, gp in Data_clim_monthly_75g:
    v1[k-1] =  np.nanpercentile(gp['var1'].values,q=75,axis=0)
    v2[k-1] =  np.nanpercentile(gp['var2'].values,q=75,axis=0)
    v3[k-1] =  np.nanpercentile(gp['var3'].values,q=75,axis=0)
    v4[k-1] =  np.nanpercentile(gp['var4'].values,q=75,axis=0)
Data_clim_monthly_75['var1'] = (('month','lat','lon'),v1)    
Data_clim_monthly_75['var2'] = (('month','lat','lon'),v2)    
Data_clim_monthly_75['var3'] = (('month','lat','lon'),v3)    
Data_clim_monthly_75['var4'] = (('month','lat','lon'),v4)    

Я в основном работаю с xarray. Я все еще хотел бы решение в рамках xarray.


person claude    schedule 03.11.2017    source источник


Ответы (1)


Мы еще не добавили метод quantile в объект groupby. Однако вы можете применять произвольные функции сокращения к каждой группе, используя метод reduce. В моем примере ниже я применяю np.nanpercentile к каждой группе.

In [21]: ds
Out[21]:
<xarray.Dataset>
Dimensions:  (lat: 71, lon: 26, time: 456)
Coordinates:
  * time     (time) datetime64[ns] 1979-01-31 1979-02-28 1979-03-31 ...
Dimensions without coordinates: lat, lon
Data variables:
    var1     (time, lon, lat) float64 0.4286 0.4032 0.2178 0.7652 0.8108 ...
    var2     (time, lon, lat) float64 0.8259 0.3625 0.6556 0.7403 0.2381 ...

In [22]: ds.groupby('time.month').reduce(np.nanpercentile, dim='time', q=0.75)
Out[22]:
<xarray.Dataset>
Dimensions:  (lat: 71, lon: 26, month: 12)
Coordinates:
  * month    (month) int64 1 2 3 4 5 6 7 8 9 10 11 12
Dimensions without coordinates: lat, lon
Data variables:
    var1     (month, lon, lat) float64 0.04153 0.03099 0.07881 0.01749 ...
    var2     (month, lon, lat) float64 0.03518 0.06896 0.01287 0.025 0.01536 ...

Изменить: из версии xarray 0.12. .2 и далее Объекты GroupBy имеют GroupBy.quantile метод, который вы искали:

ds.groupby(‘time.month’).quantile(q=0.75, dim=‘time’)
person jhamman    schedule 03.11.2017
comment
Отлично - действительно, это сработало и быстрее, чем мое решение. - person claude; 16.11.2017
comment
@jhamman, что, если у меня есть рентгеновский массив с почасовыми временными шагами за несколько лет, и я бы вернул процентиль за один день? Что-то вроде ds.resample(time='24H').reduce(np.nanpercentile, dim='time', q=0.90) действительно занимает много времени - person Glori P.; 18.11.2019