Pandas 日期時間處理
Pandas 提供了強大的日期時間處理功能,可以輕鬆解析、操作和分析時間序列資料。
建立日期時間
從字串轉換
import pandas as pd
# 單一日期
date = pd.to_datetime('2024-01-15')
print(date) # 2024-01-15 00:00:00
# Series 轉換
s = pd.Series(['2024-01-01', '2024-01-15', '2024-02-01'])
dates = pd.to_datetime(s)
print(dates)
指定格式
# 自訂格式
s = pd.Series(['01/15/2024', '02/20/2024'])
dates = pd.to_datetime(s, format='%m/%d/%Y')
# 常見格式碼
# %Y - 四位年份 (2024)
# %m - 月份 (01-12)
# %d - 日期 (01-31)
# %H - 小時 (00-23)
# %M - 分鐘 (00-59)
# %S - 秒 (00-59)
處理錯誤
s = pd.Series(['2024-01-01', 'invalid', '2024-02-01'])
# 錯誤時回傳 NaT(Not a Time)
dates = pd.to_datetime(s, errors='coerce')
# 錯誤時保持原值
dates = pd.to_datetime(s, errors='ignore')
建立日期範圍
# 連續日期
dates = pd.date_range('2024-01-01', periods=5)
# DatetimeIndex(['2024-01-01', '2024-01-02', '2024-01-03', '2024-01-04', '2024-01-05'])
# 指定結束日期
dates = pd.date_range('2024-01-01', '2024-01-10')
# 指定頻率
dates = pd.date_range('2024-01-01', periods=5, freq='W') # 每週
dates = pd.date_range('2024-01-01', periods=5, freq='M') # 每月
dates = pd.date_range('2024-01-01', periods=5, freq='H') # 每小時
日期時間屬性
透過 .dt accessor 存取日期時間的各種屬性:
df = pd.DataFrame({
'date': pd.to_datetime(['2024-01-15 10:30:45', '2024-06-20 14:15:30'])
})
df['year'] = df['date'].dt.year # 年份
df['month'] = df['date'].dt.month # 月份
df['day'] = df['date'].dt.day # 日期
df['hour'] = df['date'].dt.hour # 小時
df['minute'] = df['date'].dt.minute # 分鐘
df['second'] = df['date'].dt.second # 秒
df['weekday'] = df['date'].dt.weekday # 星期幾(0=週一)
df['day_name'] = df['date'].dt.day_name() # 星期名稱
df['quarter'] = df['date'].dt.quarter # 季度
df['dayofyear'] = df['date'].dt.dayofyear # 一年中的第幾天
判斷屬性
df['date'].dt.is_month_start # 是否月初
df['date'].dt.is_month_end # 是否月底
df['date'].dt.is_quarter_start # 是否季初
df['date'].dt.is_year_start # 是否年初
df['date'].dt.is_leap_year # 是否閏年
日期運算
時間差
df = pd.DataFrame({
'start': pd.to_datetime(['2024-01-01', '2024-02-15']),
'end': pd.to_datetime(['2024-01-10', '2024-03-01'])
})
# 計算天數差
df['days'] = (df['end'] - df['start']).dt.days
加減時間
from pandas import Timedelta
df = pd.DataFrame({
'date': pd.to_datetime(['2024-01-15', '2024-06-20'])
})
# 加 7 天
df['plus_7_days'] = df['date'] + Timedelta(days=7)
# 減 1 個月
df['minus_1_month'] = df['date'] - pd.DateOffset(months=1)
# 加 2 小時
df['plus_2_hours'] = df['date'] + Timedelta(hours=2)
常用 DateOffset
pd.DateOffset(days=1)
pd.DateOffset(weeks=1)
pd.DateOffset(months=1)
pd.DateOffset(years=1)
日期格式化
轉換成字串
df = pd.DataFrame({
'date': pd.to_datetime(['2024-01-15', '2024-06-20'])
})
df['formatted'] = df['date'].dt.strftime('%Y/%m/%d')
# '2024/01/15', '2024/06/20'
df['formatted'] = df['date'].dt.strftime('%Y年%m月%d日')
# '2024年01月15日', '2024年06月20日'
時區處理
df = pd.DataFrame({
'date': pd.to_datetime(['2024-01-15 10:00:00', '2024-01-15 14:00:00'])
})
# 設定時區
df['date_utc'] = df['date'].dt.tz_localize('UTC')
# 轉換時區
df['date_taipei'] = df['date_utc'].dt.tz_convert('Asia/Taipei')
過濾日期
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=100),
'value': range(100)
})
# 過濾特定日期範圍
mask = (df['date'] >= '2024-01-15') & (df['date'] <= '2024-02-15')
filtered = df[mask]
# 過濾特定月份
filtered = df[df['date'].dt.month == 1]
# 過濾特定星期
filtered = df[df['date'].dt.weekday == 0] # 週一
重新取樣(Resample)
對時間序列資料進行重新取樣(類似 groupby):
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=100, freq='D'),
'value': range(100)
})
df = df.set_index('date')
# 按月彙總
monthly = df.resample('M').sum()
# 按週平均
weekly = df.resample('W').mean()
# 常用頻率
# 'D' - 每天
# 'W' - 每週
# 'M' - 每月
# 'Q' - 每季
# 'Y' - 每年
# 'H' - 每小時
實際應用
計算年齡
df = pd.DataFrame({
'birthday': pd.to_datetime(['1990-05-15', '1985-10-20', '2000-01-01'])
})
today = pd.Timestamp.today()
df['age'] = (today - df['birthday']).dt.days // 365
計算工作天數
from numpy import busday_count
df = pd.DataFrame({
'start': pd.to_datetime(['2024-01-01', '2024-02-01']),
'end': pd.to_datetime(['2024-01-31', '2024-02-29'])
})
df['business_days'] = df.apply(
lambda row: busday_count(row['start'].date(), row['end'].date()),
axis=1
)
時間序列分析
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=365),
'sales': [100 + i % 30 for i in range(365)]
})
df = df.set_index('date')
# 計算移動平均
df['ma_7'] = df['sales'].rolling(window=7).mean()
# 計算同比(去年同期)
df['yoy'] = df['sales'].pct_change(periods=365)