聊天視窗

從數據到利潤:量化投資策略設計與實踐 - 第 3 章

3. 特徵工程:從原始數據到投資信號

發布於 2026-03-07 08:43

# 3. 特徵工程:從原始數據到投資信號 在量化投資的旅程中,資料是起點,但真正能產生交易信號的,往往是**特徵**——即從原始行情、新聞、財報等資訊中抽取出的可量化、可比較的指標。特徵工程不僅是技術手段,更是一門藝術:它要求我們在保留市場真實度的同時,將噪音剔除,讓機器學習模型更易捕捉潛在模式。 本章將依序闡述: 1. 為何特徵工程是關鍵; 2. 常見的技術指標與統計特徵; 3. 文字情感與宏觀指標的融合; 4. 合成特徵與維度約簡; 5. 實務工具與流程最佳化。 --- ## 3.1 為何特徵工程是關鍵 | 步驟 | 目的 | 常見風險 | |------|------|----------| | 資料輸入 | 原始行情、新聞、財報 | 噪音過多、缺失值 | | 特徵提取 | 抽取可量化訊息 | 過度擬合、資訊遺失 | | 正規化 | 確保尺度一致 | 標準化不當導致信號扭曲 | | 選擇/減維 | 提升模型效率 | 重要資訊被刪除 | > **風險提示**:過度依賴歷史特徵可能使模型過度擬合;保持「新手特徵」的探索空間,避免一次性把所有可能的特徵納入。 ## 3.2 技術指標 技術指標是最常見的特徵來源。以下示例使用 `pandas` 與 `ta-lib`(或 `ta`)計算簡單移動平均、布林帶、RSI。 python import pandas as pd import ta df = pd.read_csv('ticker_data.csv', parse_dates=['date'], index_col='date') # 簡單移動平均 for window in [10, 20, 50]: df[f'SMA_{window}'] = df['close'].rolling(window).mean() # 布林帶 bb = ta.volatility.BollingerBands(close=df['close'], window=20, window_dev=2) for col in ['bollinger_hband_indicator', 'bollinger_lband_indicator', 'bollinger_hband_indicator']: df[col] = bb.get(col) # RSI df['RSI_14'] = ta.momentum.RSIIndicator(df['close'], window=14).rsi() df.to_csv('features_technical.csv') > **技巧**:不同市場(ETF、期貨、外匯)對移動平均週期的敏感度不同,建議在特徵生成時多嘗試不同窗口,並在後續特徵選擇中做篩選。 ## 3.3 統計特徵 統計特徵如波動率、收益率分布指標、協方差等能揭示市場結構。 python # 近30天收益率 returns = df['close'].pct_change() for period in [5, 10, 20, 30]: df[f'return_{period}'] = returns.rolling(period).mean() df[f'vol_{period}'] = returns.rolling(period).std() df[f'skew_{period}'] = returns.rolling(period).skew() df[f'kurt_{period}'] = returns.rolling(period).kurt() > **小結**:統計特徵往往不需要太長的歷史窗口;過長會造成滯後性;過短則對噪音敏感。 ## 3.4 文字情感與宏觀指標 ### 3.4.1 文字情感 利用 NLP 先把新聞或財報摘要轉成向量,再提取情感分數。以下示例使用 `transformers` 的 `pipeline` 進行情感分析。 python from transformers import pipeline sentiment_analyzer = pipeline('sentiment-analysis') # 假設 df_news 有 'text' 欄 sentiments = df_news['text'].apply(lambda x: sentiment_analyzer(x)[0]) df_news['sentiment'] = sentiments.apply(lambda d: d['label']) df_news['score'] = sentiments.apply(lambda d: d['score']) # 聚合至每日級別 daily_sentiment = df_news.groupby(df_news.index)['score'].mean() ### 3.4.2 宏觀指標 將宏觀經濟數據(GDP、失業率、利率)作為外部特徵。 python # 讀取經濟數據 macro = pd.read_csv('macro.csv', parse_dates=['date'], index_col='date') # 重新索引以配合交易日 macro = macro.reindex(df.index, method='ffill') # 合併 df = df.join(macro) > **風險提示**:文字情感往往帶有偏差,需在模型訓練時加以正則化;宏觀指標更新頻率低,可能導致過時。 ## 3.5 合成特徵與維度約簡 在擁有大量原始特徵後,我們可透過以下方式縮減維度: 1. **相關係數過濾**:刪除高度相關的特徵。 2. **主成分分析(PCA)**:保留解釋力較高的主成分。 3. **Lasso 或 ElasticNet**:同時做特徵選擇與正則化。 python from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler features = df.drop(columns=['target']) scaler = StandardScaler() scaled = scaler.fit_transform(features) pca = PCA(n_components=0.95) # 保留 95% 變異 principal = pca.fit_transform(scaled) print(f'保留 {pca.n_components_} 個主成分,解釋力 {pca.explained_variance_ratio_.sum():.2%}') > **注意**:PCA 會產生線性組合,解釋性較弱,建議在模型解釋力要求較高時,使用特徵選擇而非維度約簡。 ## 3.6 工具與最佳實踐 | 工具 | 角色 | 優點 | |------|------|------| | `pandas` | 資料處理 | 易用、廣泛支持 | | `ta` | 技術指標 | 內置多種指標,維護活躍 | | `scikit-learn` | 轉換、模型 | 統一 API,擴展性好 | | `mlflow` | 實驗追蹤 | 版本化、可視化 | | `DVC` | 資料版本控制 | 對大文件友好 | > **最佳實踐**: > 1. **特徵生成**應與資料獲取分離,保證可重複性。 > 2. **特徵日誌**:每個特徵生成腳本都應有版本、時間戳與參數記錄。 > 3. **資料正則化**:盡量使用 `StandardScaler` 或 `MinMaxScaler`,避免數值過大或過小。 > 4. **避免「看得見就做」**:不要把所有計算都放到模型訓練腳本,特徵工程應在獨立流程完成。 ## 3.7 小結 特徵工程是將市場訊號轉化為機器可讀格式的關鍵環節。從技術指標、統計特徵到 NLP 與宏觀經濟,層層堆疊、精煉,最終形成能驅動模型的「特徵集」。在實務中,需兼顧 **可解釋性**、**可重複性**與**效率**。下一章,我們將把這些特徵帶入機器學習模型,並進行回測與風險控制的設計。 > **練習題**: > 1. 針對某 ETF,設計包含 5 個技術指標、2 個統計特徵、1 個文字情感特徵的特徵集。 > 2. 在 MLflow 中紀錄每一次特徵生成的參數、時間與輸出檔案大小。 > 3. 用 PCA 檢測特徵集中的冗餘度,報告保留主成分與解釋力。