模型如劍,各有鋒芒。
有人斷言「樹王無敵」,也有人堅信「深網之道」。
有人劍走偏鋒,直取非線性之要害; 有人以柔制剛,在簡潔中取勝。
每一把劍,都在等待合適的對手與出場時機。
📝 前言
前面整理過資料,也做了一些特徵工程,終於走到了模型這一塊。這一步,感覺上才是真正進入「機器學習」的世界。
就像之前說的,最開始就是挑一個模型,把資料整理好就丟進去跑跑看,分數不好就換一種模型試試看。但是當真的要去爭取那一點點分數時,每一次的更換都是「試試看」,沒有一個正確的邏輯能告訴我,這樣做是往高分邁進,說不定更換後會變低分也說不定。
也因此,我發現我得學習各種模型的底層邏輯。自己創造一個模型對於我這種新手來講太過困難,但不懂底層邏輯,我也根本搞不懂模型是怎麼做決策的,然而——
什麼是樹模型?什麼又是神經網路?我一開始根本連它們差在哪都不清楚。各種名詞展開在我面前,令人眼花撩亂。
不過後來我慢慢發現,這些模型就像不同的工具,有的擅長切割、有的擅長分類、有的則善於從混亂中看出趨勢。與其硬背下那些技術名詞,我開始試著去理解它們的「性格」和「適合的場景」。
我不敢說自己完全搞懂了,但至少現在的我,比起一開始那種「亂槍打鳥」的狀態,能更有方向地去選擇模型,也知道該怎麼從資料特性出發去思考。 這篇會以我在 Kaggle 各項比賽中實際用過的兩大模型為主:樹模型與神經網路。另外也會簡單介紹經典的線性模型,以及幾種我自己有稍微接觸過的其他常見模型。
不過模型的種類非常多,而且各有千秋,要在一篇筆記裡全部講完實在太難,何況其中也有不少是我自己還沒碰過的。這篇主要是記錄我目前比較熟悉、也在實戰中確實用過的部分,未來如果有新的嘗試,也會再增加一些篇章來說明。
📂模型分類:他們其實都不是同一種人
一、線性模型(Linear Models)
這是最直觀、數學底最乾淨的一群。它們假設「特徵和目標之間有某種線性的關係」,就像是在試著用一條直線去擬合所有資料點。
- 常見代表:Linear Regression(線性回歸)、Ridge、Lasso
- 適合場景:特徵和目標變數之間關係單純時,或需要可解釋性強的模型
- 優點:簡單、快速、容易理解
- 缺點:學不出非線性,容易欠擬合
二、樹模型(Tree-based Models)
這群模型就像不斷分裂的選擇題,每一個分支都代表一種條件、一次判斷。它們不要求資料必須線性,而是用分段規則去逼近真實情況。
- 常見代表:Decision Tree、Random Forest、XGBoost、LightGBM、CatBoost
- 適合場景:類別型特徵多、資料結構複雜、需要處理非線性時
- 優點:強大、穩定、效果好;常見於 Kaggle 高分解法
- 缺點:容易過擬合(尤其是單棵樹),部分模型解釋性較差
三、神經網路(Neural Networks)
如果說前面那些模型像「手工雕刻」,那神經網路就像是用一個龐大的機器自己把結果磨出來。它不需要你明確告訴它規則,而是自己學著去找出模式。
- 常見代表:MLP、CNN、RNN、Transformer
- 適合場景:圖像辨識、自然語言處理、時間序列、高維非線性問題
- 優點:能處理結構複雜、特徵量龐大的問題;效果好
- 缺點:難以解釋、需要大量資料、容易訓練不穩定
四、其他模型(我知道但目前還不熟)
這些模型在某些領域也很有代表性
- SVM
- 適合小樣本分類,擅長畫出清晰的「分隔線」。
- k-NN
- 直覺、屬於「懶惰學習」,在預測時才計算與鄰居的距離。
- Naive Bayes
- 常見於文字分類,速度快、原理簡單。
- ARIMA / Prophet
- 專門處理時間序列,擅長捕捉趨勢與週期性。
- K-means / DBSCAN
- 無監督學習常見演算法,用於分群與探索性分析。
有些模型我知道名字,也大概看過別人怎麼用,但自己實際上沒操作過太多。
如果未來有實作經驗,再另外整理出來寫一篇筆記補上。
👉 接下來,就從我真的有碰過的幾種模型開始。
線性模型、樹模型,還有最近才慢慢學會怎麼用的神經網路。
📘 線性模型深入解析
線性模型用到的方法,是最常見,也是統計學、線性代數等數學科目一定會學到的「線性回歸」。
老實說,第一次看到有哪些模型可以選時,線性模型是我直接跳過的。
當時我心想:「不就是做線性回歸,然後外推到預測點而已嗎?這個我甚至手算都行。」 但後來才發現,線性模型還是有它好用的地方,尤其在資料特徵不多、關係單純、需要可解釋性的場景裡,它是個相當不錯的起手式。
我們這邊不會深入數學細節,只會大致帶過原理,以下先大概說明線性回歸的原理。
Scikit-learn
裡的**LinearRegression
**是一個典型的多元線性回歸模型,其核心原理很簡單。
為每一個特徵找出一個合適的「權重」,讓全部相加的結果,儘可能貼近真實值。
預測值 = 特徵1 × 權重1 + 特徵2 × 權重2 + ... + 截距
從這個數學式可以看出,特徵值的大小會直接影響模型學出來的權重。
也因此,線性模型對於「離群值」與「特徵大小落差」非常敏感。
這也解釋了為什麼,在使用線性模型之前,我們必須先對資料做適當的標準化或縮放處理,否則模型可能會被某些異常值拉歪,學出完全不合理的權重分配。
這裡舉例,如果一個欄位的數值範圍是 0~1,另一個是 0~10000,那後者很可能會在模型裡佔掉大部分的「解釋空間」,即使它其實沒什麼關聯性。
這也是為什麼,使用線性模型時,我們通常會先做特徵的「標準化」或「正規化」,像是:
- MinMaxScaler:把特徵壓到 0~1 範圍
- StandardScaler:轉換成平均為 0、標準差為 1 的分佈
- RobustScaler:針對有離群值的資料使用中位數與 IQR 做縮放
這些方法可以避免某些欄位的數值太大而讓模型失衡,讓每個特徵在訓練時的「權重競爭」回到公平狀態。
scikit-learn裡其他線性模型
除了最基本的 LinearRegression
,Sklearn 還有幾個進階版的線性模型,它們長得很像,但在訓練時會多加一點「限制條件」或「懲罰」,讓模型表現得更穩定。
- Ridge
- 特性 / 原理:加入 L2 正則化,懲罰權重平方值,讓模型收斂更平滑。
- 適合場景:特徵很多但彼此關係分散時。
- Lasso
- 特性 / 原理:加入 L1 正則化,懲罰權重絕對值,可讓部分特徵權重變 0。
- 適合場景:用來自動做特徵選擇。
- ElasticNet
- 特性 / 原理:L1+L2 的混合型正則化,兩邊優點兼具。
- 適合場景:欄位多又不確定哪些重要時。
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
# 基本線性回歸(無正則化)
linear = LinearRegression()
# L2 正則化(Ridge)
ridge = Ridge(alpha=1.0)
# L1 正則化(Lasso)
lasso = Lasso(alpha=0.1)
# 混合正則化(ElasticNet)
elastic = ElasticNet(alpha=0.1, l1_ratio=0.5)
內部參數可以參考Scikit-learn
網站的說明:
https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html
小結
簡單的線性模型,不一定能解出複雜問題,但在理解資料、建立 baseline 上依然非常有價值。當我們遇到更複雜、非線性的資料結構時,就會需要更強大、彈性的模型——這時候,樹模型就會登場了。
📘 樹模型深入解析
當初接觸機械學習前,就有聽過經典樹模型的大名「隨機森林」。
那時什麼都不懂,不懂森林怎麼隨機?又怎麼跟機械學習扯上邊?
後來才知道,這名字其實是從它的模型結構來的。
隨機森林是由很多棵「決策樹(Decision Tree)」組成的,而樹模型的核心,其實就是那個概念。
所以什麼是決策樹(Decision Tree)
其實決策樹就是一連串的動作方向判斷,這裡舉個例子:
Q:該吃甚麼晚餐?
這時你就會摸摸錢包,看看日子,想想昨晚吃了什麼。
你發現錢包還夠錢,可能就買麥當勞吃。 你發現今天是個好日子,可能就直接去吃鐵板燒。 你想起昨晚已經吃過麥當勞了,那今天就不吃了,改吃拉麵。
這一連串的決策行為,我們可以將它這樣畫出。
有錢嗎?
|
┌────────┴────────┐
否 是
| |
超商麵包 今天是特殊日子嗎?
|
┌──────┴──────┐
否 是
| |
昨天吃什麼? 吃鐵板燒
|
┌────────┴────────┐
麥當勞 其他
| |
拉麵 麥當勞
這就是決策樹的核心思想:根據一個又一個條件,逐步縮小選擇範圍,直到最後做出決定。
這樣一棵簡單的決策樹就畫出來了,有枝幹有葉子,也有結點。
我們將機器學習的概念套進去,每一個枝末(葉節點)就是模型最終的預測結果;每一個節點就是一個用來判斷的特徵條件。
而這棵「樹」,其實是由模型自動從訓練資料中長出來的,也就是說,我們不需要手動設定規則(像是「錢多就吃鐵板燒」),模型會自己找出哪些特徵最能幫助它做出準確的判斷。
接下來來詳細說一下:
🌿 一棵樹怎麼長出來?
模型訓練的過程其實就是不斷地問自己:
「我現在要用哪個特徵,把資料切得最乾淨?」
這時就會用到像「基尼不純度(Gini Impurity)」、「資訊增益(Information Gain)」這類評估方式,來衡量「這個特徵有多會分資料」。
切完一次,再往下一層繼續切,直到:
- 切到的資料都是同一類(分類任務);
- 切到沒有更多能幫助預測的特徵;
- 或是樹太深、太雜亂,開始過擬合,這時會啟動「剪枝(Pruning)」的動作來修剪。
上面這些,就是構成「一棵樹」的基本原理與精神。
但如果只靠一棵樹,判斷方向就會被限制住,如果有其他優先判斷的順序,也就會判斷不出來。
這就是為什麼我們會需要「森林」和「梯度提升」這些強化版模型。
接下來就來看看幾種常見的樹模型,以及它們各自的特色與用途。
🌲 常見的樹模型與使用時機
市面上常見的樹模型,其實都建立在「決策樹」這個概念之上,只是用了不同的策略讓它變得更強壯、更穩定,甚至跑得更快。
下面列出幾個自己在kaggle上使用過的樹模型:
1. RandomForest:靠團隊力量取勝
它會建立很多棵「隨機長出來的決策樹」,每棵樹只看部分特徵和樣本,最後透過「多數決」做出預測。
- 優點:穩定、抗過擬合、幾乎不太需要調參
- 缺點:模型大,不太容易解釋為什麼這樣判斷
使用方法:
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(
n_estimators=100,
max_depth=5,
min_samples_split=2,
max_features='sqrt',
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
n_estimators
- 說明:樹的數量。
- 實務建議:越多越穩定,但也越慢,常見值約 100~500。
max_depth
- 說明:每棵樹的最大深度。
- 實務建議:用來控制模型複雜度,避免過擬合。
min_samples_split
- 說明:分裂節點的最小樣本數。
- 實務建議:數值越大會讓樹更簡單,越小模型越靈活。
max_features
- 說明:每次分裂時考慮的特徵數。
- 實務建議:'sqrt' 是常見預設值(對分類效果佳)。
random_state
- 說明:隨機種子。
- 實務建議:為了結果可重現性,建議固定。
更詳細的設定可以參考Scikit-learn
網站的說明:
https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html
2. 梯度提升(Gradient Boosting):逐步補強錯誤
這是另一種集成學習的思維:不是「大家一起投票」,而是「一棵接一棵地補前面犯的錯」。
每一棵新樹都會專注學習上一次預測錯的部分,逐步把預測調得更準。
- 優點:準確率通常不錯,邏輯清楚
- 缺點:訓練時間較長,容易過擬合(需搭配 early stopping)
from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier(
n_estimators=300,
learning_rate=0.05,
max_depth=4,
min_samples_split=5,
subsample=0.8,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
n_estimators
- 說明:樹的總數。
- 建議調整方向:100~1000(通常搭配 early stopping 使用)。
learning_rate
- 說明:每棵樹的學習幅度。
- 建議調整方向:數值小一點較穩定,建議 0.01~0.1。
max_depth
- 說明:單棵樹的深度。
- 建議調整方向:通常介於 3~6。
min_samples_split
- 說明:分裂節點的最小樣本數。
- 建議調整方向:常設 2~10,用來防止過擬合。
min_samples_leaf
- 說明:葉節點的最小樣本數。
- 建議調整方向:常設 1~10。
subsample
- 說明:每棵樹使用的資料比例。
- 建議調整方向:小於 1 時表示隨機採樣,常見設定 0.6~1.0。
max_features
- 說明:每棵樹能使用的特徵比例。
- 建議調整方向:可設 'sqrt'、'log2' 或浮點數比例。
3. XGBoost:強化版的 Boosting
XGBoost 是 Gradient Boosting 的強化版,名字是 eXtreme Gradient Boosting。跟原版比,它引入了很多工程與數學的優化:
- 使用二階導數(Hessian)來提升精度
- 支援 L1 / L2 正則化,幫助防止過擬合
- 支援缺失值處理、自動剪枝、多線程運算
- 優點:效能強、準確率高、Kaggle 比賽常勝軍
- 缺點:參數多、複雜度高,較不適合新手直接上手
import xgboost as xgb
model = xgb.XGBClassifier(
n_estimators=300,
learning_rate=0.05,
max_depth=6,
subsample=0.8,
colsample_bytree=0.8,
gamma=1,
reg_alpha=0.5,
reg_lambda=1,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
n_estimators
- 說明:樹的數量。
- 調整建議:建議搭配 early_stopping 使用。
learning_rate
- 說明:每棵樹的學習率。
- 調整建議:0.01~0.3,越小越穩定。
max_depth
- 說明:最大深度。
- 調整建議:常見設定為 3~10。
subsample
- 說明:每棵樹使用的資料比例。
- 調整建議:0.6~1.0。
colsample_bytree
- 說明:每棵樹用到的特徵比例。
- 調整建議:0.5~1.0。
gamma
- 說明:最小損失減少,用來限制分裂。
- 調整建議:數值越大越保守。
reg_alpha
- 說明:L1 正則化。
- 調整建議:可用於特徵選擇。
reg_lambda
- 說明:L2 正則化。
- 調整建議:主要用來抑制過擬合。
4. LightGBM:極速進化的機器學習快手
LightGBM 是微軟開發的樹模型,最大的特色就是:快。速度快、記憶體省、準確率也不差。
它不是傳統「一層一層長」的方式(Level-wise),而是用「葉子優先」的策略(Leaf-wise)來擴張樹,雖然容易過擬合,但效率驚人。
- 優點:訓練速度快、省資源、支援原生類別特徵
- 缺點:對資料敏感,可能需要更多調參來避免 overfitting
import lightgbm as lgb
model = lgb.LGBMClassifier(
n_estimators=300,
learning_rate=0.05,
max_depth=6,
num_leaves=31,
subsample=0.8,
colsample_bytree=0.8,
reg_alpha=0.5,
reg_lambda=1,
random_state=42
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
num_leaves
- 說明:每棵樹的葉節點數。
- 建議:越大越複雜,常見值約 31~128。
max_depth
- 說明:樹的最大深度。
- 建議:用來限制模型複雜度。
learning_rate
- 說明:學習率。
- 建議:通常搭配 early stopping 使用。
subsample
/colsample_bytree
- 說明:資料與特徵的抽樣比例。
- 建議:有助於提升泛化能力、減少過擬合。
reg_alpha
/reg_lambda
- 說明:L1 / L2 正則化。
- 建議:用來控制模型的泛化能力。
categorical_feature
- 說明:指定類別欄位(不需 One-hot)。
- 建議:讓 LightGBM 自動處理類別特徵。
5. CatBoost:貓貓型類別專家
CatBoost 是 Yandex(俄羅斯版 Google)開發的樹模型,特別針對「類別特徵」做了大量優化。
- 可以原生處理類別欄位(不需做 One-hot)
- 使用「ordered boosting」避免資訊洩漏
- 採用「對稱樹(symmetric tree)」讓推理更快
- 優點:處理類別特徵非常穩、效果不錯、參數較少
- 缺點:較冷門、初學者較少資源參考
from catboost import CatBoostClassifier
model = CatBoostClassifier(
iterations=300,
learning_rate=0.05,
depth=6,
l2_leaf_reg=3,
random_state=42,
verbose=0
)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
iterations
- 說明:樹的數量。
- 建議:常見設定在 100~1000。
learning_rate
- 說明:每棵樹的學習率。
- 建議:通常設在 0.01~0.1 之間。
depth
- 說明:樹的深度。
- 建議:常見值為 4~10。
l2_leaf_reg
- 說明:L2 正則化強度。
- 建議:是抑制過擬合的重要參數。
cat_features
- 說明:指定類別特徵欄位。
- 建議:可自動處理類別特徵,不需額外轉換。
✅ 總結一下
- RandomForest
- 適合情境:快速上手、泛用穩定。
- 優點:模型穩定、抗噪性強、少量調參即可。
- 缺點:解釋性困難、模型通常較大。
- Gradient Boosting
- 適合情境:需要精細調控、錯誤導向修正。
- 優點:能逐步疊代逼近準確解。
- 缺點:訓練速度慢、容易過擬合。
- XGBoost
- 適合情境:追求高精度、Kaggle 比賽常見。
- 優點:強大的正則化能力、多功能性。
- 缺點:模型結構複雜、需要較多調參。
- LightGBM
- 適合情境:大量資料、高維度特徵。
- 優點:訓練快、省資源、表現優秀。
- 缺點:容易過擬合,需要謹慎設定參數。
- CatBoost
- 適合情境:類別資料多、希望前處理少。
- 優點:內建類別特徵處理、效果穩定。
- 缺點:文件相對較少、社群與資源不多。
樹模型的家族其實很大,我這篇主要介紹的是在我有實際運用過的幾種樹。
但除此之外,其實還有很多其他類型的樹模型,也各自有其專精的場景與邏輯,比如:
- Extra Trees:與隨機森林類似,但在節點分裂上更隨機化,訓練速度快,有時會有更好的泛化能力。
- Isolation Forest:專為異常偵測設計,透過隨機分割空間來尋找孤立樣本。
- Rotation Forest:結合 PCA 與多模型方式,提升分類能力但計算量大。
這類樹模型我比較少用到,同時在網路上的資料也比較少
📘 模型融合:Voting、Stacking 與朋友們
就像前面提到的,雖然我們介紹的都是樹模型,但它們各自使用了不同的策略來進行分類,每一種都有自己擅長處理的資料類型。有些模型在整體表現上可能不如其他,但在特定結構的資料上卻能發揮強大威力;而那些總體表現突出的模型,反而有可能在某些特定樣本上失準。
於是我開始想:為什麼不能把這些模型的優點結合起來?
事實上,這不是什麼天馬行空的想法,而是一種在機器學習領域非常成熟的策略,叫做 Ensemble Learning(集成學習)。
前面提到的 RandomForest 和 XGBoost,其實本身就是集成學習的代表:它們是由多棵樹組成的模型,透過「團隊合作」來提升預測效果。而除了這些「內建融合」的模型,我們也可以手動組合不同類型的模型,設計出更靈活的集成策略。
這就是我們接下來要介紹的 Voting 和 Stacking。
🔹 Voting:投票表決
Voting 是最直觀的集成方式,把多個模型的預測結果拿來「投票表決」,讓多數人說了算。
根據輸出型態的不同,Voting 又分為兩種:
- 硬投票(Hard Voting):直接看每個模型預測的類別,哪個類別票數最多就選哪個。
- 軟投票(Soft Voting):看每個模型預測出來的機率分布,將機率加總後選出機率最高的類別。
適用於模型不太相似,但各有強項的情況,可以有效彌補某一模型的盲點。
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
from catboost import CatBoostClassifier
model_rf = RandomForestClassifier(n_estimators=100, max_depth=6, random_state=42)
model_xgb = xgb.XGBClassifier(n_estimators=300, learning_rate=0.05, max_depth=6, random_state=42)
model_cat = CatBoostClassifier(iterations=300, learning_rate=0.05, depth=6, verbose=0, random_state=42)
voting_model = VotingClassifier(
estimators=[('rf', model_rf),('xgb', model_xgb),('cat', model_cat)],
voting='soft' # 可選 'hard' 或 'soft'
)
voting_model.fit(X_train, y_train)
y_pred = voting_model.predict(X_test)
🔧 Voting 的優缺點
優點
- 結構簡單,不容易出錯。
- 對異常值有一定抗性。
- 易於整合多種模型(線性、樹、SVM 都能用)。
缺點
- 沒有學習「誰比較準」,所有模型一視同仁。
- 如果模型彼此太相似,效果容易被稀釋。
- 無法自動權衡模型的好壞。
🚨 Voting 使用建議
- 模型越多樣(越異質),越有機會互補
- 若各模型結果非常一致,效果提升有限
- 可作為 baseline 的進階版,或快速測試集成效果
🍹 Blending:簡單又實用的混合方式
Blending 是集成學習中最直觀的一種:直接把幾個模型的預測結果混合在一起,不需要複雜的結構,也不用再訓練新的模型。
最常見的作法是「加權平均」,就像調酒師在不同酒精中選出比例,把每個模型的預測加起來:
python
複製編輯
final_pred = 0.6 * model1.predict(X) + 0.4 * model2.predict(X)
這種方式的好處是:
- 快速、簡單、不易出錯
- 適合模型數量不多、也沒有太大落差的情況
- 模型越互補,效果越好
實務上可以根據交叉驗證的成績,幫每個模型設定權重,或是單純用平均也可以跑出不錯的結果。
🧠 有時我們會更進一步,把模型的預測結果當成特徵,再丟進一個 Logistic Regression(或 XGBoost)去學習最適的組合方式,這種就叫做進階型的 Blending,跟我們接下來要介紹的 Stacking 有點像,但流程上更簡單些。
🧩 Stacking:分工合作、最終整合
Stacking(堆疊) 是集成學習中另一種更聰明的方式:
前面的模型先各自對資料做出預測,
然後再把這些預測結果拿去當作「新特徵」,交給最終模型(Meta Model)做最終判斷。
這種設計能更有策略地整合各模型的優勢,也會讓整體預測更穩。
from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
import xgboost as xgb
from catboost import CatBoostClassifier
# Base 模型們
model_rf = RandomForestClassifier(n_estimators=100, max_depth=6, random_state=42)
model_xgb = xgb.XGBClassifier(n_estimators=300, learning_rate=0.05, max_depth=6, random_state=42)
model_cat = CatBoostClassifier(iterations=300, learning_rate=0.05, depth=6, verbose=0, random_state=42)
# Meta 模型:這裡選擇邏輯回歸,簡單又穩
meta_model = LogisticRegression()
# Stacking 組合
stacking_model = StackingClassifier(
estimators=[('rf', model_rf),('xgb', model_xgb),('cat', model_cat)],
final_estimator=meta_model,
passthrough=False, # 是否也給 meta model 原始特徵
cv=5,
n_jobs=-1
)
stacking_model.fit(X_train, y_train)
y_pred = stacking_model.predict(X_test)
💡 Stacking 小建議:
- Meta 模型建議使用簡單、泛化性強的模型(如邏輯回歸、線性模型)
- 可以搭配
GridSearchCV
、Optuna
調參讓效果更穩定 - 不建議用太相似的模型堆疊,這樣融合意義會降低
🔧 樹模型的超參數調整:不是亂轉的旋鈕
學會用模型是一回事,但要把模型調出最適的味道,還得靠「超參數調整(Hyperparameter Tuning)」。這些參數就像武器的設定:同一把劍,劍身長一點、重量重一點,打出來的效果就不同。
尤其是樹模型,超參數的數量不少,影響也很大。如果不調,很多時候只能發揮七八成的實力;調得好,模型分數就能獲得進一步的提升。
🎯 常見超參數(以 XGBoost 為例)
n_estimators
(整數)- 樹的數量,越多越穩定,但也會越慢。
- 常與 early_stopping 搭配使用。
max_depth
(整數)- 每棵樹的最大深度,用來控制模型複雜度。
- 過深容易導致過擬合。
learning_rate
(小數)- 每棵樹的學習幅度。
- 越小越穩定,越大學習越快但風險也更高。
subsample
(0~1)- 每棵樹使用的資料比例。
- 有助於避免過擬合。
colsample_bytree
(0~1)- 每棵樹能用到的特徵比例。
gamma
(非負數)- 分裂節點時的最小損失減少值。
- 越高越保守,能抑制不必要的分裂。
reg_alpha
(非負數)- L1 正則化,能幫助特徵稀疏。
reg_lambda
(非負數)- L2 正則化,用來抑制過擬合。
以上幾個在 LightGBM、CatBoost 也有類似對應,只是名稱略有不同。
🧪 調參方式有哪些?
1. 手動調整(Manual Tuning)
最原始也最常見的方式。根據交叉驗證的結果,一步步手動改變參數。不需要額外工具,但容易漏掉好的組合。
2. 網格搜尋(Grid Search):最笨但最全面的方法
列出一堆參數組合,模型自動一一嘗試。保證能找出表現最好的組合,但非常耗時、效率低。
from sklearn.model_selection import GridSearchCV
from xgboost import XGBClassifier
param_grid = {
'max_depth': [3, 6, 9],
'learning_rate': [0.01, 0.1],
'n_estimators': [100, 300]
}
grid = GridSearchCV(XGBClassifier(), param_grid, cv=3, scoring='roc_auc')
grid.fit(X_train, y_train)
- 優點:簡單直接,不易錯。
- 缺點:計算量大,不適合參數多或資料量大的情況。
3. 隨機搜尋(Random Search):稍微聰明一點的隨機試試看
隨機從參數空間中抽樣,比 Grid Search 快很多,也常常能找到不錯的結果。
from sklearn.model_selection import RandomizedSearchCV
param_dist = {
'max_depth': range(3, 10),
'learning_rate': [0.01, 0.05, 0.1],
'n_estimators': range(100, 500)
}
random_search = RandomizedSearchCV(XGBClassifier(), param_distributions=param_dist, n_iter=10, cv=3)
random_search.fit(X_train, y_train)
- 優點:減少計算成本,常能找到不錯的參數。
- 缺點:有機會錯過最好的那組。
4. Optuna
這是目前最主流的超參數優化工具之一,用貝葉斯優化的方法去聰明地搜尋最佳組合,而不是傻傻亂試。它會根據每一次試驗的結果,調整下一步該試什麼。
import optuna
from xgboost import XGBClassifier
from sklearn.model_selection import cross_val_score
def objective(trial):
params = {
'max_depth': trial.suggest_int('max_depth', 3, 10),
'learning_rate': trial.suggest_float('learning_rate', 0.01, 0.1),
'n_estimators': trial.suggest_int('n_estimators', 100, 500),
'subsample': trial.suggest_float('subsample', 0.6, 1.0),
'colsample_bytree': trial.suggest_float('colsample_bytree', 0.6, 1.0)
}
model = XGBClassifier(**params)
score = cross_val_score(model, X_train, y_train, cv=3, scoring='roc_auc')
return score.mean()
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)
print(study.best_params)
- 優點:速度快、效果好,適合中大型資料集與複雜模型。
- 缺點:需要學習曲線,部分實作需安裝額外套件。
5. 自建最佳化演算法:動手打造你的調參流程
以上工具都可以很快上手,也不需要太多設定,但也因此會受到一定限制。當我們希望加上更複雜的條件、更多自定義的搜尋策略,或對某些參數組合進行排除與強化,就得自己設計搜尋流程。
這時候,「自建最佳化演算法」就派上用場了。
對我來講最經典的例子之一就是遺傳演算法(Genetic Algorithm, GA),它模擬基因的選擇、交配與突變過程,從一群隨機生成的參數組合中,不斷挑選出表現較佳的「後代」,進而演化出更好的模型設定。
像我自己在碩士論文中,就曾用 GA 進行馬達設計的最佳化,那時便是透過這樣的方式,讓效率與轉矩在演化過程中取得良好平衡。
這類演算法的自由度非常高,只要你定義得出「評分標準」與「元素表示法」,理論上什麼都可以拿來優化,包括模型超參數、特徵選擇、甚至資料處理流程。
📘 模型驗證與評估:Cross-Validation 的原理與選擇
當模型建立起來後,將訓練資料拆成訓練集跟測試集丟入模型,通常就想趕快看準確率的分數了,但偶爾發生訓練模擬出來的分數,與實際預測test集丟上kaggle的分數差太多了,第一次發現這種情況時,我滿頭問號,到底發生甚麼事情了?
後來才知道,這就是我們常說的「過擬合(Overfitting)」,模型在訓練資料上表現很好,但一遇到新資料就崩潰。為了避免這樣的情況,交叉驗證(Cross-Validation) 就是我們用來檢查模型是否具備「泛化能力」的關鍵方法。
🔁 為什麼要交叉驗證?
在實務中,通常我們會將資料分成「訓練集」與「測試集」,讓模型只看訓練資料,最後用測試集來評估表現。
但這樣的分法有個問題——測試結果高度依賴那個「切割點」。如果剛好某一類型資料都被切到測試集,模型表現就可能不準。為了更全面檢查模型能力,我們引入「多次切割、多次評估」的概念。
🧩 常見的交叉驗證方法
以下是幾種常見的交叉驗證策略:
1. K-Fold Cross-Validation
最常見的方法。將資料切成 K 份,每次拿其中一份當驗證集,剩下的 K-1 份當訓練集,重複 K 次。
- 適用情境:資料量中等,結構均勻
- 優點:能穩定評估模型在不同資料分布下的表現
- 缺點:資料量太小時容易產生高變異甚至欠擬合
from sklearn.model_selection import KFold
kf = KFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in kf.split(X):
X_train, X_val = X[train_idx], X[val_idx]
2. Stratified K-Fold
K-Fold 的「分層版」。會依據目標變數的分布進行切分,保證每一折中類別比例與整體資料一致,避免分類不均。
- 適用情境:分類任務、類別不平衡
- 優點:類別比例穩定,避免抽到「全是正樣本」的情況
- 缺點:無法應用於回歸問題
from sklearn.model_selection import StratifiedKFold
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in skf.split(X, y):
X_train, X_val = X[train_idx], X[val_idx]
3. TimeSeriesSplit
針對時間序列資料的專用交叉驗證方式。保留資料的時間順序,讓模型只能用「過去」預測「未來」,符合實際應用情境。
- 適用情境:股價、銷售量等有時間順序的任務
- 優點:符合真實預測時序,不洩漏未來資訊
- 缺點:資料會愈切愈少,早期折數資訊量低
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_idx, val_idx in tscv.split(X):
X_train, X_val = X[train_idx], X[val_idx]
小結
訓練分數漂亮,結果上了 leaderboard 卻慘不忍睹,這種事我也遇過。
有時是資料沒整理好,有時就是用錯驗證方法。
我曾在時間序列任務裡硬用 Stratified K-Fold,當時模擬分數直接超過 Top 1,信心滿滿一提交,結果直接躺底。
交叉驗證花時間沒錯,但如果能提早踩坑修正,絕對比賽後後悔來得划算。
📘 模型解釋利器:SHAP 值與特徵重要性
模型模擬穩、交叉驗證也通過了,那下一個問題就來了:
「這個模型到底是怎麼做出判斷的?」
「我改了某個特徵,為什麼分數會變高?」
「我現在用的是 XGBoost,它會不會根本就是憑感覺在選特徵?」
這時候,模型解釋工具就派上用場了。
而在眾多方法中,SHAP(SHapley Additive exPlanations) 幾乎是目前最主流也最被信任的解釋方式之一。
它不是告訴你哪個特徵重要,而是直接告訴你:
這個特徵對每一筆預測,究竟「拉高」還是「拉低」了結果。
🌈 SHAP 是怎麼做到的?
SHAP 的核心靈感來自「夏普利值(Shapley Value)」,這是一個來自博弈論的概念。
想像今天有一組團隊一起完成了某個專案,但每個人貢獻程度不同,你要怎麼公平分配獎金?
Shapley Value 的想法是這樣的:
把所有可能的出場順序都跑一次,計算每個人對於團隊表現的「邊際貢獻」,最後平均起來,這個值就叫做 Shapley 值。
SHAP 就是把這個概念套在模型預測上,試圖去回答:
「如果沒有這個特徵,模型會少了多少分數?」
「如果這個特徵晚一點加入,它對結果的貢獻會是多少?」
雖然聽起來很耗時,但 SHAP 對樹模型(像 XGBoost、LightGBM、CatBoost)有專門優化的解法 —— TreeExplainer
,速度非常快,甚至可以用在上萬筆資料上。
🧰 SHAP 可以做什麼?
SHAP 不只是告訴你特徵重要性,它還能幫助你做以下幾件事:
- 特徵重要性排序
- 說明:哪些特徵對模型最有影響?
- 常見工具:summary_plot。
- 每筆資料的解釋
- 說明:模型為什麼給出這個預測?
- 常見工具:force_plot。
- 特徵影響方向
- 說明:某個數值越高,會讓預測值上升還是下降?
- 常見工具:summary_plot(利用色彩區分)。
- 特徵交互作用
- 說明:兩個特徵之間是否存在互相影響?
- 常見工具:dependence_plot。
- 模型偏誤偵測
- 說明:模型是否在某些族群或子群上存在偏見?
- 常見工具:特徵分析+分群視覺化。
🛠️ SHAP 使用方式(以 XGBoost 為例)
import shap
import xgboost as xgb
# 建立模型
model = xgb.XGBClassifier()
model.fit(X_train, y_train)
# 建立 explainer(針對樹模型)
explainer = shap.TreeExplainer(model)
# 計算 shap 值
shap_values = explainer.shap_values(X_train)
# 繪製 summary plot
shap.summary_plot(shap_values, X_train)
# 依單一特徵畫交互圖(查看變化趨勢)
shap.dependence_plot("age", shap_values, X_train)
🖼️ SHAP 圖像解說
summary_plot
這是最常見也最經典的 SHAP 圖,告訴你:
- 哪些特徵對預測最重要(由上到下排列)
- 每個特徵的影響方向(紅色=特徵值高,藍色=特徵值低)
你可以快速發現:
- 哪些特徵是「高會拉高預測,低會拉低預測」
- 哪些特徵則可能是「反向影響」
dependence_plot
這是用來分析「特徵間交互作用」的利器。
例如你發現 age
對預測有很大影響,那它是不是會受到 income
或 education
的牽制?用這個圖可以看得一清二楚。
✅ 小結
SHAP 不只是「做圖好看」的工具,它是一個強大到可以讓你重新理解模型、調整特徵工程,甚至直接幫你排除資料異常與模型偏誤的助手。
若你用的是樹模型,真的值得加進你的分析流程裡。
🧠 神經網路:從樹走進深度世界
在前面,我們講過許多樹模型的結構與演化方式,它們擅長處理結構化數據、處理缺失值能力強、速度也快。但當遇到圖像、語音、自然語言這類非結構化資料時,樹模型就有些力不從心了。
這時,就該輪到神經網路(Neural Network)上場了。
1. 神經網路是什麼?
如果用一句話形容神經網路,它就是:
「由大量簡單的節點組成的函數近似器,靠大量資料與反覆訓練,學會如何將輸入對應到正確的輸出。」
這些節點就像人腦的神經元(Neuron),每個節點會接收前一層的輸入,加權後通過一個非線性函數,傳遞給下一層。
以下是一個最簡單的三層前饋神經網路(input → hidden → output)的結構圖:

2. 神經網路的構成要素
- 輸入層(Input Layer):接受資料,例如數字圖像、時間序列等。
- 隱藏層(Hidden Layers):主要的運算核心,節點數量與層數決定了模型的容量。
- 激活函數(Activation Function):加入非線性能力,常見的有 ReLU、Sigmoid、Tanh。
- 損失函數(Loss Function):評估預測與真實值差異,如 MSE、Cross-Entropy。
- 優化器(Optimizer):如 SGD、Adam,用來調整權重以減少損失。
- 反向傳播(Backpropagation):讓網路學會「哪裡做錯了」並調整自己。
3. 為什麼要用神經網路?
- 擅長處理大量特徵且關係複雜的問題
- 在非結構化資料(圖像、語音、文字)上效果特別好
- 能透過多層結構學會抽象概念與特徵轉換
但也不是沒缺點,像是:
- 訓練成本高、需要 GPU 加速
- 資料需求大,容易過擬合
- 難以解釋(黑箱)
4. 我們從哪裡開始?
初學者可以從 Keras(TensorFlow) 或 PyTorch 開始練習,這些框架已經把反向傳播、梯度下降都包好了,我們只需要關注模型設計與資料流程。
這裡是一個使用 PyTorch 建立簡單分類器的範例:
import torch
import torch.nn as nn
class SimpleNN(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super().__init__()
self.fc1 = nn.Linear(input_dim, hidden_dim)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(hidden_dim, output_dim)
def forward(self, x):
x = self.fc1(x)
x = self.relu(x)
return self.fc2(x)
model = SimpleNN(input_dim=20, hidden_dim=64, output_dim=2)
5. 常見神經網路架構
神經網路的「結構」就是它的骨架。不同問題會用到不同的網路架構,以下是幾種常見且實用的:
(1)前饋神經網路(Feedforward Neural Network, FNN)
- 最基礎的神經網路架構,資料只往前流動,不會回傳或循環。
- 適用:結構化資料分類、回歸問題。
(2)卷積神經網路(Convolutional Neural Network, CNN)
- 引入卷積層與池化層,強調「區域感知」與「權重共享」,非常適合圖像處理。
- 適用:圖像分類、物件偵測、醫療影像等。
(3)循環神經網路(Recurrent Neural Network, RNN)
- 網路具有記憶性,會保留前一時刻的輸出作為當前的輸入。
- 適用:時間序列、語音辨識、文字生成。
延伸架構如 LSTM、GRU,解決了 RNN 的梯度消失問題。
(4)Transformer
- 基於「注意力機制(Attention)」,大幅取代了 RNN 結構,是現在 NLP 領域的主力架構。
- 適用:語言模型(如 ChatGPT)、機器翻譯、摘要生成等。
6. 神經網路的各項設定
神經網路的設定彈性非常大,也因此一不小心就容易調得「過深過寬」,導致過擬合或訓練崩潰。
以下是常見幾個重要的超參數與建議調整方法:
hidden_dim
- 說明:每層神經元數量。
- 實務建議:32~512,依資料複雜度調整,太大容易過擬合。
num_layers
- 說明:隱藏層數量。
- 實務建議:1~3 層適合入門任務,層數更多時需配合正則化。
activation
- 說明:激活函數。
- 實務建議:ReLU 通用;輸出為機率時,最後一層使用 Sigmoid 或 Softmax。
optimizer
- 說明:參數更新方法。
- 實務建議:Adam 收斂速度快且穩定,入門任務推薦使用。
learning_rate
- 說明:學習率。
- 實務建議:通常從 0.001 開始;學不動可調高,若出現震盪則調低。
batch_size
- 說明:每次更新所用的資料量。
- 實務建議:常見設定為 32 或 64;若 GPU 顯存足夠可放大。
dropout
- 說明:隨機丟棄比例。
- 實務建議:常設 0.2~0.5,可有效減少過擬合。
🧪 實務調參策略
- 先固定架構,再微調學習率與 Batch Size
比如先用兩層 + ReLU + Adam,把學習率從 0.01 → 0.001 → 0.0001 試一輪。
- 觀察訓練與驗證 Loss 差距
若訓練 loss 很低但驗證 loss 很高 → 代表過擬合,可加入 Dropout、EarlyStopping。
- 使用 Learning Rate Scheduler
有些任務中會從高學習率開始,然後逐步降低,例如:
from torch.optim.lr_scheduler import StepLR
scheduler = StepLR(optimizer, step_size=10, gamma=0.5)
📌 其他技巧補充
- 使用 BatchNorm 可加速收斂與穩定訓練。
- 若資料量小,考慮用較淺層網路 + L2 正則化。
- 使用
Optuna
、Ray Tune
等工具進行自動超參優化,也是進階實務方法之一。
7. 函數大解析:激活、損失與學習率
🔸 激活函數
- ReLU
- 特性:快速、簡單、不飽和。
- 用途:主流首選。
- Sigmoid
- 特性:輸出範圍在 0~1。
- 用途:二分類輸出層常用。
- Tanh
- 特性:對稱、範圍在 -1~1。
- 用途:少數舊模型仍在使用。
- Softmax
- 特性:輸出為多類別機率分佈。
- 用途:多分類輸出層。
🔸 損失函數
- 回歸
- 函數:MSE、MAE。
- 說明:用於預測連續數值。
- 分類
- 函數:CrossEntropy。
- 說明:多類別分類任務常用。
- 多標籤分類
- 函數:BCEWithLogitsLoss。
- 說明:同時判斷多個標籤。
🔸 學習率與更新方式
- 學習率大:收斂快但不穩
- 學習率小:穩定但收斂慢
推薦搭配:
- Adam Optimizer:適合入門,收斂穩定
- Scheduler:如 StepLR、CosineAnnealingLR 可動態調整學習率
8. 補充:與樹模型的差異
- 適用資料
- 樹模型:結構化數據。
- 神經網路:非結構化數據(圖像、語音、文字)。
- 模型解釋性
- 樹模型:高,可透過特徵重要性解釋。
- 神經網路:較低,通常視為黑箱模型。
- 訓練速度
- 樹模型:快速。
- 神經網路:較慢,需要大量運算資源。
- 超參數數量
- 樹模型:中等,可調整項目有限。
- 神經網路:多,需特別注意學習率、層數等設定。
- 缺失值處理
- 樹模型:原生支援(例如 LightGBM)。
- 神經網路:通常需要填補或用特殊方式處理。
- 特徵工程
- 樹模型:非常重要,需要精心設計特徵。
- 神經網路:能自動學習特徵,相對需求較少。
神經網路就像是能解鎖 AI 更深層領域的鑰匙。它不只是一種模型,而是一個龐大的家族,從 FNN 到 CNN,再到 Transformer,每一種都有它的使命與擅長領域。
✅ 總結:每個模型都有它上場的時候
這篇筆記一路從線性模型講到神經網路,說穿了就是在回答一個問題:
「到底該怎麼選模型?」
線性模型簡單直白,適合快速看出資料有沒有規律;
樹模型就像在走邏輯流程圖,擅長處理有結構、有邏輯的資料;
神經網路雖然是個黑箱,但它會自己學特徵,特別適合處理圖像、語音、文字這種「你也說不出到底要抓什麼」的資料。
不同模型就像不同的工具:
有的適合鋸,有的適合釘,有的可以鑽牆。
沒有絕對的好壞,只有適不適合這次的問題。
所以我想說的總結很簡單:
模型是工具,不是答案。
會用工具、知道什麼時候該換工具,才是重點。
你不用一開始就什麼都會,重要的是每用過一種模型,你就更懂得怎麼處理資料、怎麼看問題。慢慢來,一次一個任務,下一篇,我們開始進入kaggle題目,來看看實際是如何操作的。