聊天視窗

數據驅動的投資策略:從數據清洗到模型部署 - 第 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%,可直接投入特徵工程與模型訓練。 ## 結語 數據清洗不是一次性的操作,而是整個投資流程的基石。透過系統化的流程與自動化工具,我們可以持續保障資料品質,為後續模型提供可靠的基礎。下一章將深入「特徵工程」,學習如何從乾淨的資料中抽取投資信號。