返回目錄
A
資料驅動決策:從數據探索到模型部署 - 第 3 章
第3章:特徵工程——把洞察轉化為可用資訊
發布於 2026-02-27 15:43
# 第3章:特徵工程——把洞察轉化為可用資訊
在前一章中,我們透過視覺化洞察了資料的結構與潛在問題。接下來的核心工作,就是將這些洞察轉換為模型能夠直接利用的特徵。特徵工程不僅能提升模型表現,更能縮短實作迴圈,讓數據科學團隊快速交付價值。
---
## 3.1 何謂特徵工程
> **特徵工程**:從原始資料中選擇、轉換、創造出能夠提升模型預測力的「特徵」的整個流程。
| 步驟 | 目的 | 典型手法 |
|---|---|---|
| 清洗 | 去除噪音、修正錯誤 | 缺失值補全、離群值處理 |
| 選擇 | 保留重要訊息 | 相關係數、互信息 |
| 轉換 | 讓特徵更易於模型處理 | 標準化、對數變換 |
| 創造 | 擴充資訊 | 交互項、聚合特徵 |
| 減維 | 降低維度、減少複雜度 | PCA、LDA、t‑SNE |
> **思考提示**:每一步都可能對模型產生千差萬別的影響。小小的轉換有時能突破「模型瓶頸」。
---
## 3.2 數值特徵處理
### 3.2.1 缺失值補全
```python
import numpy as np
# 取均值補全
X['age'].fillna(X['age'].mean(), inplace=True)
# 取中位數補全
X['income'].fillna(X['income'].median(), inplace=True)
```
### 3.2.2 離群值處理
> **Z‑Score 法**:若 |z| > 3 可視為離群。
```python
from scipy import stats
z_scores = np.abs(stats.zscore(X['score']))
X = X[z_scores < 3]
```
> **箱形圖法**:IQR+1.5 乘子。
```python
Q1 = X['score'].quantile(0.25)
Q3 = X['score'].quantile(0.75)
IQR = Q3 - Q1
mask = (X['score'] >= Q1 - 1.5*IQR) & (X['score'] <= Q3 + 1.5*IQR)
X = X[mask]
```
### 3.2.3 變換與尺度化
| 變換 | 何時適用 | 範例 |
|---|---|---|
| Log | 正偏分佈 | `np.log1p()` |
| Box‑Cox | 需要正值 | `scipy.stats.boxcox()` |
| StandardScaler | 需要零均值、單位方差 | `sklearn.preprocessing.StandardScaler()` |
| MinMaxScaler | 需要限定範圍 | `sklearn.preprocessing.MinMaxScaler()` |
> **小技巧**:對於 `NaN` 在標準化前先補完,避免 `fit_transform` 時拋錯。
---
## 3.3 類別特徵處理
### 3.3.1 One‑Hot Encoding
```python
X = pd.get_dummies(X, columns=['gender', 'city'], drop_first=True)
```
### 3.3.2 Ordinal Encoding
> 適用於有序類別(如教育程度)
```python
from sklearn.preprocessing import OrdinalEncoder
enc = OrdinalEncoder(categories=[['中學', '大學', '碩士', '博士']])
X['edu_level'] = enc.fit_transform(X[['edu_level']])
```
### 3.3.3 Target Encoding
> 直接將目標變數的平均值映射到類別。
```python
mean_target = y.groupby(X['brand']).mean()
X['brand_te'] = X['brand'].map(mean_target)
```
> **風險提示**:若樣本量小,請使用「加權平均」或「貝式平滑」以防過度擬合。
---
## 3.4 時間序列特徵
| 特徵 | 產生方式 | 典型用途 |
|---|---|---|
| 時間窗指標 | 滑動窗口 | 30 天平均值 |
| 時間戳分解 | 年、月、日、週、時 | 週期性預測 |
| 滑動差分 | 連續差值 | 稳定化、季節去除 |
```python
# 30 天移動平均
X['price_ma30'] = X['price'].rolling(window=30).mean()
```
---
## 3.5 交互特徵與聚合
### 3.5.1 交互項
```python
X['price_per_unit'] = X['price'] / X['quantity']
```
### 3.5.2 聚合特徵
> 針對分組資料計算聚合統計。
```python
agg = X.groupby('customer_id').agg({'amount': ['sum', 'mean', 'max']})
agg.columns = ['amount_sum', 'amount_mean', 'amount_max']
X = X.merge(agg, left_on='customer_id', right_index=True, how='left')
```
---
## 3.6 維度縮減
| 方法 | 優點 | 缺點 |
|---|---|---|
| PCA | 直觀、計算快 | 只保留線性關係 |
| t‑SNE | 非線性映射 | 計算昂貴、參數敏感 |
| UMAP | 與 t‑SNE 相近但速度快 | 需要調參 |
> **實務建議**:若模型對維度不敏感(如隨機森林),可直接省略;若需可視化或計算效率,請採用 PCA。
---
## 3.7 進階技巧
1. **自動特徵工程**:使用 `featuretools` 或 `tsfresh` 自動生成時間序列特徵。
2. **正則化與懲罰**:在特徵選擇前加入 L1/L2 懲罰,減少冗餘。
3. **Feature Hashing**:對大類別資料(如產品名稱)快速哈希映射,避免 One‑Hot 產生維度爆炸。
---
## 3.8 小結
- **特徵工程**是把業務洞察轉化為模型語言的橋梁。
- 嚴謹的數值與類別處理能夠大幅提升模型穩定度。
- 時間序列特徵、交互項與聚合能夠捕捉業務深層關聯。
- 維度縮減與進階工具能有效管理高維度與複雜度。
> **實務提醒**:每一步特徵工程都應與模型評估相互驗證,避免「過度工程」帶來的維度災難。
---
## 3.9 挑戰題
> **挑戰**:選擇一個商業案例(例如線上零售、金融風控或健康監測),從資料集出發,設計至少三個可提升模型表現的特徵,並說明你選擇的原因與預期效果。
---
## 3.10 實戰示例:電商訂單預測
```python
# 1. 載入資料
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestRegressor
# 假設 df 包含 order_date, customer_id, product_id, quantity, price, status
# 2. 特徵工程
def engineer(df):
df = df.copy()
df['order_day'] = pd.to_datetime(df['order_date']).dt.dayofweek
df['total_amount'] = df['quantity'] * df['price']
# 聚合特徵
agg = df.groupby('customer_id')['total_amount'].agg(['sum','mean']).reset_index()
agg.columns = ['customer_id','cust_total_sum','cust_total_mean']
df = df.merge(agg, on='customer_id', how='left')
return df
X = engineer(df)
y = X['status'] # 假設二元分類
X = X.drop(['order_date','status'], axis=1)
numeric_features = ['quantity','price','total_amount','cust_total_sum','cust_total_mean']
categorical_features = ['product_id','customer_id','order_day']
numeric_transformer = Pipeline(steps=[('scaler', StandardScaler())])
categorical_transformer = Pipeline(steps=[('onehot', OneHotEncoder(handle_unknown='ignore'))])
preprocess = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
model = Pipeline(steps=[
('preprocess', preprocess),
('rf', RandomForestRegressor(n_estimators=200, random_state=42))
])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model.fit(X_train, y_train)
print('驗證集 R^2:', model.score(X_test, y_test))
```
> **解說**:上述流程示範了時間拆解、聚合、交互、尺度化與編碼的完整 pipeline,並即時可直接投入模型訓練。
---
## 3.11 總結
特徵工程是資料科學流程中最具「創造力」與「風險」的環節。透過結合統計洞察、業務領域知識與先進工具,你能把雜亂的數據轉化為模型語言,讓機器學習模型真正擁抱業務價值。接下來,我們將把這些特徵帶入模型構建,並評估其對預測效果的具體貢獻。