
🙋♀️ 什麼是特徵(Feature)?
想像一個情境:
你想領養一隻小狗,到了收容所後,該怎麼跟承辦人員描述你想要的狗狗呢?
你可能會說:「我想要一隻可愛的小狗。」 但這樣的描述太模糊了,對方可能無法立刻理解你的偏好。
如果你改說:「我想要一隻咖啡色毛、黑嘴巴、看起來很可愛的小狗。」 這時候,承辦人員就更容易幫你找到符合條件的狗狗。
在這個例子中,像「咖啡色毛色」、「黑色嘴巴」這些可以觀察或量測的資訊,就稱為「特徵」。
📌 什麼是特徵工程?
特徵工程是指: 將原始資料進一步「轉換、處理或創造」成能夠讓機器學習模型更容易理解、學習的特徵。
這些新的特徵不一定直接來自原始資料,而是透過:
- 加工(例如數學轉換)
- 拆解(例如把地址拆成縣市/區域)
- 合併(例如創造新變數:身高 / 體重 = BMI)
- 編碼(將類別變數轉為數字)
- 選擇(挑出有幫助的特徵)
來強化模型的學習能力。
💡簡單來說,特徵是模型認識資料的方式,而特徵工程是讓模型看得更清楚、更準確的技巧。
🎯 為什麼需要特徵工程?
特徵工程也是機器學習流程中的一個環節,通常會在資料清理後進行,可以進一步的將資料轉換成更符合模型學習的樣子。

🧰 常見特徵工程技巧
1. 數值型特徵處理

# 標準化
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import pandas as pd
import numpy as np
df = pd.DataFrame({'value': [10, 20, 30]})
scaler = StandardScaler()
df['value_scaled'] = scaler.fit_transform(df[['value']])
# 正規化
scaler = MinMaxScaler()
df['value_normalized'] = scaler.fit_transform(df[['value']])
# 分箱
df['bins'] = pd.cut(df['value'], bins=[0, 15, 25, 35], labels=['low', 'medium', 'high'])
# 對數轉換(取log)
df['log_value'] = np.log1p(df['value']) # log(1 + x),避免 log(0)
print(df)
# 輸出
value value_scaled value_normalized bins log_value
0 10 -1.224745 0.0 low 2.397895
1 20 0.000000 0.5 medium 3.044522
2 30 1.224745 1.0 high 3.433987
說明
- 標準化、正規化都是透過轉換資料的分布,進而幫助模型學習。
- 分箱則是將數值型資料離散化的技巧。
- log這類相關的轉換方法很多,目的都是要將極值(很大或很小)對資料的影響變小
- 如: 原本數值為[10, 100, 1000, 1000]
- 以底數為10取log後,則變成[1, 2, 3, 4]
- 除了用在訓練資料之外,也常應用在預測結果的轉換,在此不深入探討。
2. 類別型特徵處理

# Label encoding
from sklearn.preprocessing import LabelEncoder
df = pd.DataFrame({'gender': ['M', 'F', 'F', 'M']})
le = LabelEncoder()
df['gender_encoded'] = le.fit_transform(df['gender'])
print(df)
# 輸出
gender gender_encoded
0 M 1
1 F 0
2 F 0
3 M 1
# One-hot encoding
df_encoded = pd.get_dummies(df, columns=['gender'])
print(df_encoded)
gender_encoded gender_F gender_M
0 1 False True
1 0 True False
2 0 True False
3 1 False True
# 頻率編碼(Frequency encoding)
freq = df['gender'].value_counts(normalize=True)
df['gender_freq'] = df['gender'].map(freq)
print(df)
# 輸出
gender gender_encoded gender_freq
0 M 1 0.5
1 F 0 0.5
2 F 0 0.5
3 M 1 0.5
# 文字向量化(TF-IDF)
from sklearn.feature_extraction.text import TfidfVectorizer
text_data = ['dog cat fish', 'dog dog cat', 'fish bird']
vectorizer = TfidfVectorizer()
tfidf_matrix = vectorizer.fit_transform(text_data)
df_tfidf = pd.DataFrame(tfidf_matrix.toarray(), columns=vectorizer.get_feature_names_out())
print(df_tfidf)
# 輸出
bird cat dog fish
0 0.000000 0.577350 0.577350 0.577350
1 0.000000 0.447214 0.894427 0.000000
2 0.795961 0.000000 0.000000 0.605349
說明
丟入模型的資料必須都是數值型資料,因此任何類別型特徵都要先經過數值化處理。
- Label encoding: 將標籤["A", "B", "C"]轉換為[1, 2, 3]
- 優點: 不額外新增特徵欄位
- 缺點: 特徵間不一定會有順序關係,可能不適合
- One-hot encoding: 將標籤["A", "B", "C"]轉換為[[1, 0, 0], [0, 1, 0], [0, 0, 1]]
- 優點: 保持各類別的獨立關係
- 缺點: 會增加特徵欄位,特徵總數容易暴增
- Frequency: 各類別出現頻率差異不大時不適用
- 文字向量化: 此為自然語言處理任務常用的技術,在此不討論。
- 用向量來表示文字
- 有興趣的人可以查閱"Word Embedding"相關資料。
3. 特徵創造(Feature Creation)

# 拆解日期
df = pd.DataFrame({'date': pd.to_datetime(['2024-01-01', '2024-06-20'])})
df['year'] = df['date'].dt.year
df['month'] = df['date'].dt.month
df['day'] = df['date'].dt.day
print(df)
# 輸出
date year month day
0 2024-01-01 2024 1 1
1 2024-06-20 2024 6 20
# 統計特徵
df = pd.DataFrame({
'city': ['A', 'A', 'B', 'B'],
'price': [10, 20, 15, 25]
})
# 每個城市的平均價格
df['city_avg_price'] = df.groupby('city')['price'].transform('mean')
print(df)
# 輸出
city price city_avg_price
0 A 10 15.0
1 A 20 15.0
2 B 15 20.0
3 B 25 20.0
# 欄位交互特徵
df = pd.DataFrame({
'city': ['A', 'A', 'B', 'B'],
'price': [10, 20, 15, 25]
})
# 計算每筆資料的單位價格(與該城市平均價格相比)
df['price_per_unit'] = df['price'] / df['city_avg_price']
print(df)
# 輸出
city price city_avg_price price_per_unit
0 A 10 15.0 0.666667
1 A 20 15.0 1.333333
2 B 15 20.0 0.750000
3 B 25 20.0 1.250000
說明
特徵創造顧名思義就是自己創造新的特徵出來使用。
- 拆解日期: 將日期可以拆成年/月/日/週/季等多個欄位
- 可在非時間序列模型中引入時間資訊
- 統計特徵: 計算特定欄位之平均數、眾數、中位數和變異數等統計量當成新特徵。
- 集中趨勢:平均數、眾數、中位數
- 分散趨勢:變異數
- 欄位交互特徵:運用Domain knowledge來創造新特徵
- 如:價格和數量可以計算成單位價格
- 通常有機會更能影響要預測的Y欄位
4. 特徵選擇(Feature Selection)

import pandas as pd
# 模擬資料
data = {
'身高_cm': [160, 165, 170, 175, 180],
'體重_kg': [55, 60, 68, 72, 80]
}
df = pd.DataFrame(data)
# 計算皮爾森相關係數
correlation = df.corr(method='pearson')
print(correlation)
# 輸出
身高_cm 體重_kg
身高_cm 1.000000 0.987241
體重_kg 0.987241 1.000000
說明
- 0.987 表示「身高與體重」高度正相關,數值接近 1。
- 通常會將相關性高的特徵留下,相關性低的特徵刪除
- 但這只計算"線性"相關性,沒有考慮到"非線性"相關性
- df.corr() 預設使用 Pearson 方法,也可用 "spearman" 或 "kendall" 方法分析非線性關係。
特徵選擇的方法有很多不同類別,也相對複雜,常用的方法為Lasso Regression、Random Forest和XGboost,簡單一點的方法則是使用相關係數和共線性來挑選特徵。這部分會在另外討論!!! 初學者可以使用較為簡單的相關係數來嘗試即可~