返回目錄
A
數據科學的藝術與科學:從基礎到實踐 - 第 4 章
第4章 特徵工程與資料前處理
發布於 2026-02-25 14:47
# 第4章 特徵工程與資料前處理
> **特徵工程** 是把原始資料轉換為機器學習模型能夠直接使用的「特徵」的過程。透過合理的前處理與特徵選擇,可大幅提升模型表現、減少過擬合、降低計算成本。
---
## 4.1 資料前處理概念
| 項目 | 定義 | 為何重要 |
|------|------|------------|
| **缺失值處理** | 填補或刪除資料中缺失的項目 | 防止模型輸入為 NaN 導致錯誤或偏差 |
| **標準化 / 正規化** | 調整特徵分佈使其具有相似尺度 | 促進梯度下降收斂,減少某些演算法的偏倚 |
| **離群值偵測** | 甄別偏離正常範圍的資料點 | 避免離群值對模型造成過大影響 |
| **類別編碼** | 把類別變數轉為數值 | 使模型能處理非數值資料 |
| **特徵選擇 / 建構** | 選擇對預測有用的特徵或合成新特徵 | 提升模型效能、降低維度 |
---
## 4.2 缺失值處理
1. **先確認缺失情況**
python
import pandas as pd
df = pd.read_csv('data.csv')
print(df.isnull().mean())
*Output 範例*:
age 0.02
income 0.00
gender 0.05
`
2. **刪除法**
*行刪除*:若缺失比例低於 5% 且不會影響樣本量。
*列刪除*:若特定變數全部缺失。
3. **填補法**
*數值型*:均值、中央値、最頻值、kNN、MICE。
*類別型*:最頻值、專門的類別編碼器(如 `sklearn.impute.SimpleImputer(strategy='most_frequent')`)。
4. **進階填補**
*Model‑Based Imputation*:利用其他特徵預測缺失值。
python
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imp = IterativeImputer(random_state=0)
X_imp = imp.fit_transform(X)
5. **記錄缺失**
*建立缺失標誌*,可作為模型的一部分特徵。
python
df['age_missing'] = df['age'].isnull().astype(int)
---
## 4.3 標準化與正規化
| 演算法 | 建議尺度 | 標準化方式 |
|--------|----------|------------|
| **SVM / KNN / Lasso** | 0 平均、單位方差 | `StandardScaler` |
| **神經網路** | 0~1 或 -1~1 | `MinMaxScaler` 或 `RobustScaler` |
| **樹演算法** | 無需尺度 | 可忽略 |
python
from sklearn.preprocessing import StandardScaler, MinMaxScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
> **小技巧**:在交叉驗證時,確保 `fit` 只在訓練集完成,`transform` 應在驗證集與測試集使用已學到的參數。
---
## 4.4 離群值偵測與處理
1. **箱型圖(Box‑plot)**:利用四分位數上限與下限。
python
import seaborn as sns
sns.boxplot(x=df['age'])
2. **IQR 方法**:
python
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
df = df[(df['age'] >= lower) & (df['age'] <= upper)]
3. **z‑score**:
python
from scipy import stats
df = df[(np.abs(stats.zscore(df['age'])) < 3)]
4. **Robust Methods**:如 `RobustScaler` 直接忽略離群值。
5. **離群值處理策略**:
* **刪除**:若數據量足夠。
* **截尾**:將離群值截斷為阈值。
* **保留**:若離群值可能代表重要訊息,保留並加標誌。
---
## 4.5 類別編碼
| 方法 | 優缺點 |
|------|--------|
| **One‑Hot Encoding** | 對於無序類別最安全,維度高 |
| **Ordinal Encoding** | 適用有序類別,簡化維度 |
| **Target Encoding** | 利用目標變數提升資訊量,需避免過擬合 |
| **Frequency / Count Encoding** | 取頻率或計數,適用高基數 |
python
from sklearn.preprocessing import OneHotEncoder
enc = OneHotEncoder(sparse=False)
X_cat = enc.fit_transform(df[['gender', 'city']])
> **實務提醒**:在交叉驗證時,確保編碼器只在訓練集學習,以防資訊洩漏。
---
## 4.6 特徵選擇與建構
### 4.6.1 相關性分析
python
corr = df.corr()
plt.figure(figsize=(10,8))
sns.heatmap(corr, annot=True, cmap='coolwarm')
### 4.6.2 統計測試
* **卡方檢定**(離散特徵)
* **ANOVA / t‑test**(連續特徵)
### 4.6.3 迴歸係數/重要度
* **Linear Models**:係數大小判斷
* **Tree‑based**:feature_importances_
### 4.6.4 主成分分析 (PCA)
python
from sklearn.decomposition import PCA
pca = PCA(n_components=0.95) # 保留 95% 變異
X_pca = pca.fit_transform(X_scaled)
### 4.6.5 交互特徵 & 多項式特徵
python
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
X_poly = poly.fit_transform(X)
### 4.6.6 連結模型特徵
利用已有模型的預測結果作為新特徵,可提升下游模型表現。
---
## 4.7 實戰案例:二手車價格預測
| 步驟 | 操作 | 工具/程式碼片段 |
|------|------|-----------------|
| 1 | 資料讀取 | `pd.read_csv()` |
| 2 | 缺失處理 | `SimpleImputer` + `age_missing` |
| 3 | 類別編碼 | `OneHotEncoder` |
| 3 | 標準化 | `StandardScaler` |
| 4 | 離群值處理 | IQR 截尾 |
| 5 | 特徵選擇 | `SelectFromModel` + RandomForestRegressor |
| 6 | 建構多項式特徵 | `PolynomialFeatures(degree=2)` |
| 7 | 迭代訓練 | XGBoost + LightGBM |
| 8 | 評估 | MAE / RMSE |
python
import pandas as pd
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler, PolynomialFeatures
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
# 1. 讀取
train = pd.read_csv('used_cars_train.csv')
X = train.drop('price', axis=1)
y = train['price']
# 2. 前處理管線
numeric_features = ['year', 'mileage', 'engine_size']
categorical_features = ['make', 'model', 'color']
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer(transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
# 3. 模型
model = Pipeline(steps=[
('preprocessor', preprocessor),
('poly', PolynomialFeatures(degree=2, include_bias=False)),
('regressor', RandomForestRegressor(n_estimators=500, random_state=42))
])
# 4. 交叉驗證
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5, scoring='neg_mean_absolute_error')
print('MAE:', -scores.mean())
> **學習重點**:此案例示範了如何串接缺失填補、標準化、類別編碼、交互特徵與樹模型在同一管線中,並保證資訊洩漏防止。
---
## 4.8 小結
* **前處理是基礎**:正確處理缺失、尺度與離群值,可避免模型學習到錯誤訊息。
* **特徵選擇是關鍵**:透過統計、模型重要度與降維,既能提升精度,也能減少計算負擔。
* **管線化**:使用 `Pipeline`、`ColumnTransformer` 及交叉驗證可確保過程 reproducible 且不洩漏。
* **不斷實驗**:不同領域(金融、醫療、圖像)對前處理的需求各異,務必在實務中多試驗、驗證。
---
> **參考文獻**
> 1. "Feature Engineering for Machine Learning: Principles and Techniques for Data Scientists" – Bob Finlay
> 2. "Hands‑On Machine Learning with Scikit‑Learn, Keras & TensorFlow" – Aurélien Géron
> 3. Kaggle Notebook: "Used Cars Price Prediction" – DataCamp