Tech
Python
Jade Lin
May 2022
要將字串轉換成 datetime
,相比同功能的函式,pandas.to_datetime
的效能應該是滿好的。我是參考這裡。
如果查 to_datetime
效能問題,可能會得到一些回答。但是如果該做的都做了,卻比別人測出來的慢超多,或甚至就像我遇到的案例,明明什麼都沒改,偏偏就是有的處理會特別慢呢?這可能和資料特性有關…
部門的專案裡,有一個小程式,每次會從資料庫,拉取資料做處理。隨著資料量越來越大,從資料庫拉取資料的時間變得太長,以致於該程式無法在目標時間內消化完資料。於是DBA提供另一個語法,讓我測試看看能提升多少拉取資料的速度。原本的語法必須經過某個排序,而新的語法不經過排序(若排序也有額外的效能問題),但最後取得的資料是一樣的,只是順序不同。
於是我用新的語法,測試從資料庫拉取大量資料,觀察到時間上有大幅度的改善,就很開心的把程式正式更改成這種新語法。
BUT!人生就是有這樣的BUT!程式實際運作後,卻發現程式的總處理時間變得更長了?!我可以很確定我沒有改到其它部分,那……只好進去挖到底是哪裡變慢了……
在這個小程式處理這些資料的過程中,需要將部份欄位的值做格式轉換。其中有些是日期字串,要轉成
datetime
,尤其面對的資料,不同欄位也會含有不同格式的日期字串。最後選擇使用to_datetime
,實際運作起來,效能的確也滿不錯。但現在單純只是資料順序改變,在轉換日期的效能變得極差,變差時的執行時間甚至超過十倍 =.=
實在太奇怪了,於是 trace code 到 pandas 裡,才發現原來
to_datetime
有是否快取的差異……
進入本篇的主題:pandas.to_datetime
如果仔細看官方文件,to_datetime 有一個引數藏在最後面:cache
cache: bool, default True
If True, use a cache of unique, converted dates to apply the datetime conversion. May produce significant speed-up when parsing duplicate date strings, especially ones with timezone offsets. The cache is only used when there are at least 50 values. The presence of out-of-bounds values will render the cache unusable and may slow down parsing.
這裡提到,對有重複的日期字串的資料,開啟快取能有很大幅度的加速。另外,在50筆資料以下不會啟用快取。
但這段文字只說到這,單看這個也不會覺得有什麼關係,畢竟cache
預設值是True
,那應該表示只要大於50筆資料,就是要有快取吧?呵呵,才不是呢 =.=
仔細看 pandas datetime source code
會看到引數cache
會傳入_maybe_cache
,而這裡的引數cache
只是初步看要不要試著做快取。所以當cache == False
就肯定不會做快取,可能用於幾乎沒有重複的資料上。
若直接用預設值cache == True
呼叫,則決定是否做快取的邏輯,實際上會在should_cache
函式裡。此時會看到這段文字:
By default for a sequence of less than 50 items in size, we don't do caching; for the number of elements less than 5000, we take ten percent of all elements to check for a uniqueness share; if the sequence size is more than 5000, then we check only the first 500 elements.
All constants were chosen empirically by.
個人解讀:
所以資料內容是會影響是否啟用快取的。那怎麼"檢查資料差異性有多大"?
這裡我們以5000筆資料來看:
check_count==500
unique_elements
unique_share==0.7
也就是說,一般以預設值下去運作的話,超過5000筆資料,它會取前500筆資料,計算不重複的值的數量,若超過 500*0.7 = 350
的數量,即認定資料差異性過大,它就不會做快取;反之,若是<=350 的話,表示資料差異性不大,它就會執行快取的機制,來加速日期的轉換。
至於當資料在50~5000筆之間時,也是取10%的值來判斷要不要做快取,但是畢竟數量不大,有沒有差距可能也不會太明顯。
到這裡就可以理解我遇到的案例,只是資料的順序改變了,卻造成巨大的效能差異的原因。
%Y-%m-%dT%H:%M:%S.%f%z
轉換單欄資料,從字串轉成datetime
:
data counts | spent time | with cache |
---|---|---|
13,995 | 0.051s | YES |
13,995 | 0.581s | NO |
848,990 | 3.626s | YES |
848,990 | 41.954s | NO |
可以看出,以這程式面對到的資料特性來說,基於同樣的機器環境、處理同樣的資料,使用快取與否,造成極大的效能差異。
注意資料順序可能會影響到處理的效能。根據面對到的資料特性,可以注意一下是否有遇到相似的狀況,再視情況看怎麼調整出最好的使用方式。
我遇到的案例,後來是在轉換日期前,先將資料做排序。因為即使排序多花費了幾秒,對於因此省下來的轉換時間,還是遠遠值得啊~~
還有,註解真的是很棒的東西。不然在 trace code 時,應該會花更多的時間在猜作者的想法吧!