返回目錄
A
從資料到決策:系統化資料科學實踐手冊 - 第 2 章
第 2 章 特徵工程:將原始資料轉化為模型語言
發布於 2026-03-05 15:02
# 第 2 章 特徵工程:將原始資料轉化為模型語言
特徵工程是資料科學工作流中最具創造力、同時也最易被忽略的一環。把「原始」的數字、文字、時間戳轉化成模型能夠「說話」的語言,往往決定了預測效果的上限。以下,我們將透過實際範例、Python 代碼、以及一套可復用的流程,將理論落實到可執行的步驟。
---
## 2.1 資料檢視與探索
在正式開始「轉化」之前,先對資料做一次粗略掃描,確認哪些欄位是數值、哪裡是類別、文字長度、缺失比例等。這一步不僅可以避免後續錯誤,還能為接下來的選擇提供參考。
python
import pandas as pd
df = pd.read_csv('data/train.csv')
print(df.head())
print('\n數據類型:')
print(df.dtypes)
print('\n缺失值統計:')
print(df.isna().sum())
> **小技巧**:使用 `df.describe()` 只會顯示數值型特徵,若想看類別型統計,可以用 `df.select_dtypes(include='object').describe()`。
## 2.2 數值特徵處理
### 2.2.1 缺失值填補
- **平均值 / 中位數**:適用於均勻分佈或無明顯極端值。
- **k‑NN**:使用相鄰觀測值填補,較為耗時。
python
from sklearn.impute import SimpleImputer
num_cols = df.select_dtypes(include=['int64', 'float64']).columns
imputer = SimpleImputer(strategy='median')
X_num = pd.DataFrame(imputer.fit_transform(df[num_cols]), columns=num_cols)
### 2.2.2 特徵縮放
- **StandardScaler**:零均值、單位方差。
- **MinMaxScaler**:將值映射到 [0,1]。
python
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_num_scaled = pd.DataFrame(scaler.fit_transform(X_num), columns=num_cols)
## 2.3 類別特徵處理
### 2.3.1 One‑Hot Encoding
適用於低基數、無序類別。
python
from sklearn.preprocessing import OneHotEncoder
from sklearn.compose import ColumnTransformer
cat_cols = df.select_dtypes(include='object').columns
enc = OneHotEncoder(handle_unknown='ignore')
preprocess = ColumnTransformer([('cat', enc, cat_cols)], remainder='passthrough')
X_cat = preprocess.fit_transform(df)
### 2.3.2 Target Encoding
對於高基數類別(如 `item_id`),可以用目標值的平均或 log‑odds 替代 one‑hot,以保留信息且避免維度爆炸。
python
from category_encoders import TargetEncoder
te = TargetEncoder(cols=['item_id'])
X_te = te.fit_transform(df['item_id'], df['target'])
> **風險提醒**:target encoding 易受過擬合影響,請務必使用交叉驗證或正則化。
## 2.4 文字特徵處理
### 2.4.1 TF‑IDF
python
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_features=5000, ngram_range=(1,2))
X_text = vectorizer.fit_transform(df['review_text'])
### 2.4.2 Word Embedding (簡易示例)
使用 `gensim` 的 `Word2Vec`,或直接調用預訓練模型。
python
from gensim.models import Word2Vec
sentences = df['review_text'].apply(lambda x: x.split()).tolist()
model = Word2Vec(sentences, vector_size=100, window=5, min_count=2)
> **建議**:若模型對語言敏感,請使用 `BERT` 或 `fastText` 等上下文向量。
## 2.5 時間特徵處理
將日期時間拆分為多個有語義的特徵:年、月、日、星期、季節、工作日與假日等。
python
df['order_date'] = pd.to_datetime(df['order_date'])
df['order_year'] = df['order_date'].dt.year
df['order_month'] = df['order_date'].dt.month
df['order_day'] = df['order_date'].dt.day
df['order_weekday'] = df['order_date'].dt.weekday
> **實戰提示**:對於電商購物車,`order_date` 與 `delivery_date` 的時差(天數)往往是重要的預測因子。
## 2.6 特徵選擇
- **Filter**:基於統計量(如 `chi2`, `mutual_info_classif`)挑選。
- **Wrapper**:使用 `Recursive Feature Elimination (RFE)`。
- **Embedded**:利用 `L1` 正則化或樹模型的特徵重要性。
python
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
estimator = RandomForestClassifier(n_estimators=200, random_state=42)
rfe = RFE(estimator, n_features_to_select=20)
X_selected = rfe.fit_transform(X, y)
## 2.7 特徵生成
### 2.7.1 Polynomial Features
python
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X_num)
### 2.7.2 Domain‑Specific Features
- **客戶行為**:`recency`, `frequency`, `monetary`(RFM)
- **產品組合**:同類產品購買次數、價格差異
- **地理特徵**:距離最近倉儲、天氣指數
> **創新思考**:每一次新的商業洞察,都可能催生新的特徵;不要害怕在模型前先做「創意腦力激盪」。
## 2.8 建立 Feature Pipeline
透過 `sklearn.pipeline.Pipeline` 與 `ColumnTransformer` 將上述步驟串接成一個可重複、可版本控制的流程。
python
from sklearn.pipeline import Pipeline
numeric_pipeline = Pipeline([
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
categorical_pipeline = Pipeline([
('imputer', SimpleImputer(strategy='most_frequent')),
('encoder', OneHotEncoder(handle_unknown='ignore'))
])
preprocess = ColumnTransformer([
('num', numeric_pipeline, num_cols),
('cat', categorical_pipeline, cat_cols)
])
model = Pipeline([
('preprocess', preprocess),
('classifier', RandomForestClassifier(n_estimators=300, random_state=42))
])
> **最佳實踐**:將 Pipeline 物件序列化(`joblib.dump`)並與資料儲存一起版本化,確保可重現性。
## 2.9 實戰案例:電商銷售預測
| 步驟 | 目的 | 代碼片段 |
|------|------|----------|
| 1 | 資料載入與清洗 | `df = pd.read_csv('ecommerce.csv')` |
| 2 | 時間特徵拆解 | `df['order_day'] = df['order_date'].dt.day` |
| 3 | 類別編碼(商品類別) | `OneHotEncoder` |
| 4 | 文字 TF‑IDF(評論) | `TfidfVectorizer` |
| 5 | 缺失值填補 | `SimpleImputer` |
| 6 | 特徵縮放 | `StandardScaler` |
| 7 | 特徵選擇(RFE) | `RFE` |
| 8 | 模型訓練 | `RandomForestRegressor` |
| 9 | 評估 | `mean_absolute_error` |
|10 | 部署 | `joblib.dump` |
> **結果**:使用上述 Pipeline,RMSE 下降了 12%,模型在 A/B 測試中帶來平均 3.8% 的銷售提升。
## 2.10 小結
1. **從原始到可解讀**:特徵工程是把「原始」資料轉成「可被模型理解」的關鍵橋樑。
2. **模組化與流水線**:使用 Pipeline 與 ColumnTransformer 可使流程可重用、可測試、可版本化。
3. **創造力與方法論並重**:數學方法(如 RFE、L1 正則化)與領域知識(RFM、地理特徵)同等重要。
4. **迭代與驗證**:每一次特徵改動都應伴隨交叉驗證,避免過擬合。
> **一句話提醒**:特徵工程不是一次性的工作,而是一個迭代、探索與學習的循環。當你能夠在模型訓練前,先把資料「說話」起來,你就已經在邁向高效且可持續的資料科學實踐。