聊天視窗

自由數據:用資料科學解鎖個人財務自由 - 第 3 章

第三章:特徵工程與信號發掘

發布於 2026-02-25 01:06

# 第三章:特徵工程與信號發掘 > **本章目標**:將已清理好的財務資料轉化為可供機器學習模型使用的高質量特徵,並透過特徵洞察生成投資信號,為後續模型建構與組合優化奠定基礎。 --- ## 3.1 引言 特徵工程是資料科學工作流中最具創造性且最耗時的部分。對於投資而言,特徵的選擇、轉換與合成直接影響模型的預測力與交易表現。本章將從三大資料來源說明: 1. **技術指標**(技術分析產生的數值特徵) 2. **基本面因子**(公司財務數據、估值指標) 3. **文本資料**(新聞、社群、財報文字) 並示範如何將它們融合成統一的特徵集,最後以「買進/賣出」信號為例說明信號發掘的流程。 --- ## 3.2 技術指標(Technical Indicators) 技術指標是以價格與成交量為基礎,透過數學函數產生的可量化訊號。常用指標分為兩大類: | 類別 | 代表指標 | 典型用途 | |------|----------|-----------| | 趨勢追蹤 | SMA, EMA, MA | 判斷長短期趨勢 | | 動量衡量 | RSI, MACD, Stochastic | 判斷過度買賣 | | 波動度 | Bollinger Bands, ATR | 估計風險水平 | | 交叉信號 | SMA crossover, MACD cross | 產生交易訊號 | ### 3.2.1 公式與計算 以下列出最常用的三種指標公式,並以 Pandas 及 `ta` 套件為例示範。 | 指標 | 公式 | 參數 | |------|------|------| | SMA | \\text{SMA}_n = \frac{1}{n}\sum_{i=0}^{n-1} P_{t-i} | n (週期) | | EMA | \text{EMA}_n = \alpha P_t + (1-\alpha)\text{EMA}_{n,t-1} | \alpha = 2/(n+1) | | RSI | 100 - \frac{100}{1 + \frac{\text{AvgGain}}{\text{AvgLoss}}} | 14 | #### 範例:計算 20 日 SMA 與 MACD python import pandas as pd import ta # 假設 df 已經包含 'Close' 欄位 # 20 日簡單移動平均 sma20 = ta.trend.sma_indicator(close=df['Close'], window=20) # MACD macd = ta.trend.macd(close=df['Close'], window_slow=26, window_fast=12, window_sign=9) # 加入原始 df result = df.assign(SMA20=sma20, MACD=macd.macd(), MACD_Signal=macd.macd_signal(), MACD_Hist=macd.macd_diff()) ### 3.2.2 特徵選擇與共線性 - **多重共線性**:多個技術指標往往高度相關,例如 SMA20 與 SMA50 的關係。可以使用 **VIF(Variance Inflation Factor)** 進行檢測,若 VIF>5 可考慮移除。 - **特徵重要性**:在訓練模型前,可先用 **RandomForestRegressor** 估算特徵重要度,保留前 N 個特徵。 --- ## 3.3 基本面因子(Fundamental Factors) 基本面因子是從公司財務報表、估值指標中提取的數值。常見的因子包含: | 因子 | 來源 | 代表指標 | |------|------|----------| | 估值 | 財報 | PE, PB, PS, EV/EBITDA | | 成長 | 財報 | 營收成長率, 淨利成長率 | | 獲利 | 財報 | ROE, ROA, 毛利率 | | 負債 | 財報 | 負債比率, 負債/資本 | ### 3.3.1 資料取得 - **API**:`yfinance`, `IEX Cloud`, `Alpha Vantage` 提供基本面資料。 - **資料庫**:如 `SEC Edgar` 提供 10-K、10-Q 財報 PDF 轉 CSV。 python import yfinance as yf ticker = yf.Ticker('AAPL') # 取得財務摘要 summary = ticker.get_financials() # 取得估值指標 info = ticker.info pe_ratio = info['trailingPE'] pb_ratio = info['priceToBook'] ### 3.3.2 數值化與標準化 - **缺失處理**:基本面數據常有缺失,使用 `pandas.DataFrame.interpolate()` 或 `ffill/bfill`。 - **標準化**:為避免量級差異,使用 **z-score** 或 **Min-Max Scaling**。 python from sklearn.preprocessing import StandardScaler scaler = StandardScaler() basic_features_scaled = scaler.fit_transform(basic_df) --- ## 3.4 文本資料處理(Text Data Processing) 文本資料提供了市場情緒與公司新聞的非結構化訊息,對於機器學習模型極具價值。常見來源: | 來源 | 例子 | |------|------| | 財經新聞 | Reuters, Bloomberg | | 研究報告 | Morningstar, 研究所 | | 社群媒體 | Twitter, Reddit r/WallStreetBets | ### 3.4.1 NLP 主要流程 1. **分詞 / Tokenisation**:`spaCy`, `NLTK`。對於中文,可使用 `jieba` 或 `HanLP`。 2. **向量化**: - **詞袋模型**(Bag‑of‑Words)+ `CountVectorizer` 或 `TfidfVectorizer`。 - **詞嵌入**:Word2Vec, GloVe, FastText。 - **Transformer**:BERT、RoBERTa、FinBERT 等。 3. **情緒分析**: - **簡易**:使用正負詞庫(如 `snowNLP`)計算情緒分數。 - **先進**:`transformers` `pipeline('sentiment-analysis')`。 4. **主題建模**:LDA、NMF。 #### 範例:英文財經新聞情緒分數(FinBERT) python from transformers import pipeline sentiment_pipeline = pipeline('sentiment-analysis', model='yiyang/finbert-base', device=0) # 假設 news_texts 是新聞標題列表 scores = [sentiment_pipeline(t)[0]['score'] for t in news_texts] # 加入特徵集 feature_df['news_sentiment'] = scores #### 中文情緒分析範例(SnowNLP) python from snownlp import SnowNLP def compute_sentiment(text): s = SnowNLP(text) return s.sentiments # 0-1 之間 sentiments = news_df['content'].apply(compute_sentiment) news_df['sentiment'] = sentiments ### 3.4.2 特色提取 - **情緒指標**:每日平均情緒分數、正負比率。 - **事件指標**:關鍵詞頻次、關鍵事件(如併購、股東變動)標記。 - **主題分佈**:使用 `NMF` 產生主題權重,可作為額外特徵。 --- ## 3.5 統一特徵構建流程 > **目標**:將價格、財務、文本三種特徵按時間戳對齊,形成完整、乾淨且可直接送入模型的特徵矩陣。 ### 3.5.1 步驟 1. **資料合併**: python merged = price_df.join(basic_features, how='inner', on='Date') merged = merged.join(text_features, how='left', on='Date') 2. **缺失處理**:填補 `NaN`,必要時刪除首尾缺失行。 3. **時間窗特徵**:利用 `rolling()` 計算移動平均、標準差等。 4. **編碼**: - **類別型**:One‑Hot (`pd.get_dummies`) 或 Target Encoding。 - **序列型**:如果使用 RNN 或 LSTM,可將特徵轉成三維張量。 5. **標準化**:全局 `StandardScaler` 或 `RobustScaler`。 6. **特徵儲存**: python import joblib joblib.dump(preprocessor, 'models/preprocessor.joblib') ### 3.5.2 版本化與重現性 - **配置檔**:`config.yaml` 內定義所有窗口、因子、資料來源。 - **版本控制**:使用 `git lfs` 儲存大文件;`DVC` 可管理資料版本。 --- ## 3.6 信號發掘(Signal Generation) 交易信號是模型或手動規則所產出的「買進/賣出/觀望」判斷。以技術指標為例,常見的買賣訊號規則如下: | 規則 | 條件 | |------|------| | SMA Crossover | \\text{SMA}_{short} > \text{SMA}_{long} → 買進 | | MACD Cross | MACD > Signal → 買進;MACD < Signal → 賣出 | | RSI Overbought | RSI > 70 → 賣出 | | RSI Oversold | RSI < 30 → 買進 | ### 3.6.1 範例:生成交易訊號 python # 以 SMA20 與 SMA50 交叉為例 condition_buy = (sma20 > sma50) & (df['Date'].shift(1) <= df['Date'].shift(1)) condition_sell = (sma20 < sma50) & (df['Date'].shift(1) <= df['Date'].shift(1)) signals = pd.Series(index=df.index, data=0) signals[condition_buy] = 1 signals[condition_sell] = -1 df = df.assign(signal=signals) ### 3.6.2 風險調整的評估 - **夏普率**:\(\frac{E[R_p] - R_f}{\sigma_{p}}\) - **Information Ratio**:\(\frac{E[R_p] - R_b}{\sigma_{p-b}}\) - 在回測時,對每條信號計算其風險調整後的報酬,以篩選「有價值」的訊號。 --- ## 3.7 進階特徵技術 | 技術 | 目的 | 典型實作 | |------|------|----------| | FFT | 週期特徵 | `np.fft.fft` 取得頻域分量 | | Rolling Stats | 時間窗特徵 | `df.rolling(window).agg(['mean', 'std'])` | | Lag Features | 轉換序列型資料 | `df.shift(k)` | | 混合特徵 | 融合多來源 | `pd.concat([tech_df, basic_df, text_df], axis=1)` | > **提醒**:使用 FFT 時需先進行 **去趨勢**(如差分)才能得到穩定的頻域特徵;滾動特徵要確保 **未泄露** 任何未來資訊。 --- ## 3.8 實務技巧 1. **特徵重要性評估** - **Permutation Importance**:隨機打亂單一特徵,觀察模型準確率變化。 - **SHAP**:提供每筆樣本的特徵貢獻度。 python import shap explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X_train) shap.summary_plot(shap_values, X_train) 2. **避免資料泄露** - 所有 **訓練/驗證/測試** 切分前均應在「完整」資料上進行合併與缺失填補。 - 在計算滾動特徵時,只允許 **past‑only** 的窗口。 3. **可重複性** - 將特徵工程程式封裝成函式,並在 `requirements.txt` 與 `pyproject.toml` 明確列出依賴。 - 使用 `dvc run` 建立流水線,確保每次重新執行時能得到相同的特徵矩陣。 --- ## 3.9 結語 特徵工程不是「一次性」的工作,而是投資策略開發過程中持續迭代、優化的核心。透過技術指標、基本面因子與文本特徵的深度結合,可讓模型擁有多維度的市場觀察,進而產生更可靠的交易信號。本章所示範的範例與工具,將在接下來的「模型建構」與「策略回測」章節中得到直接應用。 --- > **下一章**:在「特徵化資料」之後,我們將聚焦於**機器學習模型**(回歸、分類、強化學習)的訓練、超參數調優與模型選擇,並以「夏普率」為基準評估不同模型在投資組合中的貢獻。