聊天視窗

掌握時序預測:Python 與統計學的實務指南 - 第 2 章

第 2 章:Python 時序資料工具

發布於 2026-02-21 11:21

# 第 2 章:Python 時序資料工具 > 本章將深入探討 Python 生態系中處理時序資料的核心工具:**Pandas**、**NumPy**、**Matplotlib** 與 **Seaborn**。透過實際範例與最佳實踐,讀者將能快速將原始時間序列資料轉為可供分析、可視化與建模的結構。 --- ## 2.1 Pandas 時序資料結構與操作 ### 2.1.1 `DatetimeIndex`、`PeriodIndex` 與 `TimedeltaIndex` | 物件 | 主要用途 | 典型範例 | |------|----------|----------| | `DatetimeIndex` | 以秒級(或更高)為基礎的時間點索引 | `pd.date_range(start='2020-01-01', periods=100, freq='D')` | | `PeriodIndex` | 以「期間」為基礎(如月、季) | `pd.period_range(start='2020-01', periods=12, freq='M')` | | `TimedeltaIndex` | 表示兩個時間點之差 | `pd.timedelta_range(start='0 days', periods=5, freq='H')` | > **注意**:`DatetimeIndex` 允許對時間進行「對齊(align)」、「重採樣(resample)」與「頻率轉換」;`PeriodIndex` 更適合處理「月度報表」或「季度財報」;`TimedeltaIndex` 常用於「滯後特徵」與「時間差」的計算。 ### 2.1.2 建立時序資料集 ```python import pandas as pd import numpy as np # 1. 產生日序列 dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D') # 2. 產生對應的隨機數值(例如每日銷售額) np.random.seed(42) values = np.random.poisson(lam=200, size=len(dates)) # 3. 建立 DataFrame sales = pd.DataFrame({'date': dates, 'sales': values}) # 將 date 設為索引 sales.set_index('date', inplace=True) print(sales.head()) ``` 輸出示例: ``` sales date 2023-01-01 179 2023-01-02 213 2023-01-03 195 2023-01-04 210 2023-01-05 197 ``` ### 2.1.3 常用操作 | 操作 | 目的 | 範例 | |------|------|------| | `df.resample()` | 重新採樣(例如將日資料轉為週資料) | `weekly = sales.resample('W').sum()` | | `df.shift()` | 計算滯後值 | `sales['lag1'] = sales['sales'].shift(1)` | | `df.asfreq()` | 填補缺失頻率 | `sales = sales.asfreq('D')` | | `df.between_time()` | 擷取指定時間段 | `morning = df.between_time('08:00', '12:00')` | | `df.tz_localize()/tz_convert()` | 時區處理 | `df.tz_localize('UTC').tz_convert('Asia/Taipei')` | ### 2.1.4 索引重設與切片 ```python # 重設索引為整數 sales_reset = sales.reset_index() print(sales_reset.head()) # 切片操作 # 1) 取 2023-03-01 到 2023-03-31 的資料 march_sales = sales.loc['2023-03-01':'2023-03-31'] # 2) 取 2023 年前 100 天 first_100 = sales.iloc[:100] ``` ### 2.1.5 合併與連接 | 方法 | 何時使用 | 範例 | |------|----------|------| | `pd.concat()` | 垂直或水平拼接 | `pd.concat([df1, df2])` | | `df.merge()` | SQL join | `df1.merge(df2, on='id', how='left')` | | `df.join()` | 基於索引的簡易 join | `df1.join(df2)` | > **實務提醒**:在合併多個時序資料時,務必先確認索引的頻率與時區,避免「跨時區重疊」造成資料錯位。 --- ## 2.2 NumPy:基礎數值運算與時間序列 ### 2.2.1 時間序列數值化 ```python # 產生 1 年每日日期 np_dates = np.arange('2023-01-01', '2024-01-01', dtype='datetime64[D]') print(np_dates[:5]) # 2023-01-01, 2023-01-02, ... # 轉為秒數(自 1970-01-01 以來的秒) seconds = np_dates.astype('datetime64[s]').astype(int) print(seconds[:5]) ``` ### 2.2.2 週期性函式 ```python # 生成 2 週的正弦波,週期為 14 天 period = 14 days = np.arange(0, 30) sin_wave = np.sin(2 * np.pi * days / period) print(sin_wave) ``` > **應用**:`numpy.sin()` 與 `numpy.cos()` 可直接用於建立「季節性滯後特徵」或「波形預測」時的基礎函式。 --- ## 2.3 Matplotlib 與 Seaborn:時間序列可視化技巧 ### 2.3.1 基本折線圖 ```python import matplotlib.pyplot as plt plt.figure(figsize=(10, 4)) sales.plot(kind='line', title='Daily Sales (2023)') plt.ylabel('Sales') plt.xlabel('Date') plt.tight_layout() plt.show() ``` ### 2.3.2 重新採樣視覺化 ```python # 週總銷售額 weekly_sum = sales.resample('W').sum() plt.figure(figsize=(10, 3)) weekly_sum.plot(title='Weekly Total Sales') plt.show() ``` ### 2.3.3 季節性子圖(Seasonal Decomposition) ```python from pandas.plotting import register_matplotlib_converters register_matplotlib_converters() # 兼容 pandas 時間索引 # 以月為單位的季節性圖 monthly = sales.resample('M').sum() fig, ax = plt.subplots(3, 4, figsize=(15, 8), sharex=True) for i, month in enumerate(monthly.index): ax[i//4, i%4].bar(month, monthly['sales'], width=1) ax[i//4, i%4].set_title(str(month)) ax[i//4, i%4].tick_params(axis='x', rotation=45) plt.tight_layout() plt.show() ``` ### 2.3.4 自動相關圖 (ACF) ```python from pandas.plotting import lag_plot lag_plot(sales['sales'], lag=1, title='Lag‑1 Plot') plt.show() ``` > **解釋**:ACF(自動相關函式)可視化資料在不同滯後下的相關性,對於檢查「隨機游走」或「季節性」特徵尤為重要。 ### 2.3.5 Seaborn 風格化折線圖 ```python import seaborn as sns sns.set_style('whitegrid') # 以 Seaborn 的 FacetGrid 對不同月份的折線進行子圖顯示 sales_reset = sales.reset_index() sales_reset['month'] = sales_reset['date'].dt.month sns.lineplot(data=sales_reset, x='date', y='sales', hue='month') plt.title('Monthly Sales Trend with Seaborn') plt.show() ``` --- ## 2.4 進階可視化:從原始資料到分析洞察 ### 2.4.1 熱度圖(Heatmap) - 週/日時間結構 ```python # 建立一個 7 天 × 24 小時的數據矩陣(假設每小時銷售) hours = np.arange(24) weeks = np.arange(7) heat_data = np.random.poisson(lam=10, size=(7, 24)) plt.figure(figsize=(8, 5)) sns.heatmap(heat_data, cmap='viridis', xticklabels=hours, yticklabels=['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']) plt.title('Weekly Hourly Sales Heatmap') plt.xlabel('Hour of Day') plt.ylabel('Day of Week') plt.show() ``` > **洞察**:熱度圖能快速揭露「高峰時段」與「週末效應」。 ### 2.4.2 分布圖(Distribution)與箱型圖(Boxplot) ```python # 資料分布 sns.histplot(sales['sales'], bins=30, kde=True) plt.title('Sales Distribution') plt.xlabel('Sales') plt.show() # 箱型圖:各月銷售箱型圖 monthly_sales = sales.resample('M').sum() monthly_sales.plot(kind='box', title='Monthly Sales Boxplot') plt.show() ``` ### 2.4.3 互補函式:`pandas.plotting` 模組 ```python from pandas.plotting import autocorrelation_plot autocorrelation_plot(sales['sales']) plt.title('Autocorrelation of Sales') plt.show() ``` --- ## 2.5 版本與環境建議 | 套件 | 建議版本 | 安裝指令 | |------|----------|----------| | Pandas | ≥ 2.0 | `pip install pandas>=2.0` | | NumPy | ≥ 1.26 | `pip install numpy>=1.26` | | Matplotlib | ≥ 3.8 | `pip install matplotlib>=3.8` | | Seaborn | ≥ 0.13 | `pip install seaborn>=0.13` | > 建議使用 **Python 3.10+** 以確保 `datetime64` 的完整功能,並使用 **JupyterLab** 或 **VSCode + Jupyter** 進行交互式開發。 --- ## 2.6 小結 在本章中,我們掌握了以下關鍵能力: 1. **Pandas**:建立、索引、重採樣、合併與特徵工程; 2. **NumPy**:數值化時間、生成週期性波形; 3. **Matplotlib & Seaborn**:創建折線、子圖、熱度圖與自動相關圖。 這些工具為後續章節(模型建立、參數調整、模型評估)奠定了堅實的基礎。 --- > **實作練習**: > > 1. 下載 Kaggle `daily-sales` 資料集,重建 `DatetimeIndex`,並使用 `resample('W')` 生成每週銷售總額。 > 2. 利用 `statsmodels.tsa.stattools.adfuller` 進行單位根檢定前,先將資料做 7 天滑動平均。 > 3. 使用 Seaborn 的 `pairplot` 對 `sales` 與滯後特徵做可視化探索。 > > (提示:可使用 `pip install -U statsmodels` 取得最新 ADF 版本。)