xarray: неправильное время после сохранения

Может ли кто-нибудь воспроизвести такое поведение xarray при сохранении времени с большими значениями? Я немного в недоумении от того, что здесь происходит.

Изменить: кажется, что xarray делает что-то не так, если числовое значение «время» превышает определенный порог. Обратите внимание, что это происходит только для «дней с тех пор», а не, например, для «секунд с тех пор».

Я использую Python 3 и xarray версии 0.10.7.

import numpy as np
import xarray as xr

# print('xarray version: {}'.format(xr.__version__))

ds = xr.Dataset(coords={'time': (
    'time', 
    np.arange(106300.5, 106665.5+5*365, 365), 
    {'units': 'days since 1800-01-01 00:00:00'})})
# print(ds.time)
ds = xr.decode_cf(ds)
# print(ds.time)
ds.to_netcdf('./test.nc')
ds = xr.open_dataset('./test.nc', decode_cf=False)
print(ds.time)

Вне:

<xarray.DataArray 'time' (time: 6)>
array([ 106300.5     ,  106665.5     , -106473.482335, -106108.482335,
       -105743.482335, -105378.482335])
Coordinates:
  * time     (time) float64 1.063e+05 1.067e+05 -1.065e+05 -1.061e+05 ...
Attributes:
    _FillValue:  nan
    units:       days since 1800-01-01
    calendar:    proleptic_gregorian

Изменить: вот содержимое файла с ncdump:

netcdf test {
dimensions:
    time = 6 ;
variables:
    double time(time) ;
        time:_FillValue = NaN ;
        time:units = "days since 1800-01-01" ;
        time:calendar = "proleptic_gregorian" ;

// global attributes:
        :_NCProperties = "version=1|netcdflibversion=4.4.1.1|hdf5libversion=1.10.1" ;
data:

 time = 106300.5, 106665.5, -106473.482334601, -106108.482334601, 
    -105743.482334601, -105378.482334601 ;
}

person Lukas    schedule 04.07.2018    source источник
comment
Вы имеете в виду отрицательное время, представляющее поплавки? Каково содержимое файла test.nc?   -  person sophros    schedule 04.07.2018
comment
Это было исправлено в версии 0.11.0 с помощью #2519.   -  person Lukas    schedule 11.11.2018


Ответы (1)


Да, я могу воспроизвести это. Это можно считать ошибкой в ​​xarray; вы можете поднять вопрос на GitHub.

При сохранении файла под капотом xarray берет декодированные даты и преобразовывает их в временные дельты с исходной даты. Проблема в том, что даты в вашем примере набора данных пересекают границу на 292 года позже указанной контрольной даты (1800-01-01).

In [1]: import numpy as np

In [2]: import xarray as xr

In [3]: ds = xr.Dataset(coords={'time': (
   ...:     'time',
   ...:     np.arange(106300.5, 106665.5+5*365, 365),
   ...:     {'units': 'days since 1800-01-01 00:00:00'})})
   ...:

In [4]: ds = xr.decode_cf(ds)

In [5]: ds.time
Out[5]:
<xarray.DataArray 'time' (time: 6)>
array(['2091-01-15T12:00:00.000000000', '2092-01-15T12:00:00.000000000',
       '2093-01-14T12:00:00.000000000', '2094-01-14T12:00:00.000000000',
       '2095-01-14T12:00:00.000000000', '2096-01-14T12:00:00.000000000'],
      dtype='datetime64[ns]')
Coordinates:
  * time     (time) datetime64[ns] 2091-01-15T12:00:00 2092-01-15T12:00:00 ...

In [6]: ds.to_netcdf('so.nc')

In [7]: xr.open_dataset('so.nc', decode_times=False).time
so.nc
Out[7]:
<xarray.DataArray 'time' (time: 6)>
array([ 106300.5     ,  106665.5     , -106473.482335, -106108.482335,
       -105743.482335, -105378.482335])
Coordinates:
  * time     (time) float64 1.063e+05 1.067e+05 -1.065e+05 -1.061e+05 ...
Attributes:
    units:     days since 1800-01-01
    calendar:  proleptic_gregorian

292 года — это максимальный отрезок времени, который может представлять объект np.timedelta64 с точностью до наносекунды (см. ="nofollow noreferrer">здесь в документации); больше, чем это, и вы столкнетесь с переполнением (что является причиной отрицательных значений).

Обходной путь, который вы могли бы использовать, — перезаписать кодировку единиц, связанную со временем в вашем наборе данных, с новым значением:

In [8]: ds.time.encoding['units'] = 'days since 1970-01-01'

In [9]: ds.to_netcdf('so-workaround.nc')

In [10]: xr.open_dataset('so-workaround.nc', decode_times=False).time
Out[10]:
<xarray.DataArray 'time' (time: 6)>
array([44209.5, 44574.5, 44939.5, 45304.5, 45669.5, 46034.5])
Coordinates:
  * time     (time) float64 4.421e+04 4.457e+04 4.494e+04 4.53e+04 4.567e+04 ...
Attributes:
    units:     days since 1970-01-01
    calendar:  proleptic_gregorian

Здесь я выбрал 'days since 1970-01-01' намеренно, так как это то, вокруг чего сосредоточены объекты np.datetime64 в NumPy.

person spencerkclark    schedule 06.07.2018
comment
Спасибо за проверку @skc! Я изучил это немного подробнее и отправил отчет здесь. - person Lukas; 08.07.2018