聊天視窗

掌握時序預測: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. **事件特徵**:節假日與促銷活動對銷售有明顯影響,應納入模型。 掌握這些資料預處理與特徵工程技巧,將為後續模型訓練與預測奠定堅實基礎。下一章將著重於 **模型選擇** 與 **模型評估**,以完成整體時序預測工作流。