聊天視窗

數據驅動的投資策略:從數據清洗到模型部署 - 第 3 章

第3章 特徵工程:從乾淨資料抽取投資信號

發布於 2026-03-05 05:11

# 第3章 特徵工程:從乾淨資料抽取投資信號 > **目標**:將前章完成的「清洗後」S&P 500 日行情轉換為機器學習模型可直接使用的數值特徵。 > > **為什麼特徵工程重要?** > > 在投資領域,模型的表現往往不只是演算法本身,而是資料提供的資訊量與質量。透過合適的特徵工程,我們能把金融市場的非線性、時序性、異質性轉化為模型易於學習的模式,並有效降低維度、提升可解釋性。 ## 3.1 特徵工程流程總覽 | 步驟 | 內容 | 工具 | 典型範例 | |------|------|------|-----------| | 1. 載入乾淨資料 | 讀取 `clean_sp500.csv` | `pandas` | `pd.read_csv()` | | 2. 基本統計特徵 | 收盤價、成交量等 | `pandas` | `Close`, `Volume` | | 3. 時序衍生特徵 | 滾動統計、滾動回報 | `pandas` | `rolling.mean()` | | 4. 技術指標 | 移動平均、RSI、MACD | `ta` | `ta.trend.SMAIndicator()` | | 5. 欠采樣 / 調整尺度 | 標準化、對數變換 | `scikit-learn` | `StandardScaler()` | | 6. 特徵選擇 | 主成分、重要性排序 | `sklearn` | `SelectKBest()` | | 7. 檢查多重共線性 | VIF | `statsmodels` | `variance_inflation_factor()` | > **提示**:在實際部署前,將「特徵工程」寫成可重複的函式或 pipeline,確保日後數據更新時可以自動執行。 ## 3.2 基本統計特徵 python import pandas as pd import numpy as np ds = pd.read_csv('clean_sp500.csv', parse_dates=['Date']) ds.set_index('Date', inplace=True) # 基本收盤價、成交量 features = ds[['Close', 'Volume']].copy() # 日回報 features['Return'] = features['Close'].pct_change().fillna(0) # 滑動對數回報(可減少極端值影響) features['LogReturn'] = np.log(features['Close'] / features['Close'].shift(1)).fillna(0) > **說明**:日回報是最簡單且廣泛使用的特徵,然而在高頻或高波動市場,日回報可能過於噪聲,這時可以考慮使用更長期的滾動回報或其他衍生指標。 ## 3.3 滾動統計與衍生特徵 | 參數 | 說明 | 實作 | |------|------|------| | 20日移動平均 | 趨勢判斷 | `SMA_20` | | 50日波動率 | 市場風險 | `Vol_50` | | 14日RSI | 超買超賣 | `RSI_14` | | 12日EMA - 26日EMA | MACD | `MACD` | python import ta # 移動平均 features['SMA_20'] = ta.trend.sma_indicator(features['Close'], window=20) features['EMA_20'] = ta.trend.ema_indicator(features['Close'], window=20) # 波動率(20日標準差) features['Vol_20'] = features['Return'].rolling(window=20).std() * np.sqrt(252) # RSI features['RSI_14'] = ta.momentum.rsi(features['Close'], window=14) # MACD macd = ta.trend.MACD(features['Close'], window_slow=26, window_fast=12, window_sign=9) features['MACD'] = macd.macd() features['MACD_signal'] = macd.macd_signal() features['MACD_diff'] = macd.macd_diff() > **備註**:`ta`(Technical Analysis Library in Python)提供了大量經典技術指標,使用時要留意參數的市場適應性。若市場結構變化,建議重新評估參數。 ## 3.4 高階衍生特徵 ### 3.4.1 交易量與價量關係 - **成交量動量**:量值與前期量值之差。 - **OBV(On-Balance Volume)**:累計成交量,反映買賣力量。 python # 交易量動量 features['Volume_Momentum'] = features['Volume'].diff().fillna(0) # OBV obv = ta.volume.on_balance_volume(features['Close'], features['Volume']) features['OBV'] = obv ### 3.4.2 複合指標 - **Bollinger Bands**:上下帶判斷波動極端。 - **ADX(Average Directional Index)**:趨勢強度。 python bb = ta.volatility.BollingerBands(features['Close'], window=20, window_dev=2) features['BB_High'] = bb.bollinger_hband() features['BB_Low'] = bb.bollinger_lband() features['BB_Middle'] = bb.bollinger_mavg() adx = ta.trend.ADXIndicator(features['High'], features['Low'], features['Close'], window=14) features['ADX'] = adx.adx() > **小結**:這些複合指標往往需要多個子指標的協同判斷,避免單一指標的誤判。使用時可視覺化或交叉驗證以確保穩定性。 ## 3.5 特徵尺度與轉換 | 轉換 | 目的 | 方式 | |------|------|------| | 標準化 | 消除不同量級影響 | `StandardScaler()` | | 對數變換 | 轉化長尾分佈 | `np.log1p()` | | 分位數轉換 | 對極端值穩健 | `QuantileTransformer()` | python from sklearn.preprocessing import StandardScaler, QuantileTransformer numeric_cols = features.select_dtypes(include=[np.number]).columns scaler = StandardScaler() features_scaled = scaler.fit_transform(features[numeric_cols]) # 轉換後回到 DataFrame features_scaled_df = pd.DataFrame(features_scaled, index=features.index, columns=numeric_cols) > **實務建議**:對於回測期間的數據,不要在訓練集之外擷取統計量,以免資訊洩漏。可使用 `TimeSeriesSplit` 進行交叉驗證。 ## 3.6 特徵選擇與降維 ### 3.6.1 基於相關係數的篩選 python corr_matrix = features_scaled_df.corr().abs() upper = corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)) to_drop = [column for column in upper.columns if any(upper[column] > 0.9)] features_reduced = features_scaled_df.drop(columns=to_drop) ### 3.6.2 主成分分析(PCA) python from sklearn.decomposition import PCA pca = PCA(n_components=0.95) # 保留 95% 變異 principal_components = pca.fit_transform(features_reduced) print(f'保留 {pca.n_components_} 個主成分') > **注意**:PCA 會降低可解釋性,若模型需要解釋投資因子,建議保持原始特徵並用特徵重要性來篩選。 ## 3.7 特徵重要性評估 以 `XGBoost` 為例,快速判斷哪些特徵對預測最有價值。 python import xgboost as xgb X = features_reduced y = (features['Return'].shift(-1) > 0).astype(int) # 明日漲跌作為目標 model = xgb.XGBClassifier(n_estimators=200, learning_rate=0.05, max_depth=5, subsample=0.8, colsample_bytree=0.8) model.fit(X[:-1], y[:-1]) # 迴避最後一筆無目標 importances = model.feature_importances_ feat_importances = pd.Series(importances, index=X.columns).sort_values(ascending=False) print(feat_importances.head(10)) > **解讀**:高重要度特徵往往包含關鍵訊息,如 `SMA_20`、`RSI_14`、`Vol_20` 等;若某些技術指標重要度極低,可考慮移除,以減少模型複雜度。 ## 3.8 特徵工程的最佳實踐 | 原則 | 說明 | |------|------| | **避免資訊洩漏** | 在預測之前,所有統計量(均值、標準差)都應基於訓練集計算。 | | **自動化 pipeline** | 使用 `sklearn.pipeline` 或 `mlflow` 追蹤特徵版本。 | | **可解釋性** | 儘量保留物理意義的特徵,避免「黑盒」特徵化。 | | **持續監控** | 特徵分佈隨時間變化,需定期檢查概況圖。 | | **多模型驗證** | 在多個演算法上評估特徵重要性,避免模型偏差。 ## 3.9 小結 特徵工程是把市場信號轉化為機器可讀的關鍵步驟。透過「基本統計」→「技術指標」→「衍生特徵」→「尺度轉換」→「特徵選擇」的層層遞進,我們可以構建出既有解釋性又有預測力的特徵集。接下來的第4章,我們將以這些特徵為基礎,進入「模型訓練與驗證」的核心環節,探討如何選擇演算法、處理時序交叉驗證,以及避免過擬合。