numpy 如何在pandas 2中解析分辨率为's'的日期时间列表?

qmb5sa22  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(119)

我有一个带有日期时间列的csv。然而,日期从公元1年一直到公元3000年。它们超出了普通datetime64[ns]数据类型的范围。
在pandas < 2中,我的解决方法是让这个列具有“period[H]”dtype。我有一个自定义函数来做这件事,我在pd.read_csv中将其作为date_parser传递。
在pandas >= 2中,引入了一个使用其他分辨率的时间戳的选项。date_parser参数已被弃用,因此前面的解决方案也不可行。我想我可以简单地用pd.to_datetime转换整列字符串。
但这不管用。
完整示例:
example.csv

index,date
A,"0004-04-04T12:30"
B,"2004-04-04T12:30"
C,"3004-04-04T12:30"

字符串

1.盲目乐观-失败

日期是ISO 8601,最简单的格式。

df = pd.read_csv('example.csv', parse_dates=['date'])
print(df.date.dtype, '|', type(df.date.iloc[0]))


收到警告:

<ipython-input-103-059359fbaeab>:1: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format


输出:object | <class 'str'>
如果example.csv只包含datetime64[ns]-valid日期,则可以完美工作。

2.如文档所示-失败

Doc说:“作为对象读入,然后根据需要应用于_datetime()。”

df = pd.read_csv('example.csv')
pd.to_datetime(df.date)


失败原因

OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 0004-04-04T12:30, at position 0


pd.to_datetime(df.date, unit='s')给出:

ValueError: non convertible value 0004-04-04T12:30 with the unit 's', at position 0


所以我猜这里的unit参数没有我期望的含义。

3.按元素转换-部分工作

def to_timestamp(val):
    if pd.isna(val):
        return pd.Timestamp('NaT', unit='s')
    return pd.Timestamp(val, unit='s')
df = pd.read_csv('example.csv')
df['date'] = df.date.apply(_to_timestamp)
print(df.date.dtype, '|', type(df.date.iloc[0]))


打印:object | <class 'pandas._libs.tslibs.timestamps.Timestamp'>
因此,实际上,单个元素已经被转换为时间戳,耶!但是列本身仍然有一个“object”dtype,而不是“datetime”dtype。
df.date.astype('datetime64[s]')失败

OutOfBoundsDatetime: Cannot cast 0004-04-04 12:30:00 to unit='ns' without overflow., at position 0


即使我指定了“s”分辨率?pd.to_datetime(df.date)也一样。

4.踏出pandas - Works

import numpy as np
def to_d64(val):
    if pd.isna(val):
        return np.datetime64('')
    return np.datetime64(val)

df = pd.read_csv('example.csv')
df['date'] = np.array(df.date.apply(to_d64), dtype='M8[s]')
print(df.date.dtype, '|', type(df.date.iloc[0]))


成功!它打印:

datetime64[s] | <class 'pandas._libs.tslibs.timestamps.Timestamp'>


但代价是什么?在真实的的代码中,我的csv有数千行。pandas < 2代码确保避免了逐个元素转换,因为这会带来性能问题。我希望对“s”解析的支持可以直接从字符串解析步骤访问。我还注意到,我的最后一个例子是可行的,因为我的字符串是ISO 8601格式的,这是numpy支持的。这根本不是一个普遍的解决办法。
我错过了什么吗?有人有更干净的解决方案吗?
编辑:我在Linux(Fedora 37)上使用pandas 2.0.3和numpy 1.24.4,Python 3.11.4。

ojsjcaue

ojsjcaue1#

我认为to_datetime中的unit只有在输入是整数时才会生效-但我认为即使输入是字符串,也有工作使其生效。非纳秒支持是相当新的,所以还不太成熟。
无论如何,这里有一个解决方案,你可以使用它直到to_datetime可以解析非纳秒范围的字符串,这涉及到通过numpydatetime64[s]

In [22]: data = """\
    ...: index,date
    ...: A,"0004-04-04T12:30"
    ...: B,"2004-04-04T12:30"
    ...: C,"3004-04-04T12:30"
    ...: """

In [23]: df = pd.read_csv(io.StringIO(data))

In [24]: df['date'] = df['date'].to_numpy().astype('datetime64[s]')

In [25]: df
Out[25]:
  index                date
0     A    4-04-04 12:30:00
1     B 2004-04-04 12:30:00
2     C 3004-04-04 12:30:00

字符串

相关问题