我有一个带有日期时间列的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。
1条答案
按热度按时间ojsjcaue1#
我认为
to_datetime
中的unit
只有在输入是整数时才会生效-但我认为即使输入是字符串,也有工作使其生效。非纳秒支持是相当新的,所以还不太成熟。无论如何,这里有一个解决方案,你可以使用它直到
to_datetime
可以解析非纳秒范围的字符串,这涉及到通过numpy
datetime64[s]
:字符串