返回目錄
A
掌握時序預測:Python 與統計學的實務指南 - 第 3 章
第 3 章 資料預處理與特徵工程
發布於 2026-02-21 11:45
# 第 3 章 資料預處理與特徵工程
在時序預測的工作流中,資料預處理與特徵工程往往是模型表現的關鍵決定因素。本章將系統化說明如何處理缺失值、平滑化、差分、對數變換,並介紹衍生季節指標與滾動特徵的設計。透過實際程式範例與圖示,我們將把理論落地於實務中。
---
## 3.1 缺失值處理
### 3.1.1 時序資料缺失的常見來源
| 來源 | 說明 |
|------|------|
| 觀測設備失效 | 例如氣象站偶發無法送達資料 |
| 交易系統停機 | 金融市場資料在假日或維護時段缺失 |
| 人為取樣 | 例如零售銷售每天錄入延遲 |
| 連續週期缺失 | 由於資料來源不穩定導致長時間缺口 |
缺失值會影響模型的學習與預測精度,尤其在時間序列中,缺失往往伴隨著 **序列連續性破壞**,因此處理方式需兼顧時間相依性。
### 3.1.2 主要處理方法
| 方法 | 適用情境 | 例子 |
|------|----------|------|
| 前向填補 (ffill) | 缺失值短且相對平滑 | `df['y'].fillna(method='ffill')` |
| 後向填補 (bfill) | 缺失值在開頭 | `df['y'].fillna(method='bfill')` |
| 插值 (interpolate) | 缺失值分布不均 | `df['y'].interpolate(method='time')` |
| 時間加權平均 | 季節性變動較大 | `df['y'].interpolate(method='polynomial', order=2)` |
| 模型補值 | 大量缺失且結構複雜 | 隨機森林、XGBoost 補值 |
> **小提示**:對於 **長期缺口**,最佳做法是結合 **外部資訊**(如同業指標、宏觀經濟變數)來預測缺失值,而非單純使用插值。
### 3.1.3 實作範例
python
import pandas as pd
# 讀取示例資料
df = pd.read_csv('sales.csv', parse_dates=['date'])
df.set_index('date', inplace=True)
# 檢查缺失值
print(df.isna().sum())
# 前向填補
df['sales_ffill'] = df['sales'].fillna(method='ffill')
# 時間插值
df['sales_interp'] = df['sales'].interpolate(method='time')
---
## 3.2 平滑化 (Smoothing)
平滑化旨在去除隨機波動,提取長期趨勢。常用手段包括 **移動平均** (MA) 與 **指數加權移動平均** (EWMA)。
### 3.2.1 移動平均 (MA)
python
# 7 天簡單移動平均
df['sales_ma7'] = df['sales'].rolling(window=7, center=True).mean()
- **窗口大小** 取決於資料頻率與季節週期:日資料可使用 7、30、90 天窗口;週資料可使用 4、12、24 週。
### 3.2.2 指數加權移動平均 (EWMA)
python
# 指數加權平均,半衰期 10 天
df['sales_ewm10'] = df['sales'].ewm(span=10, adjust=False).mean()
> **技巧**:EWMA 對最近數據給予更高權重,適合**趨勢突變**的場景。
---
## 3.3 差分 (Differencing)
差分是常用的平穩化手段,消除非平穩的趨勢與季節性。
### 3.3.1 一階差分
python
# 一階差分
df['sales_diff1'] = df['sales'].diff()
### 3.3.2 季節差分
若資料具有季節性(例如每 12 個月),可使用季節差分:
python
# 季節差分(12 個月)
df['sales_seasdiff'] = df['sales'].diff(periods=12)
> **判斷差分次數**:可透過 ACF/PACF 或單位根檢定(ADF)判斷所需差分階數。
---
## 3.4 對數變換 (Log Transform)
對數變換能緩和**異方差**,使得資料更接近常態,特別適用於收益率、銷售額等正值資料。
python
import numpy as np
# 加 1 防止 log(0)
df['sales_log'] = np.log1p(df['sales'])
> **注意**:若資料包含負值,需先做偏移或採用 Box‑Cox 變換。
---
## 3.5 衍生季節指標 (Seasonal Indicators)
### 3.5.1 日期分解
python
# 直接分解日期欄位
df['year'] = df.index.year
df['month'] = df.index.month
df['dayofweek'] = df.index.dayofweek
### 3.5.2 週期編碼方式
| 編碼 | 優缺點 |
|------|--------|
| One‑Hot | 計算量大,適合少數獨特季節 | 例如 `pd.get_dummies(df['month'], prefix='month')` |
| Target Encoding | 避免稀疏性,保留季節效應 | 需留一份資料做驗證 |
| Ordinal | 適合順序季節變數 | `df['month_ordinal'] = df['month']` |
> **實務建議**:在 **多變數時序預測** 時,先將季節指標加入 **lag** 特徵,再做 **one‑hot** 以避免多重共線性。
---
## 3.5 滾動特徵 (Rolling Features)
滾動特徵提供了**歷史統計**資訊,可直接傳遞給機器學習模型。
### 3.5.1 滾動統計
python
# 滾動 30 天平均、標準差、最小值、最大值
window = 30
for stat in ['mean', 'std', 'min', 'max']:
col = f'sales_roll{window}_{stat}'
df[col] = getattr(df['sales'], 'rolling')(window=window, center=True).__getattribute__(stat)()
### 3.5.2 Lag Features
python
# 3 天滯後
for lag in [1, 3, 7]:
df[f'sales_lag{lag}'] = df['sales'].shift(lag)
> **技巧**:Lag 特徵可使用 **rolling_mean** 與 **rolling_std** 作為附加信息,提升模型對異常事件的辨識能力。
---
## 3.6 事件與節假日特徵
- **節假日**:對於零售、金融市場資料,節假日往往引發顯著銷售波動。可利用 `pandas.tseries.holiday` 或 `holidays` 套件產生節假日掩碼。
- **促銷活動**:將促銷日作為二元指標或數值強度。
- **交互特徵**:如 `sales_lag1 * month_is_dec` 以捕捉「年末促銷 + 高銷售」的共同效應。
---
## 3.7 例子:零售銷售預測資料集
以下流程示意圖(可在實際筆記中繪製)顯示從資料載入到特徵工程的完整流程。
mermaid
flowchart TD
A[載入原始資料] --> B{缺失值?}
B -- Yes --> C[ffill / interpolate]
B -- No --> D[平滑化]
D --> E[差分 / 對數變換]
E --> F[日期分解 + 週期編碼]
F --> G[滾動統計 & Lag Features]
G --> H[事件/節假日特徵]
H --> I[特徵矩陣完成]
> **實作提示**:可將以上步驟封裝為 `sklearn.pipeline.Pipeline` 或自訂 `FeatureEngineer` 類別,確保 **重複性** 與 **可維護性**。
---
## 3.8 小結
1. **缺失值處理**:根據缺口長短與外部資訊選擇合適填補策略。
2. **平滑化**:簡單移動平均和指數加權移動平均能有效降低噪聲。
3. **差分**:必要時執行季節差分,配合單位根檢定判斷差分階數。
4. **對數變換**:減少異方差,提升常態性。
5. **季節指標 & 滾動特徵**:以日期分解、編碼與滾動統計結合,捕捉週期與長期趨勢。
6. **事件特徵**:節假日與促銷活動對銷售有明顯影響,應納入模型。
掌握這些資料預處理與特徵工程技巧,將為後續模型訓練與預測奠定堅實基礎。下一章將著重於 **模型選擇** 與 **模型評估**,以完成整體時序預測工作流。