close
拯救pandas計劃(11)——轉換DataFrame內的字符串型日期為日期類型

最近發現周圍的很多小夥伴們都不太樂意使用pandas,轉而投向其他的數據操作庫,身為一個數據工作者,基本上是張口pandas,閉口pandas了,故而寫下此系列以讓更多的小夥伴們愛上pandas。

系列文章說明:

系列名(系列文章序號)——此次系列文章具體解決的需求

平台:

windows 10
python 3.8
pandas >=1.2.4
/ 數據需求

目前有這麼一列日期數據,不過是以字符串類型顯示的,需要轉換成日期類型。

date02021-11-27 00:00:0012021-12-17 00:00:0022021-12-17 00:00:0032021-12-16 12:00:0042021-12-17 00:00:0052021-12-17 00:00:0062021-12-02 00:00:0072021-11-13 00:00:0082021-12-17 00:00:0092021-11-18 12:00:00102021-12-16 12:00:00
/ 需求拆解

在python中就有很多關於日期處理的庫,數最常見常用的就是datetime庫了,在pandas里也有處理日期的方法pandas.to_datetime,粗略的看了下該方法的解釋文檔,基於datetime庫做了更多擴展,在pandas里使用to_datetime方法更輕便的轉換日期類型數據。

/ 需求處理

在這一例中,可以簡單使用pd.to_datetime(data['date'])即可,不用指定轉換的類型,它會自動尋找到符合的日期類型進行轉換。

>>>importpandasaspd>>>df=...>>>df['date'].valuesarray([['2021-11-2700:00:00'],['2021-12-1700:00:00'],['2021-12-1700:00:00'],['2021-12-1612:00:00'],['2021-12-1700:00:00'],['2021-12-1700:00:00'],['2021-12-0200:00:00'],['2021-11-1300:00:00'],['2021-12-1700:00:00'],['2021-11-1812:00:00'],['2021-12-1612:00:00'],['2021-12-1412:00:00'],['2021-12-1700:00:00']],dtype=object)>>>pd.to_datetime(df['date'])

本例的需求非常容易解決,再稍微探索下它更多的用法。

pd.to_datetime(arg:Union[~DatetimeScalar,List,Tuple,~ArrayLike,ForwardRef('Series')],errors:str='raise',#產生錯誤的處理方式dayfirst:bool=False,#日在首位yearfirst:bool=False,#年份在首位utc:Union[bool,NoneType]=None,#是否返回時區format:Union[str,NoneType]=None,#格式exact:bool=True,#是否精確地按格式匹配unit:Union[str,NoneType]=None,#時間單位,默認nsinfer_datetime_format:bool=False,#根據判斷第一個日期作為基準,較少後續的日期推斷origin='unix',#參考日曆cache:bool=True,)

它的參數都是很有作用的,但也是有常用與不常用的區分,如需了解所有參數的含義,可以參考官方文檔及python的內置模塊datetime。下面分享幾個我常用的。

errors,轉換過程中發生錯誤處理

有三個選項,分別為:raise,coerce,ignore,設定後效果分別為:立即返回報錯,中斷代碼運行;將不能轉換的值用pd.NaT代替返回;忽略報錯,使用原值返回,這裡有個誤區,只要有錯誤發生,它不會單獨跳過這一不能轉換的值,而是不會轉換所有的數據以原數據類型返回。

format,輸入的日期格式

當輸入的日期不能讓pd.to_datetime很好的識別轉換時,就輪到它上場了。更多格式用法轉:[datetime]https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior

樣例:

pd.to_datetime(['03Apr2022','04-Apr-2022','2022-01-01','20220101','2022/01/01','Oct102021','010122',#日月年'020122',#月日年'220101'],#年月日unit='ns')

可以看到幾個對應顏色的再轉換過程出了點意外,在未設置format參數時,都可以很好的轉換,在需要轉換的日期列中,只要格式不是特別特殊的情況下完全不用設置format參數。

因為後面三個日期數據的年份是用兩個字符組成的,且位置漂浮不定,這時設置format,設置之後也只能特定日期做轉換,用法看參照datetime.datetime.strptime

#不接收單獨字符串傳入,可以使用列表,元組等其他容器類型將日期字符串放進去#轉換'010122'日月年>>>pd.to_datetime(['010122'],format='%d%m%y')DatetimeIndex(['2022-01-01'],dtype='datetime64[ns]',freq=None)#轉換'020122'月日年>>>pd.to_datetime(['020122'],format='%m%d%y')DatetimeIndex(['2022-02-01'],dtype='datetime64[ns]',freq=None)#轉換'220301'年月日>>>pd.to_datetime(['220301'],format='%y%m%d')DatetimeIndex(['2022-03-01'],dtype='datetime64[ns]',freq=None)

其他格式類似。

infer_datetime_format,將後續的日期格式用第一個轉換的日期格式匹配,默認False。

這個參數在提高轉換效率上有很大的幫助,在沒有設定format的情況下,將這個參數設定為True(infer_datetime_format=True),需要轉換的日期類型格式高度一致時,可以極大地減少轉換時間,官方稱能提高5至10倍的效率。也就是說它會蒙第一個需要轉換的日期格式,蒙對後,後續的日期轉換都按這個來,不用再去蒙格式了。

unit,時間單位,默認ns

上面的例子中的都是對字符串轉換,也有提到過幾乎不用設置日期格式就能轉換日期,還有一種在日期操作中經常會遇見的格式,就是時間戳類型的數據,這個轉換為日期當然也不在話下,同樣可以與上述日期轉換混合在一起使用,而又注意到,轉換後的時間單位都是ns,所以在未設置unit參數為其他單位時,需要傳入ns為單位的時間戳數據。

可以針對時間戳數據設置不同的unit參數來轉換,當然同次轉換的列中單位理應一致。

#ms>>>pd.to_datetime([1648195805123],unit='ms')DatetimeIndex(['2022-03-2508:10:05.123000'],dtype='datetime64[ns]',freq=None)#s>>>pd.to_datetime([1648195805],unit='s')DatetimeIndex(['2022-03-2508:10:05'],dtype='datetime64[ns]',freq=None)#D>>>pd.to_datetime([19076],unit='D')DatetimeIndex(['2022-03-25'],dtype='datetime64[ns]',freq=None)
origin,其實日期設置

可能會好奇這些數怎麼會能夠跳躍到當前日期。在這裡都是因為origin參數的設定,默認是unix,即起始時間為時區為0時區的1970-01-01,所以為什麼在使用pd.to_datetime的時候,特別在用時間戳轉換時間中有時會不對,則是此中的道理,固然可以設置origin參數,使時間戳在這個基準上進行相加,直至轉換完成。

>>>pd.to_datetime([1,2,3],unit='D',origin=pd.Timestamp('1960-01-01'))DatetimeIndex(['1960-01-02','1960-01-03','1960-01-04']/ 總結

相信都已經了解了pd.to_datetime的相關用法,在pandas日期數據轉換中不妨試試pd.to_datetime方法,結合了datetime庫中datetime.strptime函數,減少其中部分參數的使用,在項目使用過程中也可以較少在意當日期格式發生變化時需要去調整日期格式,減少錯誤的發生,pandas中也沿用了許多datetime庫中的函數,更多格式類型可參考datetime的使用文檔。

這本該是青蔥楊柳的天氣,還是牡丹海棠的時節?

於二零二二年四月十二日作

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()