【问题标题】:pandas out of bounds nanosecond timestamp after offset rollforward plus adding a month offset偏移量前滚后加上一个月偏移量后的熊猫超出纳秒时间戳
【发布时间】:2020-06-19 07:57:26
【问题描述】:

我很困惑 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')设置的日期时间,INDATUMA20070125格式的日期信息。

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

pandas.tslib.OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 2262-05-01 00:00:00

【问题讨论】:

标签: python datetime pandas datetimeoffset


【解决方案1】:

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

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 的范围,因此出现了越界错误

直接出:http://pandas-docs.github.io/pandas-docs-travis/user_guide/timeseries.html#timeseries-timestamp-limits

解决方法:

这将强制超出界限的日期为 NaT

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

【讨论】:

  • 你知道日期索引是否可能超出该范围?
  • @jetpackdata 在转换为 TimeDate 时如何解决这个问题?它似乎是一个 cath20。比如如何在转换之前比较输入。应该有办法 NaT 超出范围吗?
  • 对于超出最大限制的日期是否有解决方法?我有一个 np.where 如果 ['date'] > 今天,使用其他 col。有人胖手指指的是 3012 而不是 2012 并弄错了等式。
  • 但是我所有的日期都在 1600 之前,我应该把它全部交给 NaT 吗?就我而言,这不是一个好的解决方案。
【解决方案2】:

pd.to_datetime 中的errors 参数设置为'coerce' 会导致将超出范围的值替换为NaT。引用docs

如果'coerce',则无效解析将被设置为NaT

例如:

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

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

【讨论】:

  • 我知道 SO 不喜欢这种评论,但我只想说这正是我所需要的,我非常感谢你添加它。
  • 相同。强制是伟大的。
【解决方案3】:

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

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

【讨论】:

    【解决方案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)
    

    【讨论】:

    • 这是完美的——正是我在不丢失基础数据的情况下解决纳秒越界问题所需要的。
    【解决方案5】:

    您看到此错误消息的原因 “OutOfBoundsDatetime: OutOfBoundsDatetime: Out Of bounds nanosecond timestamp: 3000-12-23 00:00:00” 是因为 pandas 时间戳数据类型以纳秒分辨率存储日期(from the docs)。

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

    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 服务器 以纳秒分辨率存储日期,但精度最高为 100 ns(与 pandas 中的 1 ns 相比)。由于空间有限(64 位),它是范围与准确性的问题。使用 pandas 时间戳,我们的准确度更高,但日期范围更小。

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

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

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

    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 时间跨度。在使用此数据类型之前,请检查差异 b/w 时间戳和时间段。此处的日期范围和频率与 numpy 类似(上面提到的 numpy 部分)。

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

    【讨论】:

    • 这很有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-16
    • 2019-08-31
    • 2020-01-08
    • 1970-01-01
    • 2015-08-18
    相关资源
    最近更新 更多