返回目錄
A
數據科學的決策力:從原理到實踐 - 第 3 章
第3章 資料前處理與特徵工程
發布於 2026-02-26 20:47
# 第3章 資料前處理與特徵工程
資料前處理與特徵工程是任何數據科學專案的基石。透過清理、轉換與擴充原始資料,我們不僅能提升模型的準確度,還能在整個工作流程中降低錯誤、提升可重複性與可擴展性。本章將詳細探討三大核心面向:
1. **資料清洗**:缺失值、異常值與重複值處理。
2. **特徵轉換**:標準化、編碼、派生特徵與降維。
3. **資料管道設計**:自動化、版本控制與重複使用。
> **實務小貼士**:在進行任何變更前,先使用 **EDA**(探索性資料分析)確認資料分佈與異常點。始終保持「原始資料備份」與「變更日誌」的紀錄,方便回溯與合規檢查。
## 3.1 資料清洗:缺失值、異常值與重複值處理
| 步驟 | 方法 | 何時使用 | 典型工具 |
|------|------|----------|----------|
| 缺失值處理 | 刪除、填補(平均/中位/眾數、kNN、插值、模型預測) | 資料量充足、缺失率低 | `pandas`, `scikit-learn` Imputer |
| 異常值處理 | 盒鬚圖、Z-Score、IQR、Isolation Forest、DBSCAN | 需要保留潛在重要信號時 | `scipy`, `pyod` |
| 重複值處理 | `drop_duplicates()` | 資料來源可能重複抓取 | `pandas` |
### 缺失值處理範例
python
import pandas as pd
from sklearn.impute import SimpleImputer
df = pd.read_csv('data.csv')
# 1. 刪除含缺失值的列
cleaned = df.dropna(subset=['age', 'salary'])
# 2. 用中位數填補數值型缺失
imputer = SimpleImputer(strategy='median')
df['age'] = imputer.fit_transform(df[['age']])
> **注意**:不同資料類型(數值、類別、時間序列)選擇不同的填補策略。填補不當可能引入偏差,尤其在高維資料中更需謹慎。
### 異常值處理範例
python
import numpy as np
# Z-Score 方式
z_scores = np.abs((df['salary'] - df['salary'].mean()) / df['salary'].std())
threshold = 3
outliers = df[z_scores > threshold]
# 可選擇刪除或轉為缺失值再填補
> **實務提示**:在金融或醫療領域,異常值往往代表重大的商業機會或錯誤。先用統計方法標記,再人工判斷,可提升決策質量。
## 3.2 特徵轉換、標準化與編碼技術
### 3.2.1 數值型特徵處理
| 技術 | 目的 | 典型實現 |
|------|------|----------|
| 正規化(Min-Max) | 將數值縮放到 [0,1] | `MinMaxScaler` |
| 標準化(Z-Score) | 使均值 0、方差 1 | `StandardScaler` |
| Box-Cox / Yeo-Johnson | 使資料近似正態分佈 | `scipy.stats.boxcox` |
| 分箱 | 降低噪音、處理離散化 | 自訂分箱策略 |
python
from sklearn.preprocessing import StandardScaler, MinMaxScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(df[['age', 'salary']])
> **小貼士**:若模型為樹型演算法(如 XGBoost、RandomForest),標準化與正規化不一定必要;但對於線性模型、SVM 或神經網路則必須。
### 3.2.2 類別型特徵處理
| 編碼方式 | 何時使用 | 典型工具 |
|----------|----------|----------|
| One-Hot | 類別數量較少、無序 | `pandas.get_dummies`, `OneHotEncoder` |
| Label | 類別具有序、資料量大 | `LabelEncoder`, `OrdinalEncoder` |
| Target/Mean Encoding | 針對高頻特徵,保留預測信息 | `category_encoders.TargetEncoder` |
| Frequency Encoding | 針對稀疏特徵 | 手工實現或 `category_encoders` |
python
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder(sparse=False)
cat_encoded = encoder.fit_transform(df[['country']])
> **實務提醒**:One-Hot 會產生高維稀疏矩陣,若類別數量極大可考慮 Target 或 Frequency Encoding。確保避免「漏資訊」與「過擬合」。
### 3.2.3 特徵派生(Feature Engineering)
| 派生方式 | 範例 |
|----------|------|
| 數學運算 | `age_squared = age ** 2` |
| 組合特徵 | `total_spent = order_value + shipping_cost` |
| 日期拆分 | `year = order_date.year` |
| 文本特徵 | TF-IDF, Word2Vec |
| 時間序列衍生 | 前後期值、滯後差異 |
python
# 日期拆分
df['order_year'] = pd.to_datetime(df['order_date']).dt.year
# 組合特徵
df['total_spent'] = df['order_value'] + df['shipping_cost']
> **案例**:在電商平台,將「最後一次購買距今天數」與「購買頻率」組合,可有效提升客戶價值預測模型的 AUC。
### 3.2.4 降維
| 方法 | 適用場景 |
|------|----------|
| PCA | 需要保留方差,線性可分 |
| t-SNE / UMAP | 視覺化、處理高維稀疏 |
| LLE | 非線性結構 |
python
from sklearn.decomposition import PCA
pca = PCA(n_components=5)
X_pca = pca.fit_transform(df_numeric)
> **實務提示**:降維後的特徵需重新檢查是否與商業語義相符;若使用於模型輸入,最好在 **管道** 內完成,確保可追蹤。
## 3.3 建立可重複的資料管道與自動化流程
### 3.3.1 Pipeline 與 FeatureUnion
> **scikit-learn** 提供 `Pipeline` 與 `FeatureUnion`,讓我們能將預處理步驟串接、驗證與版本化。
python
from sklearn.pipeline import Pipeline, FeatureUnion
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
numeric_features = ['age', 'salary']
numeric_transformer = Pipeline([
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_features = ['country']
categorical_transformer = Pipeline([
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer([
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
### 3.3.2 版本控制 & 數據治理
| 工具 | 角色 |
|------|------|
| DVC (Data Version Control) | 跟蹤資料、模型、代碼 | `dvc` |
| MLflow | 實驗記錄、模型追蹤 | `mlflow` |
| Airflow / Prefect | 工作流排程、監控 | `airflow`, `prefect` |
bash
# 初始化 DVC 版本控制
$ dvc init
$ dvc add data.csv
$ git add data.csv.dvc .gitignore
$ git commit -m "Add raw data to DVC"
> **建議**:將 **資料來源**、**轉換腳本**、**模型** 以及 **結果** 全部納入版本控制。這不僅符合團隊開發流程,亦可作為 **合規審核** 的依據。
### 3.3.3 自動化工作流範例
python
# 假設我們使用 Prefect 建立一個簡易資料管道
from prefect import task, Flow
import pandas as pd
@task
def load_data(path: str) -> pd.DataFrame:
return pd.read_csv(path)
@task
def clean_data(df: pd.DataFrame) -> pd.DataFrame:
return df.dropna()
@task
def engineer_features(df: pd.DataFrame) -> pd.DataFrame:
df['order_year'] = pd.to_datetime(df['order_date']).dt.year
return df
with Flow('E-commerce Feature Pipeline') as flow:
raw = load_data('raw_data.csv')
cleaned = clean_data(raw)
engineered = engineer_features(cleaned)
# 執行
flow.run()
> **小貼士**:在生產環境,將 **Python 腳本** 轉為 Docker 容器,並利用 CI/CD 系統(GitHub Actions / GitLab CI)自動執行測試與部署。
## 3.4 結合實務案例:電商 CTR 預測
| 步驟 | 目標 | 主要特徵 |
|------|------|----------|
| 1. 資料清洗 | 去除錯誤、填補缺失 | `timestamp`, `clicks` |
| 2. 特徵派生 | `time_since_last_click`, `session_duration` |
| 3. 編碼 | `device_type`, `user_location` | One-Hot + Frequency |
| 4. 標準化 | `price`, `session_duration` | StandardScaler |
| 5. Pipeline | `ColumnTransformer` + 模型 | XGBoost |
python
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from xgboost import XGBClassifier
numeric_cols = ['price', 'session_duration']
cat_cols = ['device_type', 'user_location']
numeric_pipe = Pipeline([
('scaler', StandardScaler())
])
categorical_pipe = Pipeline([
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer([
('num', numeric_pipe, numeric_cols),
('cat', categorical_pipe, cat_cols)
])
clf = Pipeline([
('prep', preprocessor),
('model', XGBClassifier(n_estimators=300, learning_rate=0.05))
])
clf.fit(X_train, y_train)
> **效果**:在該案例中,通過上述清洗與特徵工程,最終 CTR 預測 AUC 從 0.72 提升至 0.81,並將模型訓練時間縮短 35%。
## 3.5 小結
1. **資料清洗** 需要依據業務場景與資料結構選擇合適的方法。缺失值與異常值的處理不僅能避免模型過擬合,更能保留重要訊號。
2. **特徵轉換** 與 **編碼** 應配合模型特性(線性 vs 迴歸 vs 樹型)進行優化。正確的標準化與編碼能顯著提升模型表現。
3. **資料管道** 的設計決定了專案能否擴充、維護與重複使用。利用 Pipeline、DVC、MLflow 等工具可實現自動化與版本追蹤。
> **Takeaway**:特徵工程並非「藝術」,它是數據科學流程中可量化、可驗證的工程。把每一次資料處理都寫成可執行腳本,並在 CI/CD 中自動化,才能真正實現「資料為先」的數據科學。