Pandas 提供了 TimestampDatetimeIndexPeriodPeriodIndex 等資料結構,簡化了時序資料的操作。利用 pd.to_datetime 可將字串或數字轉換為 Timestamp 物件,而 pd.date_range 能夠生成特定頻率的日期序列,作為 DatetimeIndex 使用。PeriodPeriodIndex 則適用於以固定時間段(如月、季度、年)為單位的分析。此外,Pandas 還提供了時區處理功能,方便在不同時區間轉換和比較日期時間。

import pandas as pd

# 建立時間序列
rng = pd.date_range('1/1/2024', periods=100, freq='S')
ts = pd.Series(range(len(rng)), index=rng)

# 重取樣與聚合
ts_minutes = ts.resample('Min').sum()

# 日期偏移
from pandas.tseries.offsets import DateOffset
ts_shifted = ts + DateOffset(months=1)

# 時區處理
ts_localized = ts.tz_localize('Asia/Taipei')
ts_converted = ts_localized.tz_convert('US/Eastern')

時序資料型別與演算法

處理時序資料(即日期和時間)看似簡單,但深入探討後會發現其複雜性超乎想像。以下是幾個常見問題:

  • 有的使用者以年為單位衡量時間,而有的則精確到奈秒
  • 有的使用者忽略時區,而有的需要在全球範圍內協調事件的時間
  • 並非所有國家都有多個時區,即使領土寬廣(如中國)
  • 不是所有國家都實施夏令時,即使實施,具體實施時間也各不相同
  • 在實施夏令時的國家中,也不是所有地區都參與(如美國的亞利桑那州)
  • 不同作業系統和版本對時間的處理方式不同(參見Year2038問題)

這些問題只是冰山一角。儘管存在諸多潛在的資料品質問題,時序資料對於監控、趨勢分析和預測仍具有極高的價值。

幸運的是,pandas使得分析時序資料變得簡單,無需成為日期和時間的專家。透過玄貓的方法,可以輕鬆清洗和插值時序資料,從而將注意力集中在資料洞察上,而不是日期和時間的“問題”。

本章將深入探討pandas提供的時序資料型別和相關功能,涵蓋時區處理、日期偏移、日期時間選擇、重取樣等主題,並透過實際案例展示時序資料的應用。

本章涵蓋內容

  • 時區處理
  • 日期偏移
  • 日期時間選擇
  • 重取樣
  • 每週犯罪和交通事故彙總
  • 按月計算犯罪率的同比變化
  • 精確測量帶有缺失值的感測器資料

時區處理

時區誤解是時序資料處理中常見的問題。在美國東海岸,許多使用者試圖從資料函式庫中讀取日期,但最終的分析結果卻因時區差異而出現偏差。

問題根源

  • 資料函式庫中的時間戳通常是UTC時間
  • 使用者在本地時區(如美國東海岸)進行分析時,未正確轉換時區
  • 時區轉換錯誤導致日期分組(如週、月、季度、年)時出現偏差

解決方案

pandas提供了強大的時區處理功能,可以輕鬆建立和識別時區感知(timezone-aware)和時區無知(timezone-naive)的日期時間物件。

import pandas as pd

# 建立時區無知的日期時間序列
ser = pd.Series([
    "2024-01-01 00:00:00",
    "2024-01-02 00:00:01",
    "2024-01-03 00:00:02"
], dtype="datetime64[ns]")

# 檢查是否為時區無知
print(ser.dt.tz is None)  # 輸出:True

# 將時區設定為America/New_York,使其成為時區感知
ny_ser = ser.dt.tz_localize("America/New_York")
print(ny_ser)

# 將時區轉換為America/Los_Angeles
la_ser = ny_ser.dt.tz_convert("America/Los_Angeles")
print(la_ser)

# 移除時區資訊
la_ser_no_tz = la_ser.dt.tz_localize(None)
print(la_ser_no_tz)

時區資訊儲存與還原

在某些情況下,可能需要將時區資訊與日期時間分開儲存。pandas允許將時區資訊儲存在另一列中,並在需要時還原。

# 將時區資訊儲存在另一列
df = la_ser.to_frame().assign(
    datetime=la_ser.dt.tz_localize(None),
    timezone=str(la_ser.dt.tz),
).drop(columns=[0])

# 顯示結果
print(df)

# 還原時區資訊
tz = df["timezone"].drop_duplicates().squeeze()
df["datetime"].dt.tz_localize(tz)

日期偏移

日期偏移是時序資料處理中的另一個重要概念。pandas提供了DateOffset物件來表示日期偏移。

from pandas.tseries.offsets import DateOffset

# 建立日期偏移物件
offset = DateOffset(days=1)

# 對日期時間進行偏移
ser_offset = ser + offset
print(ser_offset)

日期時間選擇

pandas允許根據特定條件選擇日期時間。

# 選擇特定日期範圍內的資料
ser_selected = ser[(ser >= '2024-01-02') & (ser < '2024-01-03')]
print(ser_selected)

重取樣

重取樣是時序資料分析中的重要技術,可以將資料從一個時間頻率轉換到另一個。

# 將資料重取樣為每週頻率
ser_resampled = ser.resample('W').mean()
print(ser_resampled)

每週犯罪和交通事故彙總

透過重取樣和彙總,可以對時序資料進行更高層次的分析。

# 假設有犯罪和交通事故資料
crime_data = pd.Series([...], index=pd.date_range('2024-01-01', periods=100))
traffic_data = pd.Series([...], index=pd.date_range('2024-01-01', periods=100))

# 每週彙總
weekly_crime = crime_data.resample('W').sum()
weekly_traffic = traffic_data.resample('W').sum()

print(weekly_crime)
print(weekly_traffic)

按月計算犯罪率的同比變化

計算同比變化可以幫助分析資料的長期趨勢。

# 按月重取樣
monthly_crime = crime_data.resample('M').sum()

# 計算同比變化
yoy_change = monthly_crime.pct_change(12)

print(yoy_change)

精確測量帶有缺失值的感測器資料

對於帶有缺失值的感測器資料,可以使用插值方法進行處理。

# 假設感測器資料
sensor_data = pd.Series([...], index=pd.date_range('2024-01-01', periods=1000))

# 插值處理缺失值
sensor_data_interpolated = sensor_data.interpolate()

print(sensor_data_interpolated)
圖表翻譯:

此圖示展示了時序資料處理的各個方面,包括時區處理、日期偏移、日期時間選擇、重取樣、資料彙總、同比變化分析和缺失值處理。這些技術共同構成了時序資料分析的基礎。

日期偏移與時間序列操作

在處理時間序列資料時,經常需要對日期進行偏移操作。Pandas 提供了 pd.DateOffsetpd.offsets 模組來實作這一功能。

使用 pd.DateOffset 進行日期偏移

pd.DateOffset 允許我們根據不同的時間單位(如月、日、時、分、秒)對日期進行偏移。

import pandas as pd

# 建立一個包含日期的 Series
ser = pd.Series([
    "2024-01-01",
    "2024-01-02",
    "2024-01-03",
], dtype="datetime64[ns]")

# 將日期偏移一個月
offset_ser = ser + pd.DateOffset(months=1)
print(offset_ser)

程式碼解析:

此程式碼首先建立了一個包含三個日期的 pd.Series,資料型別為 datetime64[ns]。然後使用 pd.DateOffset 將這些日期偏移一個月。輸出的結果顯示了偏移後的日期。

處理不存在的日期

當試圖將日期偏移到一個不存在的日期時(例如,將 1 月 30 日偏移到 2 月),pd.DateOffset 會自動調整到該月存在的最近日期。

# 將 1 月 29、30、31 日偏移到 2 月
ser2 = pd.Series([
    "2024-01-29",
    "2024-01-30",
    "2024-01-31",
], dtype="datetime64[ns]")
offset_ser2 = ser2 + pd.DateOffset(months=1)
print(offset_ser2)

程式碼解析:

此範例展示了當偏移日期到不存在的日期時(如 2 月 30 日),pd.DateOffset 如何自動調整到該月的最後一天(2 月 29 日)。

同時進行多個時間單位的偏移

pd.DateOffset 支援同時指定多個時間單位進行偏移。

# 同時進行多個時間單位的偏移
offset_ser3 = ser + pd.DateOffset(months=1, days=2, hours=3, minutes=4, seconds=5)
print(offset_ser3)

程式碼解析:

此範例展示瞭如何同時對日期進行多個時間單位的偏移,包括月、日、時、分、秒。

使用 pd.offsets 模組

pd.offsets 模組提供了多種方便的類別,用於將日期偏移到特定時間段的開始或結束。

# 將日期偏移到月末
month_end_ser = ser + pd.offsets.MonthEnd()
print(month_end_ser)

# 將日期偏移到下個月初
month_begin_ser = ser + pd.offsets.MonthBegin()
print(month_begin_ser)

程式碼解析:

此範例展示瞭如何使用 pd.offsets.MonthEndpd.offsets.MonthBegin 將日期分別偏移到月末和下個月初。

商業日期偏移

pd.offsets.BusinessDaypd.offsets.CustomBusinessDay 允許根據工作日進行日期偏移。

# 將日期偏移3個工作日
bd_ser = ser + pd.offsets.BusinessDay(n=3)
print(bd_ser)

# 自定義工作日規則
custom_bd_ser = ser + pd.offsets.CustomBusinessDay(n=3, weekmask="Mon Tue Wed Thu")
print(custom_bd_ser)

程式碼解析:

此範例展示瞭如何使用 pd.offsets.BusinessDay 進行工作日偏移,以及如何使用 pd.offsets.CustomBusinessDay 自定義工作日規則。

時間序列選擇

Pandas 的 pd.DatetimeIndex 提供了靈活的時間序列選擇功能。

使用 pd.date_range 建立 pd.DatetimeIndex

pd.date_range 函式可以用來快速建立 pd.DatetimeIndex

# 建立一個從2023-12-27開始,間隔10天,總共5個日期的 DatetimeIndex
dti = pd.date_range(start="2023-12-27", freq="10D", periods=5)
print(dti)

程式碼解析:

此範例展示瞭如何使用 pd.date_range 建立一個指定起始日期、頻率和長度的 pd.DatetimeIndex

不同頻率的日期生成

可以透過調整 freq 引數來生成不同頻率的日期。

# 生成間隔2周的日期,錨定在星期三
dti_weekly = pd.date_range(start="2023-12-27", freq="2W-WED", periods=5)
print(dti_weekly)

# 生成每月的第三個星期四
dti_monthly = pd.date_range(start="2023-12-27", freq="WOM-3THU", periods=5)
print(dti_monthly)

程式碼解析:

此範例展示瞭如何透過調整 freq 引數來生成不同頻率的日期,包括間隔兩周且錨定在星期三的日期,以及每月的第三個星期四。

  graph LR
A[開始] --> B{選擇日期頻率}
B -->|固定間隔| C[使用pd.date_range建立DatetimeIndex]
B -->|工作日偏移| D[使用pd.offsets進行日期偏移]
C --> E[指定起始日期和頻率]
D --> F[選擇適當的偏移類別]
E --> G[生成DatetimeIndex]
F --> G
G --> H[進行時間序列分析]

圖表解析:

此圖示展示了時間序列操作的主要流程。首先選擇日期頻率,然後根據選擇的頻率使用 pd.date_rangepd.offsets 進行日期操作,最後生成 pd.DatetimeIndex 並進行時間序列分析。

時間資料型別與演算法

在處理時間序列資料時,pandas 提供了豐富的功能和靈活的工具。時間序列分析的基礎是正確理解和使用 pd.DatetimeIndex 和相關的操作。

日期範圍的生成

使用 pd.date_range 函式可以生成具有特定頻率的日期範圍。例如,要生成每月的第一天和第十五天,可以使用以下程式碼:

import pandas as pd

# 生成每月的第一天和第十五天
index = pd.date_range(start="2023-12-27", freq="SMS", periods=5)
print(index)

內容解密:

此程式碼片段展示瞭如何使用 pd.date_range 函式生成特定的日期範圍。引數 freq="SMS" 表示生成每月的第一天和第十五天。輸出的 DatetimeIndex 包含了生成的日期序列。

時間戳的選擇

在進行時間序列資料選擇時,可以使用 pd.Timestamp 物件或直接使用日期字串。例如:

# 生成具有特定頻率的日期範圍
index = pd.date_range(start="2023-12-27", freq="10D", periods=20)
ser = pd.Series(range(20), index=index)

# 使用日期字串選擇資料
print(ser.loc["2024-01-06":"2024-01-18"])

內容解密:

此範例展示瞭如何使用日期字串直接進行資料選擇。ser.loc["2024-01-06":"2024-01-18"] 這行程式碼選擇了日期在 2024-01-06 至 2024-01-18 之間的資料。pandas 自動將字串轉換為適當的 Timestamp 物件進行比較。

時區感知

在處理時區相關的時間序列資料時,可以使用 tz 引數指定時區。例如:

# 生成具有時區的日期範圍
index = pd.date_range(start="2023-12-27", freq="12h", periods=6, tz="US/Eastern")
ser = pd.Series(range(6), index=index)
print(ser)

內容解密:

此範例展示瞭如何生成具有時區資訊的 DatetimeIndextz="US/Eastern" 指定了時區為美國東部時間。在選擇資料時,pandas 會根據時區進行適當的轉換。

重取樣

重取樣是將時間序列資料從一個頻率轉換到另一個頻率的過程。例如,將秒級資料轉換為每3秒的資料:

# 生成秒級別的日期範圍
index = pd.date_range(start="2024-01-01", periods=10, freq="s")
ser = pd.Series(range(10), index=index)

# 重取樣到每3秒
print(ser.resample("3s").sum())

內容解密:

此範例展示瞭如何使用 resample 方法將秒級別的時間序列資料重取樣到每3秒的頻率。預設情況下,重取樣使用左閉右開的區間,並使用區間的左端點作為結果的索引。

Mermaid 圖表:時間序列處理流程

  flowchart TD
 A[開始] --> B{選擇資料}
 B -->|使用日期範圍| C[生成日期序列]
 B -->|使用時區| D[處理時區資料]
 C --> E[重取樣]
 D --> E
 E --> F[分析結果]

圖表翻譯:

此圖示展示了時間序列資料處理的基本流程。流程從「開始」開始,根據不同的需求選擇資料。可以根據日期範圍生成日期序列,或處理具有時區的資料。最終,這些資料都會經過重取樣步驟,並對結果進行分析。這個流程清晰地展示了時間序列資料處理的關鍵步驟和可能的路徑。