[英]pandas out of bounds nanosecond timestamp after offset rollforward plus adding a month offset
我很困惑 pandas 是如何用這些線吹出 datetime 對象的界限的:
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 ,因此出現 outofbounds 錯誤
直接出: https ://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#timestamp-limitations
解決方法:
這將強制在NaT范圍之外的日期
pd.to_datetime(date_col_to_force, errors = 'coerce')
將pd.to_datetime
中的errors
參數設置為'coerce'
會導致用NaT
替換超出范圍的值。 引用文檔:
如果 'coerce',則無效解析將被設置為 NaT
例如:
datetime_variable = pd.to_datetime(datetime_variable, errors = 'coerce')
這不會修復數據(顯然),但仍允許處理非 NaT 數據點。
您看到此錯誤消息“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 服務器以納秒分辨率存儲日期,但精度最高為 100 ns(與 pandas 中的 1 ns 相比)。 由於空間有限(64 位),它是范圍與准確性的問題。 使用 pandas 時間戳,我們有更高的准確性,但日期范圍更小。
如果是 numpy (pandas 建立在 numpy 之上)datetime64 數據類型,
但是,如果您選擇以納秒為單位存儲並且日期超出范圍,那么 numpy 將自動環繞該日期,您可能會得到意想不到的結果(在下面的第 4 個解決方案中引用)。
np.datetime64("3000-06-19T08:17:14.073456178", dtype="datetime64[ns]")
> numpy.datetime64('1831-05-11T09:08:06.654352946')
現在有了熊貓,我們有以下選擇,
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 datetime 類型。 然而這樣做我們將失去向量化函數的好處。
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)我們也可以按照文檔中的建議使用 pandas 時間跨度。 在使用此數據類型之前,請檢查差異 b/w 時間戳和時間段。 此處的日期范圍和頻率與 numpy 類似(上面在 numpy 部分中提到過)。
my_df['dob'] = my_df['dob'].apply(lambda x: pd.Period(x, freq='ms'))
以上都不是很好,因為它會刪除您的數據。 但是,您只能維護和編輯您的轉換:
# 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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.