返回目錄
A
從數據到利潤:量化投資策略設計與實踐 - 第 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 檢測特徵集中的冗餘度,報告保留主成分與解釋力。