xarray computing moyenne mensuelle à partir de plusieurs années netcdf

Dec 18 2020

J'ai un fichier netcdf de 2 m de température de ERA5 qui va de 2000 à 2019 pour les mois 04 à 10, ce qui donne un total de 13680 pas de temps et une dimension de 61x161 lat-lon. Je veux faire une moyenne mensuelle de tous les pas quotidiens pour chaque année séparément. Par exemple, nous aurions la moyenne mensuelle des données en avril 2000, en mai 2000 et ainsi de suite. J'ai essayé le code suivant avec un rééchantillonnage xarray, mais deux problèmes se produisent.

  1. Pour une raison quelconque, la moyenne semble faire la moyenne pour toutes les années.
  2. La fonction de rééchantillonnage crée les mois 01, 02, 03, 11 et 12, bien qu'il n'y ait pas de données pour cela!

Voici de quoi je parle:

import xarray as xr
ds = xr.open_dataset(netcdf)
monthly_data=ds.resample(time='1M').mean()

Nous pouvons regarder l'horodatage qui montre le pas de temps mensuel, y compris les mois non liés.

print(np.array(monthly_data.time))
array(['2000-04-30T00:00:00.000000000', '2000-05-31T00:00:00.000000000',
       '2000-06-30T00:00:00.000000000', '2000-07-31T00:00:00.000000000',
       '2000-08-31T00:00:00.000000000', '2000-09-30T00:00:00.000000000',
       '2000-10-31T00:00:00.000000000', '2000-11-30T00:00:00.000000000',
       '2000-12-31T00:00:00.000000000', '2001-01-31T00:00:00.000000000',

Pour vérifier le contenu de la température, j'ai transformé les données en une trame de données.

temp_ar = np.array(monthly_data.t2m)    
print(pd.DataFrame(temp_ar[0,:,:]).head())
          0           1           2    ...         158         159         160
0  270.940613  270.911652  270.926727  ...         NaN         NaN         NaN
1  271.294952  271.256744  271.250946  ...  272.948608  272.974731  272.998535
2  271.416779  271.457214  271.483459  ...  273.123169  273.079285  273.058563
3  271.848755  271.791382  271.784058  ...         NaN  273.264038         NaN
4  272.226837  272.144928  272.123016  ...         NaN         NaN         NaN

print(pd.DataFrame(temp_ar[1,:,:]).head())
   0    1    2    3    4    5    6    ...  154  155  156  157  158  159  160
0  NaN  NaN  NaN  NaN  NaN  NaN  NaN  ...  NaN  NaN  NaN  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN  NaN  NaN  NaN  ...  NaN  NaN  NaN  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN  NaN  NaN  NaN  ...  NaN  NaN  NaN  NaN  NaN  NaN  NaN
3  NaN  NaN  NaN  NaN  NaN  NaN  NaN  ...  NaN  NaN  NaN  NaN  NaN  NaN  NaN
4  NaN  NaN  NaN  NaN  NaN  NaN  NaN  ...  NaN  NaN  NaN  NaN  NaN  NaN  NaN

Le 2ème tableau (qui correspond au mois 05 de 2000) ne devrait pas avoir de nans, mais c'est le cas et c'est comme ça pour tous les autres pas de temps (sauf le dernier pour une raison quelconque). Quelqu'un saurait-il pourquoi cela se produit?

Voici le jeu de données d'origine

print(ds)
<xarray.Dataset>
Dimensions:    (latitude: 61, longitude: 161, time: 13680)
Coordinates:
  * longitude  (longitude) float32 -80.0 -79.9 -79.8 -79.7 ... -64.2 -64.1 -64.0
  * latitude   (latitude) float32 50.0 49.9 49.8 49.7 ... 44.3 44.2 44.1 44.0
  * time       (time) datetime64[ns] 2000-04-01 ... 2018-10-30T23:00:00
Data variables:
    t2m        (time, latitude, longitude) float32 ...
Attributes:
    Conventions:  CF-1.6
    history:      2020-12-07 03:50:31 GMT by grib_to_netcdf-2.16.0: /opt/ecmw...

N'importe quelle aide serait. Peut-être que je devrais essayer une autre méthode? Acclamations!

Réponses

2 lhoupert Dec 18 2020 at 14:23

Je pense que tout moyen simple serait d'utiliser la groupbyméthode

Exemple:

da = xr.DataArray(
    np.linspace(0, 1673, num=1674),
    coords=[pd.date_range("1/1/2000", "31/07/2004", freq="D")],
    dims="time",
)
da

production:

<xarray.DataArray (time: 1674)>
array([0.000e+00, 1.000e+00, 2.000e+00, ..., 1.671e+03, 1.672e+03, 1.673e+03])
Coordinates:
  * time     (time) datetime64[ns] 2000-01-01 2000-01-02 ... 2004-07-31

Pour une moyenne annuelle, vous pouvez faire:

da.groupby('time.year').mean()

production:

<xarray.DataArray (year: 5)>
array([ 182.5,  548. ,  913. , 1278. , 1567. ])
Coordinates:
  * year     (year) int64 2000 2001 2002 2003 2004

Pour une moyenne par mois d'une année différente, vous pouvez créer un multi-index:

year_month_idx = pd.MultiIndex.from_arrays([da['time.year'], da['time.month']])
da.coords['year_month'] = ('time', year_month_idx)
da.groupby('year_month').mean()

production:

<xarray.DataArray (year_month: 55)>
array([  15. ,   45. ,   75. ,  105.5,  136. ,  166.5,  197. ,  228. ,  258.5,
        289. ,  319.5,  350. ,  381. ,  410.5,  440. ,  470.5,  501. ,  531.5,
        562. ,  593. ,  623.5,  654. ,  684.5,  715. ,  746. ,  775.5,  805. ,
        835.5,  866. ,  896.5,  927. ,  958. ,  988.5, 1019. , 1049.5, 1080. ,
       1111. , 1140.5, 1170. , 1200.5, 1231. , 1261.5, 1292. , 1323. , 1353.5,
       1384. , 1414.5, 1445. , 1476. , 1506. , 1536. , 1566.5, 1597. , 1627.5,
       1658. ])
Coordinates:
 * year_month          (year_month) MultiIndex
 * year_month_level_0  (year_month) int64 2000 2000 2000 ... 2002 2002 2002
 * year_month_level_1  (year_month) int64 1 2 3 4 5 6 7 8 ... 11 12 1 2 3 4 5 6