聊天視窗

資料驅動決策:從數據探索到模型部署 - 第 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 總結 特徵工程是資料科學流程中最具「創造力」與「風險」的環節。透過結合統計洞察、業務領域知識與先進工具,你能把雜亂的數據轉化為模型語言,讓機器學習模型真正擁抱業務價值。接下來,我們將把這些特徵帶入模型構建,並評估其對預測效果的具體貢獻。