返回目錄
A
數據驅動的投資策略:從數據清洗到模型部署 - 第 2 章
第二章:數據清洗與品質評估
發布於 2026-03-05 04:59
# 第二章:數據清洗與品質評估
> **本章目標**:建立起可靠、可重複的資料清洗流程,確保後續特徵工程與模型訓練的基礎品質。
## 2.1 數據質量概念
| 指標 | 定義 | 為什麼重要 |
|------|------|------------|
| 完整度(Completeness) | 資料中缺失值的比例 | 缺失值過多會直接削弱模型的預測力 |
| 一致性(Consistency) | 同一個實體在不同來源或欄位中是否相符 | 一致性差會產生不合邏輯的交易訊號 |
| 正確性(Accuracy) | 資料與實際世界的相符程度 | 低正確性會造成策略失效 |
| 時效性(Timeliness) | 資料是否即時更新 | 延遲資料會影響實時交易 |
| 可用性(Usability) | 資料是否能直接被使用 | 高可用性降低處理成本 |
> **關鍵原則**:先觀察 → 後處理。先用視覺化快速發現問題,再針對問題採取對應策略。
## 2.2 缺失值處理
### 2.2.1 觀察缺失模式
使用 `missingno` 這個簡易工具能一次性呈現缺失佈局:
python
import missingno as msno
import pandas as pd
df = pd.read_csv('data.csv')
msno.matrix(df)
msno.heatmap(df)
- **完全缺失**:某欄全為 `NaN`,直接刪除或保留視業務需求。
- **隨機缺失(MAR/MNAR)**:可考慮插補。
### 2.2.2 刪除 vs 插補
| 方法 | 適用場景 | 風險 |
|------|----------|------|
| 直接刪除 | 缺失率 < 5% 且資料量大 | 可能減少資料量 |
| 前向/後向填充(ffill/bfill) | 時間序列、缺失不多 | 可能引入自相關 |
| 線性/多項式插補 | 連續型數據 | 需要確保趨勢合理 |
| KNN 插補 | 具有多個特徵,缺失分佈均勻 | 計算成本高 |
| 多重插補(MICE) | 高缺失率,需保持不確定性 | 複雜度高 |
### 2.2.3 範例:金融日行情的缺失處理
python
import pandas as pd
# 讀取資料
price = pd.read_csv('sp500_daily.csv', parse_dates=['Date'], index_col='Date')
# 觀察缺失率
print(price.isna().mean())
# 前向填充價格,後向填充成交量(因為缺失多)
price['Close'] = price['Close'].ffill()
price['Volume'] = price['Volume'].bfill()
# 若缺失率過高(>10%)直接刪除列
price = price[price.isna().sum(axis=1) < 1]
> **提示**:對於 `Close` 價格,前向填充最常用;對於成交量,可考慮後向填充或 `median` 代替。
## 2.3 重複值處理
### 2.3.1 什麼是重複
- **完全重複**:所有欄位皆相同。
- **部分重複**:關鍵欄位(如日期、代碼)相同,其他欄位不同。
### 2.3.2 去重方法
python
# 完全去重
price = price.drop_duplicates()
# 只以日期+代碼為主鍵去重,保留最新資料
price = price.sort_values('Timestamp').drop_duplicates(subset=['Date', 'Ticker'], keep='last')
> **小心**:某些資料提供商會在同一天多次更新,若不排除,可能造成「時間漂移」問題。
## 2.4 時間同步與篩選
### 2.4.1 交易日 vs 假日
| 時間頻率 | 來源 | 篩選方法 |
|----------|------|----------|
| 日度 | 股票 | `pd.bdate_range` 或 `pd.date_range` + `pd.tseries.offsets.BDay()` |
| 週度 | ETF | `freq='W-MON'` |
| 月度 | 指數 | `freq='M'` |
python
import pandas as pd
# 產生美股交易日曆
trading_days = pd.bdate_range(start='2020-01-01', end='2023-12-31', freq='B')
### 2.4.2 合併多源時間序列
python
# 假設有兩個資料表:行情與基本面
price = pd.read_csv('price.csv', parse_dates=['Date'], index_col='Date')
fund = pd.read_csv('fundamentals.csv', parse_dates=['Date'], index_col='Date')
# 內連接,保留共同交易日
merged = price.join(fund, how='inner')
### 2.4.3 篩選交易日
python
# 移除非交易日的行
merged = merged[merged.index.isin(trading_days)]
## 2.5 異常值偵測與處理
| 方法 | 數學基礎 | 優缺點 |
|------|----------|--------|
| IQR | 四分位數 | 直觀、適用非正態分布 |
| 標準差 | 均值與標準差 | 需正態分布,易誤判 |
| z-score | 樣本均值、標準差 | 同上 |
| Isolation Forest | 監督式異常偵測 | 能捕捉非線性異常,計算成本高 |
python
import numpy as np
# IQR 篩選
Q1 = price['Close'].quantile(0.25)
Q3 = price['Close'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
price = price[(price['Close'] >= lower) & (price['Close'] <= upper)]
> **注意**:金融數據常見「極端波動」是市場事件,是否視為異常需結合業務判斷。
## 2.6 資料品質評估
| 指標 | 計算方式 | 目標值 |
|------|----------|--------|
| 缺失率 | `df.isna().mean()` | < 5% |
| 重複率 | `df.duplicated().mean()` | 0% |
| 異常比例 | `df[condition].shape[0] / df.shape[0]` | < 1% |
| 時間同步誤差 | `abs(df.index.to_series() - df.index.to_series().shift(1))` | 0 |
> **報告範例**:
>
>
> {
> "MissingRate": 0.02,
> "DuplicateRate": 0.0,
> "OutlierRate": 0.005,
> "TimeSyncError": 0.0
> }
>
>
> 透過 `pandas_profiling` 或 `sweetviz` 可自動生成交互式報告。
## 2.7 自動化流程
### 2.7.1 Pipeline 定義
python
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
pipeline = Pipeline([
('imputer', SimpleImputer(strategy='ffill')),
('scaler', StandardScaler()),
])
### 2.7.2 工作流工具
| 工具 | 特性 |
|------|------|
| Airflow | DAG、排程、監控 |
| Prefect | 直觀 API、分佈式執行 |
| Luigi | 任務依賴、狀態管理 |
> **實務建議**:將資料清洗、特徵工程、模型訓練分為獨立 DAG,並利用 `XCom` 傳遞中間資料。
### 2.7.3 版本控制與日誌
- 資料原始檔案:使用 Git LFS 或 DVC 存放。
- 清洗程式碼:以 Git 追蹤,提交訊息須包含 `cleaning`, `fix`, `refactor` 等關鍵字。
- 日誌:使用 `logging` 模組,並將日誌寫入 `elasticsearch` 方便搜尋。
## 2.8 實務案例:S&P 500 日行情清洗
| 步驟 | 操作 | 觀察結果 |
|------|------|----------|
| 1. 讀取資料 | `pd.read_csv('sp500.csv')` | 缺失率 3% |
| 2. 移除重複 | `drop_duplicates()` | 無重複 |
| 3. 前向填充 | `Close.ffill()` | 失真率 < 0.1% |
| 4. 異常值過濾 | IQR | 0.8% 异常被剔除 |
| 5. 同步交易日 | `pd.bdate_range` | 時間戳均對應交易日 |
| 6. 資料品質報告 | `pandas_profiling` | 兼容性 99% |
> **結論**:經過上述清洗後,資料完整度提升至 99%,可直接投入特徵工程與模型訓練。
## 結語
數據清洗不是一次性的操作,而是整個投資流程的基石。透過系統化的流程與自動化工具,我們可以持續保障資料品質,為後續模型提供可靠的基礎。下一章將深入「特徵工程」,學習如何從乾淨的資料中抽取投資信號。