pandas 在偏移量前滚加上添加月份偏移量后超出纳秒时间戳

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

我很困惑 pandas 如何用这些行超出日期时间对象的范围:

import pandas as pd
BOMoffset = pd.tseries.offsets.MonthBegin()
# here some code sets the all_treatments dataframe and the newrowix, micolix, mocolix counters
all_treatments.iloc[newrowix,micolix] = BOMoffset.rollforward(all_treatments.iloc[i,micolix] + pd.tseries.offsets.DateOffset(months = x))
all_treatments.iloc[newrowix,mocolix] = BOMoffset.rollforward(all_treatments.iloc[newrowix,micolix]+ pd.tseries.offsets.DateOffset(months = 1))

这里

all_treatments.iloc[i,micolix]
pd.to_datetime(all_treatments['INDATUMA'], errors='coerce',format='%Y%m%d')
设置的日期时间,
INDATUMA
20070125
格式的日期信息。

此逻辑似乎适用于模拟数据(没有错误,日期有意义),因此目前我无法重现,但它在我的整个数据中失败并出现以下错误:

pandas.tslib.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 2262-05-01 00:00:00
python datetime pandas datetimeoffset
7个回答
175
投票

由于 pandas 表示纳秒分辨率的时间戳,因此使用 64 位整数可以表示的时间跨度仅限于大约 584 年

In [54]: pd.Timestamp.min
Out[54]: Timestamp('1677-09-22 00:12:43.145225')

In [55]: pd.Timestamp.max
Out[55]: Timestamp('2262-04-11 23:47:16.854775807')

您的值超出了 2262-05-01 00:00:00 范围,因此出现越界错误

直接出:https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timestamp-limitations

解决方法:

这将强制超出范围的日期为 NaT

pd.to_datetime(date_col_to_force, errors = 'coerce')


66
投票

errors
中的
pd.to_datetime
参数设置为
'coerce'
会导致用
NaT
替换越界值。引用文档

如果‘强制’,则无效解析将被设置为 NaT

例如:

datetime_variable = pd.to_datetime(datetime_variable, errors = 'coerce')

这并没有修复数据(显然),但仍然允许处理非 NaT 数据点。


18
投票

您看到此错误消息的原因 “OutOfBoundsDatetime:超出范围纳秒时间戳:3000-12-23 00:00:00”是因为 pandas 时间戳数据类型以纳秒分辨率存储日期(来自文档)。

这意味着日期值必须在范围内

pd.Timestamp.min(1677-09-21 00:12:43.145225) and

pd.Timestamp.max(2262-04-11 23:47:16.854775807)

即使您只想要精度为秒或微秒的日期,pandas 仍然会以纳秒为单位在内部存储它。 pandas 中没有选项可以存储上述范围之外的时间戳。

这是令人惊讶的,因为像 sql server 这样的数据库和像 numpy 这样的库允许存储超出这个范围的日期。大多数情况下最多使用 64 位来存储日期。

但这就是区别。 SQL Server 以纳秒分辨率存储日期,但精度最高为 100 ns(而不是 pandas 中的 1 ns)。由于空间有限(64 位),因此这是范围与精度的问题。使用 pandas 时间戳,我们可以获得更高的精度,但日期范围更小。

如果是 numpy(pandas 构建在 numpy 之上)datetime64 数据类型,

  • 如果日期属于上述范围,您可以存储 它以纳秒为单位,类似于 pandas。
  • 或者你可以放弃纳秒分辨率并选择 微秒,这将为您提供更大的范围。这是 pandas 时间戳类型中缺少的东西。

但是,如果您选择以纳秒为单位存储并且日期超出范围,那么 numpy 将自动环绕该日期,您可能会得到意想不到的结果(在下面的第四个解决方案中引用)。

np.datetime64("3000-06-19T08:17:14.073456178", dtype="datetime64[ns]")
> numpy.datetime64('1831-05-11T09:08:06.654352946')

现在有了 pandas,我们有以下选项,

import pandas as pd
data = {'Name': ['John', 'Sam'], 'dob': ['3000-06-19T08:17:14', '2000-06-19T21:17:14']}
my_df = pd.DataFrame(data)

1)如果您同意丢失超出范围的数据,则只需使用以下参数将超出范围的日期转换为 NaT(不是时间)。

my_df['dob'] = pd.to_datetime(my_df['dob'], errors = 'coerce')

2)如果你不想丢失数据,那么你可以将值转换为Python日期时间类型。这里列“dob”是pandas对象类型,但单个值将是Python日期时间类型。然而这样做我们将失去矢量化函数的好处。

import datetime as dt
my_df['dob'] = my_df['dob'].apply(lambda x: dt.datetime.strptime(x,'%Y-%m-%dT%H:%M:%S') if type(x)==str else pd.NaT)
print(type(my_df.iloc[0][1]))
> <class 'datetime.datetime'>

3)另一种选择是如果可能的话,使用 numpy 而不是 pandas 系列。 如果是 pandas 数据框,您可以将系列(或 df 中的列)转换为 numpy 数组。单独处理数据,然后将其连接回数据框。

4)我们还可以按照docs中的建议使用pandas时间跨度。在使用此数据类型之前,请检查黑白时间戳和周期的差异。这里的日期范围和频率与 numpy 类似(上面在 numpy 部分提到)。

my_df['dob'] = my_df['dob'].apply(lambda x: pd.Period(x, freq='ms'))


4
投票

您可以尝试使用日期时间库中的 strptime() 以及 lambda 表达式将文本转换为系列对象中的日期值:

示例:

df['F'].apply(lambda x: datetime.datetime.strptime(x, '%m/%d/%Y %I:%M:%S') if type(x)==str else np.NaN)

3
投票

以上都不是很好,因为它会删除您的数据。但是,您只能维护和编辑您的转换:

# convertin from epoch to datatime mantainig the nanoseconds timestamp
xbarout= pd.to_datetime(xbarout.iloc[:,0],unit='ns')

2
投票

对于通过使用

pd.read_sql_query()
和带有日期时间值的
dtype
参数到达这里并得到这个的任何人
OutOfBoundsDatetime
错误,您可以使用参数
parse_dates
为日期列设置errors='coerce'来修复此问题。例如:

df = pd.read_sql_query(sql, conn,  dtype={'date_col': 'datetime64'), parse_dates={'date_col': {'errors': 'coerce'}}):

0
投票

确保您使用的是最新版本的 Pandas。我在尝试将表上传到 BigQuery 时遇到了这个问题(CloudShell 默认下载 1.5.*),同时使用 Pandas 读取镶木地板文件并使用 engine= 'pyarrow':

df = pd.read_parquet(path, engine='pyarrow')

我的解决方案是将 Pandas 软件包版本升级到 2.0.3 并将引擎更改为“fastparquet”(这给了我与旧 Pandas 版本不同的错误):

df = pd.read_parquet(path, engine='fastparquet')
© www.soinside.com 2019 - 2024. All rights reserved.