我想将日期时间数组传递给 Numba 函数(该函数无法矢量化,否则会非常慢)。我了解 Numba 支持 numpy.datetime64。然而,它似乎支持
datetime64[D]
(日精度),但不支持datetime64[ns]
(纳秒精度)(我通过艰难的方式了解到这一点:它有记录吗?)。
我尝试从
datetime64[ns]
转换为 datetime64[D]
,但似乎找不到方法!
我用下面的最少代码总结了我的问题。如果你运行
testdf(mydates)
,即 datetime64[D],它工作得很好。如果您运行 testdf(dates_input)
(即 datetime64[ns]),则不会。请注意,此示例只是将日期传递给 Numba 函数,该函数(尚未)对它们执行任何操作。我尝试将 dates_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 testdf(dates):
return 1
print testdf(mydates)
如果我运行
testdf(dates_input)
,得到的错误是:
numba.typeinfer.TypingError: Failed at nopython (nopython frontend)
Var 'dates' unified to object: dates := {pyobject}
注意(2023-05-30):此答案仅适用于 pandas 版本<2. Pandas 2.0.0 was released on 2023-04-03. See 相关变更日志条目。
Series.astype
将所有类似日期的对象转换为 datetime64[ns]
。
要转换为
datetime64[D]
,请在调用 values
之前使用 astype
获取 NumPy 数组:
dates_input = df["month_15"].values.astype('datetime64[D]')
请注意,NDFrame(例如 Series 和 DataFrame)只能将类似日期时间的对象保存为 dtype
datetime64[ns]
的对象。所有日期时间类自动转换为通用数据类型简化了后续日期计算。但这使得无法在 DataFrame 列中存储 datetime64[s]
对象。 Pandas 核心开发人员,Jeff Reback 解释,
“我们不允许直接转换,因为它太复杂了,无法在内部保留除 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]')
当您迭代系列中的项目时,您会得到 pandas
Timestamps
,而不是 datetime64[ns]
s。
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
确实是 dtype 的 NumPy 数组 datetime64[ns]
:
In [31]: df['month_15'].astype('datetime64[D]').values.dtype
Out[31]: dtype('<M8[ns]')
如果有效,那么您不必将所有内容都转换为
datetime64[D]
,您只需将 NumPy 数组(而不是 Pandas Series)传递给 testf
。
在计算两个日期之间的工作日数时遇到相同的错误:
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')”转换日期。它在我的特殊情况下有效。
Numpy datetime64 对象支持不同的分辨率级别,它们具有相应的 Python
datetime
对象。例如,datetime64[us]
可以转换为datetime.datetime
,datetime64[D]
转换为datetime.date
等。所以凡是需要datetime64[D]
的地方,都可以使用Python的datetime.date
;与 datetime64[us]
和 datetime.datetime
相同。遗憾的是,Python 的 datetime
不支持纳秒分辨率,因此 datetime64[ns]
变为整数。
因此,如果您收到错误提示
<M8[ns]
无法转换为 <M8[D]
,其中一个示例是:
TypeError: Iterator operand 0 dtype could not be cast from
dtype('<M8[ns]') to dtype('<M8[D]') according to the rule 'safe'
然后尝试使用适当的分辨率查看阵列(类似于将
datetime.datetime
转换为 datetime.date
):
x = np.arange('2020-01-01','2020-01-05', dtype='datetime64[D]')
y = np.arange('2020-01-01','2020-01-05', 10**9*3600*24, dtype='datetime64[ns]')
np.busday_count(x, y) # <---- error
np.busday_count(x, y.view('datetime64[D]')) # <---- OK
# ^^^^^^^^^^^^^^^^^^^^^^ # view with a different resolution
如果数据来自 OP1 中的 pandas 数据框,则可以
dt.date
将值转换为 datetime.date
对象;确保转换为列表,以便可以按原样使用 datetime.date
对象。2
df = pd.DataFrame({'x': x})
df['x'].dtype # dtype('<M8[ns]')
np.is_busday(df['x']) # error
np.is_busday(df['x'].dt.date.tolist()) # OK
# ^^^^^^^^^^^^^^^^^ # convert to a list of datetime.date objects
1 正如@unutbu提到的,pandas仅支持纳秒分辨率的
datetime64
,因此numpy数组中的datetime64[D]
在存储在pandas列中时变成datetime64[ns]
。
2
datetime.date
不是 pandas 中受支持的数据类型,因此存储它们的任何列/系列都会变成 object
数据类型,如果函数需要 datetime64[D]
或 datetime.date
类型对象,则不会这样做。所以必须将它们转换为列表,以便每个项目都可以读入为datetime.date
。
执行以下步骤:
尝试添加
.values
格式转换
例如:
>>> data_total.DURG_DATE.values.astype("datetime64[D]")