Dodawanie np.timedelta64(1, 'Y')
do tablicy dtype datetime64[ns]
nie działa, ponieważ rok nie odpowiada ustaloną liczbę nanosekund. Czasami rok to 365 dni, czasem 366 dni, czasami jest nawet dodatkowy sekundowy skok. (Uwaga dodatkowe sekundy przestępne, takie jak ten, który wystąpił w dniu 2015-06-30 23:59:60, nie są reprezentowalne jako NumPy datetime64s.)
Najprostszy sposób, jaki znam, aby dodać rok do tablicy NumPy datetime64[ns]
jest podzielenie go na części składowe, takie jak lat, miesięcy i dni, do obliczeń na tablicach liczbę całkowitą, a następnie przekomponujesz datetime64 tablicy:
def year(dates):
"Return an array of the years given an array of datetime64s"
return dates.astype('M8[Y]').astype('i8') + 1970
def month(dates):
"Return an array of the months given an array of datetime64s"
return dates.astype('M8[M]').astype('i8') % 12 + 1
def day(dates):
"Return an array of the days of the month given an array of datetime64s"
return (dates - dates.astype('M8[M]'))/np.timedelta64(1, 'D') + 1
def combine64(years, months=1, days=1, weeks=None, hours=None, minutes=None,
seconds=None, milliseconds=None, microseconds=None, nanoseconds=None):
years = np.asarray(years) - 1970
months = np.asarray(months) - 1
days = np.asarray(days) - 1
types = ('<M8[Y]', '<m8[M]', '<m8[D]', '<m8[W]', '<m8[h]',
'<m8[m]', '<m8[s]', '<m8[ms]', '<m8[us]', '<m8[ns]')
vals = (years, months, days, weeks, hours, minutes, seconds,
milliseconds, microseconds, nanoseconds)
return sum(np.asarray(v, dtype=t) for t, v in zip(types, vals)
if v is not None)
# break the datetime64 array into constituent parts
years, months, days = [f(dates_np) for f in (year, month, day)]
# recompose the datetime64 array after adding 1 to the years
dates3 = combine64(years+1, months, days)
plony
In [185]: dates3
Out[185]:
array(['1981-01-01', '1981-01-02', '1981-01-03', ..., '2015-12-30',
'2015-12-31', '2016-01-01'], dtype='datetime64[D]')
Pomimo pojawiające się tak dużo kodu, jest to rzeczywiście szybsze niż dodanie DateOff zestaw 1 roku:
In [206]: %timeit dates + DateOffset(years=1)
1 loops, best of 3: 285 ms per loop
In [207]: %%timeit
.....: years, months, days = [f(dates_np) for f in (year, month, day)]
.....: combine64(years+1, months, days)
.....:
100 loops, best of 3: 2.65 ms per loop
Oczywiście pd.tseries.offsets oferuje cały wachlarz przesunięć, które nie mają odpowiednika łatwe podczas pracy z datetime64s NumPy.
Jestem zaskoczony szybkością i szczegółowością tej odpowiedzi! Ponieważ czytam moje dane przy użyciu pand, łatwiej jest dalej używać pand "DateOffset do konwertowania dat, zanim wykonam obliczenia za pomocą numpy. Ale myślałem o zrobieniu konwersji, jak sugerujesz, więc teraz mam ten kod źródłowy, jeśli będę go potrzebować. Dzięki! – questiondude