最近發現周圍的很多小伙伴們都不太樂意使用pandas,轉而投向其他的數據操作庫,身為一個數據工作者,基本上是張口pandas,閉口pandas了,故而寫下此系列以讓更多的小伙伴們愛上pandas。
系列文章說明:
系列名(系列文章序號)——此次系列文章具體解決的需求
平台:
最近在看一本關於使用pandas進行數據處理的書,於2020年出版,其中有一段對在線零售商品的銷售日期的處理,獲取日期列中對應的月初日期。數據讀取如下:
import pandas as pd
# 按照書中代碼,將InvoiceDate解析成日期類型
df = pd.read_csv('Online_Retail.csv.zip', parse_dates=['InvoiceDate'])
df = df.dropna().copy()
ps: 數據獲取方式:
github:
https://github.com/lk-itween/FunnyCodeRepository/raw/main/PandasSaved/data/Online_Retail.csv.zip
(406829, 9)
眾所周知,在現行日歷下每月的月初是當月的1號,獲取的方法也有很多,本文列舉一二。
在書中例子中給定的代碼就是將年月日分離,再將1號拼接成新的日期數據。
def get_month_start(x):
return datetime(x.year, x.month, 1)
df['MonthStart'] = df['InvoiceDate'].map(get_month_start)
pandas
中也有對時間變量進行處理的函數,獲取月初月末日期也是可以不用自己擬寫邏輯。但使用時需注意,以下為演示過程中出現的部分情況及對應的解決辦法。
from pandas.tseries.offsets import MonthBegin, MonthEnd
# 構造演示樣例
df2 = pd.to_datetime(['2022-9-1', '2022-9-2', '2022-9-29', '2022-9-30',
'2022-10-1', '2022-10-2', '2022-10-30', '2022-10-31']).to_frame(name='date')
將間隔參數n
設置成0,即為獲取當月的月初月末日期,在圖中可以清晰的看出當僅為月初日期時才能正確的獲取當月月初日期,其余日期將獲取成下月月初日期,而月末日期可以正確獲取。
再將間隔參數n
設置為1,獲取下一月日期,效果如下:
此時月初函數是可以正確獲取到下一月的月初日期,而月末函數只有當日期為月末時才能正確獲取下月月末日期。
如何正確獲取上述錯誤情況的日期,已正確獲取的不再贅述,可得知,獲取下月初的情況和獲取本月末的函數是對的,可以對正確的結果做一次加減法後轉換成正確的目標值。
本月月初:
下月月末:
df[‘InvoiceDate’]中的日期數據是包含時間的,在獲取月初月末時並不會將時間給剔掉,使用.dt.floor('D')
截取成日期後再獲取。
df['InvoiceDate'].dt.floor('D') + MonthBegin() - MonthBegin()
使用這個方法轉換所需時間相比書中給出的方法是非常少的。
(手動水印:原創CSDN宿者朽命,https://blog.csdn.net/weixin_46281427?spm=1011.2124.3001.5343 ,公眾號A11Dot派)
在pandas中可以生成周期型的日期數據,當然可以將日期轉換成周期,本篇需要獲取的是月初月末日期,則需要將日期轉換成以月為單位的周期數據。
df3 = pd.period_range('2021-10', '2022-05', freq='M').to_frame(name='date')
生成了一組以月為周期的日期數據。對於已經是日期類型的數據可以使用.dt.to_period
方法進行轉換。
周期型數據相比日期的dt
方法,多了start_time
和end_time
,分別獲取當前日期的月初日期和月末日期。
由於end_time
會直接返回毫秒級的最後一個時刻,需要用floor
截取出日期。
還可以用dt.asfreq
獲取月初月末日期,接受兩個參數:
freq : str # 一個頻率參數,如A代表年,M代表月,D代表日
how : str {
'E', 'S'}
# 最後: 'E', 'END', or 'FINISH' for end,
# 開始: 'S', 'START', or 'BEGIN' for start.
需要將月周期轉換為日周期,結果為當月的開始,可以這樣設置:
df3['date'].dt.asfreq('D', how='S')
若要返回的是月的結束,則可以這樣設置,參數名稱非必要,默認的結束日期:
df3['date'].dt.asfreq('D', 'E')
對比兩種在示例數據中的耗時情況。
asfreq
似乎要比start_time
耗時短一點,同時注意到轉換後的結果類型不一樣,兩個的dt方法的部分屬性、方法有所不同,若需要將周期類型轉換成日期類型,可以將asfreq
更改成to_timestamp
,參數一致,耗時略微長一點,結果與start_time
類似。
注:
文章使用數據為日期類型,若日期作為字符串Series
類型,可通過pd.to_datetime(s, format),將format設定為對應格式參數轉換成日期類型後再測試文章提及的幾種方法。
源數據可通過文章開頭處獲取。
本文通過引入示例,分別闡述pandas
在獲取月初月末日期的幾種方法,顯然還有其他的方法進行獲取,pandas
中將日期處理成向量化的操作,相較於初始化datetime
類型數據,方法簡便、高效,在系列文章的前幾篇也有提到過,向量化的操作普遍比參數定義,初始化的執行效率上要高。
驟雨狂風欲催人倒,定叫天公刮目相看。
於二零二二年六月二十四日作