pandas 偏移量前滚加上添加月份偏移量后越界纳秒时间戳
pandas out of bounds nanosecond timestamp after offset rollforward plus adding a month offset
我很困惑 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
由于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,因此出现越界错误
解决方法:
这将强制超出范围的日期 NaT
pd.to_datetime(date_col_to_force, errors = 'coerce')
将 pd.to_datetime
中的 errors
参数设置为 'coerce'
会导致用 NaT
替换超出范围的值。引用 docs:
If ‘coerce’, then invalid parsing will be set as NaT
例如:
datetime_variable = pd.to_datetime(datetime_variable, errors = 'coerce')
这不会修复数据(显然),但仍允许处理 non-NaT 个数据点。
None 上面的很好,因为它会删除你的数据。但是,您只能维护和修改您的转化:
# convertin from epoch to datatime mantainig the nanoseconds timestamp
xbarout= pd.to_datetime(xbarout.iloc[:,0],unit='ns')
您可以尝试使用 datetime 库中的 strptime() 和 lambda 表达式将文本转换为系列对象中的日期值:
示例:
df['F'].apply(lambda x: datetime.datetime.strptime(x, '%m/%d/%Y %I:%M:%S') if type(x)==str else np.NaN)
您看到此错误消息的原因
"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 服务器这样的数据库和像 numpy 这样的库允许存储超出这个范围的日期。在大多数情况下,最多使用 64 位来存储日期。
但这是不同的。
SQL 服务器 以纳秒分辨率存储日期,但精度最高为 100 ns(与 pandas 中的 1 ns 相对)。由于 space 是有限的(64 位),它是范围与精度的问题。使用 pandas 时间戳,我们的准确性更高,但日期范围更小。
如果是numpy(pandas建立在numpy之上)datetime64数据类型,
- 如果日期在上面提到的range你可以存储
它以纳秒为单位,类似于 pandas.
- 或者您可以放弃纳秒级分辨率并使用
微秒,这将为您提供更大的范围。这是 pandas 时间戳类型中缺少的东西。
但是,如果您选择以纳秒为单位存储并且日期超出范围,则 numpy 将自动绕过该日期,您可能会得到意想不到的结果(在下面的第 4 个解决方案中引用).
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'))
我很困惑 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
由于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,因此出现越界错误
解决方法:
这将强制超出范围的日期 NaT
pd.to_datetime(date_col_to_force, errors = 'coerce')
将 pd.to_datetime
中的 errors
参数设置为 'coerce'
会导致用 NaT
替换超出范围的值。引用 docs:
If ‘coerce’, then invalid parsing will be set as NaT
例如:
datetime_variable = pd.to_datetime(datetime_variable, errors = 'coerce')
这不会修复数据(显然),但仍允许处理 non-NaT 个数据点。
None 上面的很好,因为它会删除你的数据。但是,您只能维护和修改您的转化:
# convertin from epoch to datatime mantainig the nanoseconds timestamp
xbarout= pd.to_datetime(xbarout.iloc[:,0],unit='ns')
您可以尝试使用 datetime 库中的 strptime() 和 lambda 表达式将文本转换为系列对象中的日期值:
示例:
df['F'].apply(lambda x: datetime.datetime.strptime(x, '%m/%d/%Y %I:%M:%S') if type(x)==str else np.NaN)
您看到此错误消息的原因 "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 服务器这样的数据库和像 numpy 这样的库允许存储超出这个范围的日期。在大多数情况下,最多使用 64 位来存储日期。
但这是不同的。 SQL 服务器 以纳秒分辨率存储日期,但精度最高为 100 ns(与 pandas 中的 1 ns 相对)。由于 space 是有限的(64 位),它是范围与精度的问题。使用 pandas 时间戳,我们的准确性更高,但日期范围更小。
如果是numpy(pandas建立在numpy之上)datetime64数据类型,
- 如果日期在上面提到的range你可以存储 它以纳秒为单位,类似于 pandas.
- 或者您可以放弃纳秒级分辨率并使用 微秒,这将为您提供更大的范围。这是 pandas 时间戳类型中缺少的东西。
但是,如果您选择以纳秒为单位存储并且日期超出范围,则 numpy 将自动绕过该日期,您可能会得到意想不到的结果(在下面的第 4 个解决方案中引用).
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'))