Python numpy: невозможно преобразовать datetime64 [ns] в datetime64 [D] (для использования с Numba)

Я хочу передать массив datetime функции Numba (которая не может быть векторизована и в противном случае будет очень медленной). Насколько я понимаю, Numba поддерживает numpy.datetime64. Однако кажется, что он поддерживает datetime64 [D] (точность дня), но не datetime64 [ns] (точность до миллисекунды) (я усвоил это на собственном горьком опыте: документировано ли это?).

Я пытался преобразовать datetime64 [ns] в datetime64 [D], но не нашел способа! Любые идеи?

Я резюмировал свою проблему с помощью минимального кода ниже. Если вы запустите testdf(mydates), то есть datetime64 [D], он будет работать нормально. Если вы запустите testdf(dates_input), то есть datetime64 [ns], этого не произойдет. Обратите внимание, что в этом примере даты просто передаются функции Numba, которая (пока) ничего с ними не делает. Я пытаюсь преобразовать date_input в datetime64 [D], но преобразование не работает. В моем исходном коде я читал из таблицы SQL в фреймворк pandas, и мне нужен столбец, который изменяет день каждой даты на 15-е.

import numba
import numpy as np
import pandas as pd
import datetime

mydates =np.array(['2010-01-01','2011-01-02']).astype('datetime64[D]')
df=pd.DataFrame()
df["rawdate"]=mydates
df["month_15"] = df["rawdate"].apply(lambda r: datetime.date( r.year, r.month,15 ) )

dates_input = df["month_15"].astype('datetime64[D]')
print dates_input.dtype # Why datetime64[ns] and not datetime64[D] ??


@numba.jit(nopython=True)
def testf(dates):
    return 1

print testf(mydates)

Ошибка, которую я получаю, если запускаю testdf(dates_input):

numba.typeinfer.TypingError: Failed at nopython (nopython frontend)
Var 'dates' unified to object: dates := {pyobject}

person Pythonista anonymous    schedule 10.08.2015    source источник
comment
Это действительно полезный вопрос, но его по какой-то причине было очень сложно найти просто поиском. Я получил аналогичную ошибку при попытке использовать np.busday_count для данных pandas, которые читаются: TypeError: Iterator operand 0 dtype could not be cast from dtype('<M8[ns]') to dtype('<M8[D]') according to the rule 'safe'   -  person Michael K    schedule 28.03.2016


Ответы (2)


Series.astype преобразует все объекты, похожие на дату, в datetime64[ns]. Чтобы преобразовать в datetime64[D], используйте values для получения массива NumPy перед вызовом astype:

dates_input = df["month_15"].values.astype('datetime64[D]')

Обратите внимание, что NDFrames (такие как Series и DataFrames) могут содержать только объекты, подобные datetime, как объекты dtype datetime64[ns]. Автоматическое преобразование всех типов datetime в общий dtype упрощает последующие вычисления даты. Но это делает невозможным хранение, скажем, datetime64[s] объектов в столбце DataFrame. Разработчик ядра Pandas, объясняет,

«Мы не разрешаем прямые преобразования, потому что просто слишком сложно хранить что-либо, кроме datetime64 [ns] внутри (это не обязательно)».


Также обратите внимание, что хотя df['month_15'].astype('datetime64[D]') имеет dtype datetime64[ns]:

In [29]: df['month_15'].astype('datetime64[D]').dtype
Out[29]: dtype('<M8[ns]')

когда вы перебираете элементы в Серии, вы получаете Timestamps панд, а не datetime64[ns].

In [28]: df['month_15'].astype('datetime64[D]').tolist()
Out[28]: [Timestamp('2010-01-15 00:00:00'), Timestamp('2011-01-15 00:00:00')]

Таким образом, неясно, действительно ли у Numba проблема с datetime64[ns], это может быть проблема с Timestamps. Извините, я не могу это проверить - у меня не установлена ​​Numba.

Однако вам может быть полезно попробовать

testf(df['month_15'].astype('datetime64[D]').values)

поскольку df['month_15'].astype('datetime64[D]').values действительно является массивом NumPy типа dtype datetime64[ns]:

In [31]: df['month_15'].astype('datetime64[D]').values.dtype
Out[31]: dtype('<M8[ns]')

Если это сработает, то вам не нужно преобразовывать все в datetime64[D], вам просто нужно передать массивы NumPy, а не серию Pandas, в testf.

person unutbu    schedule 10.08.2015
comment
Спасибо! Могу я спросить, почему это так? Я имею в виду, я не могу придумать никакой логической причины, почему дата, созданная только с годом, месяцем и днем, преобразуется с точностью до миллисекунды и не может быть преобразована обратно в точность дня, если мы не вызовем .values. Это ошибка? Или мне здесь не хватает фундаментальной причины? Это где-нибудь задокументировано? Мое большое разочарование в Python для анализа данных (что, да, я знаю, это лишь одна из многих возможностей Python, но меня не интересуют другие!), Действительно, заключается в низком качестве документации, особенно по сравнению с коммерческий пакет вроде Matlab - person Pythonista anonymous; 10.08.2015
comment
Pandas делает за вас много вещей, которые в целом удобны. К сожалению, иногда это означает, что он в конечном итоге делает то, что, по его мнению, вы хотите (например, преобразование всех дат в datetime64 [ns] / Timestamps), когда на самом деле вам нужно что-то еще. Я не знаю, задокументирована ли где-нибудь эта конкретная проблема. - person unutbu; 10.08.2015
comment
хотя на самом деле здесь происходит не это. В моем примере Pandas не должен угадывать, какая точность мне нужна (день или миллисекунда), потому что я явно указываю Pandas (.astype (datetime64 ['D']). Это больше похоже на ошибку - person Pythonista anonymous; 10.08.2015
comment
В какой-то момент Pandas принял решение объединить все данные, похожие на дату, в один общий тип данных: datetime64[ns]. У этого есть свои преимущества: это упрощает сравнение и арифметику даты. Следствием этого является то, что не существует серий dtype datetime64[D]. Возможно, df['month_15'].astype('datetime64[D]') следует вызвать исключение вместо тихого преобразования в datetime64[ns], но до тех пор, пока Pandas поддерживает политику «воронка все до даты и времени64 [ns]», df['month_15'].astype('datetime64[D]') не будет возвращать серию dtype datetime64[D]. - person unutbu; 10.08.2015
comment
Между прочим, datetime64[ns] имеет точность в наносекунду, а не в миллисекунду. - person unutbu; 10.08.2015
comment
@Pythonistaanonymous: после того, как этот ответ был написан, wesm из Pandas написал подробный комментарий с некоторой предысторией и проблемами с поддержкой других модулей datetime64 здесь: github.com/pandas-dev/pandas/issues/7307#issuecomment-224180563 - многие комментарии по этой проблеме актуальны здесь. - person John Zwinck; 28.02.2017

Возникла та же ошибка при вычислении количества рабочих дней между двумя датами:

from pandas.tseries.offsets import MonthBegin
import numpy as np 

# Calculate the beginning of the month from a given date
df['Month_Begin'] = pd.to_datetime(df['MyDateColumn'])+ MonthBegin(-1)

# Calculate # of Business Days
# Convert dates to string to prevent type error [D]
df['TS_Period_End_Date'] = df['TS_Period_End_Date'].dt.strftime('%Y-%m-%d')
df['Month_Begin'] = df['Month_Begin'].dt.strftime('%Y-%m-%d')

df['Biz_Days'] = np.busday_count(df['Month_Begin'], df['MyDateColumn']) #<-- Error if not converted into strings.

Мое обходное решение состояло в том, чтобы преобразовать даты с помощью ".dt.strftime (''% Y-% m-% d ')". В моем конкретном случае это сработало.

person Arthur D. Howland    schedule 04.12.2019