Python numpy:无法将 datetime64[ns] 转换为 datetime64[D](与 Numba 一起使用)

问题描述 投票:0回答:4

我想将日期时间数组传递给 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}
python pandas numpy datetime numba
4个回答
63
投票

注意(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


1
投票

在计算两个日期之间的工作日数时遇到相同的错误:

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')”转换日期。它在我的特殊情况下有效。


0
投票

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


0
投票

执行以下步骤:

  1. 尝试添加

    .values

  2. 格式转换

例如:

>>> data_total.DURG_DATE.values.astype("datetime64[D]")

© www.soinside.com 2019 - 2024. All rights reserved.