聊天視窗

數據科學的藝術與科學:從基礎到實踐 - 第 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