🗺️ 程式互動式地圖
AI 線・sklearn 流程

scikit-learn 的 fit、transform、predict:誰該看到哪一份資料

程式每一行都跑得動、測試分數也很漂亮,模型一上線卻打回原形,原因常常是某個會「學東西」的步驟偷看了測試資料。這一頁先把 fit、transform、predict 的分工講清楚,再看切分、前處理、Pipeline 與交叉驗證要怎麼排才不會資料洩漏。

流程排序器:兩回合步驟卡 洩漏模擬:10 筆示意資料 有沒有洩漏:13 張情境卡

💡 先搞懂問題

虛構的「青松物流」想用過去的出貨紀錄,預測哪些包裹會延誤。資料分析師小陳寫了十幾行 scikit-learn 程式:讀進資料、標準化、切成訓練集與測試集、訓練邏輯迴歸、算準確率,測試集拿到 0.93。上線一個月後回頭對帳,實際命中率只有七成左右(數字皆為示意)。程式從頭到尾沒有任何錯誤訊息,問題出在其中一行的位置:他先對整份資料呼叫 StandardScaler().fit_transform(X),之後才呼叫 train_test_split。

新手在這裡卡住,通常不是因為不認得函式,而是說不出三件事:fit、transform、predict 各自在做什麼?哪些步驟會「從資料學東西」?測試資料在整個流程裡可以出現在哪幾行?scikit-learn(簡稱 sklearn)的每個物件都用同一套介面:fit 從資料學出參數,transform 用學到的參數轉換資料,predict 用學到的參數做預測。規則只有一條:會學東西的 fit 只能看訓練資料,測試資料只能被 transform 與 predict。違反這條規則,測試資料的資訊就會悄悄流進訓練過程,這叫資料洩漏(data leakage),結果是評估分數比模型面對真正新資料時的表現好。

錯誤寫法:先 fit,再切分 整份資料 X含日後的測試列 fit_transform(X)平均、標準差含測試列 切分太晚了 測試分數偏高示意 0.93 測試列在 fit 時已經被「看過」,分數不再代表陌生資料 正確寫法:先切分,fit 只看訓練集 整份資料 切分 訓練集:fit + transform 測試集:只 transform mean_、scale_ 模型 fit predict+評分一次
上半部紅框是小陳的寫法:標準化器在切分之前就看過整份資料,等於測試列也參與了「算平均、算標準差」。下半部藍框先切分,藍色虛線代表只有訓練集學到的 mean_ 與 scale_ 被拿去轉換測試集,測試集本身從來沒有被 fit 過。

生活比喻:段考前的複習講義

晴空補習班的林老師要幫學生準備下週的數學段考。她手上有兩疊卷子:一疊是過去的練習卷,另一疊是學校寄來、規定考試當天才能拆封的段考卷。正常的做法是:林老師只從練習卷整理出常考題型和平均難度,編成一份複習講義與一套評分標準;學生用講義練習;考試當天拆開段考卷作答,批改時套用事先定好的同一套評分標準。這樣得到的分數,才代表學生面對沒看過的題目時的實力。

假設林老師為了讓講義「更貼近考試」,先偷偷拆開段考卷,把段考題也算進平均難度,再編講義。講義裡一題段考原題都沒有,但題型比例和難度分布已經被段考卷影響,學生當然考得比較好;換成別校的考卷,分數就掉下來。值得注意的是,這種偷看不需要整張考卷外流,光是「平均難度」這種統計數字就夠了。

回到程式:練習卷是訓練集(training set),封起來的段考卷是測試集(test set)。林老師從練習卷整理重點、算平均難度,對應 fit;用同一份講義與評分標準處理每一份卷子,對應 transform;學生作答對應模型的 predict。fit_transform 是「整理重點並立刻套用到練習卷」,所以只能用在訓練集。先拆段考卷再編講義,就是對全部資料 fit 之後才切分,也就是資料洩漏。
補習班(比喻) sklearn 程式 過去的練習卷 訓練集 X_tr、y_tr 封起來的段考卷 測試集 X_te、y_te 只從練習卷整理重點 fit:學出 mean_、coef_ 同一套講義與評分標準 transform:套用學到的參數 學生作答 predict:產生預測 整理重點並套到練習卷 fit_transform(只給訓練集) 先拆段考卷再編講義 全部資料 fit 後才切分
左欄是比喻,右欄是對應的程式概念。前五列是正常流程,最後一列紅色是洩漏。實驗室二會把最後一列實際算一次:同樣 10 筆示意資料,fit 看到的範圍不同,學到的平均和標準差就不同。

這個比喻有兩個地方和實際不同。第一,學生會「背」講義,模型也會記住訓練資料,但資料洩漏指的不是模型記太熟(那是過擬合,overfitting),而是評估用的資料參與了學習,讓評估本身失真。第二,真實的洩漏通常比偷看考卷更不起眼:一個平均數、一份類別清單、一組被挑中的特徵,都只會讓分數偏高一點,程式也不會報錯,所以只看分數幾乎察覺不到,必須回頭讀程式流程,問每一個 fit「你看過哪些資料」。

🎮 互動實驗室一:建模流程排序器

下面有兩回合:第一回合是手動寫法的 8 個步驟,第二回合改用 Pipeline 的 7 個步驟。把左邊的步驟卡排進右邊的編號格:電腦上可以直接拖曳;手機或想用點的,先點一張卡(會被框起來),再點一個格子。點選格子裡的卡片後再點另一格可以互換,選取後點左邊卡片區可以把它退回。排滿後按「檢查順序」,排錯的格子會晃動,並說明那樣執行時程式實際會出什麼事。正確答案不只一種,只要依賴關係對就算對。

已放 0 / 8
檢查次數 0
狀態 排列中
步驟卡(順序已打亂)
執行順序
畫面說明:左邊是打亂的步驟卡,右邊是空的執行順序。先找一定排第一的步驟,再找一定排最後的步驟。

🎮 互動實驗室二:標準化洩漏模擬

示意資料是晴空咖啡 10 位會員的月消費(單位:百元)。用 train_test_split(x, test_size=0.3, random_state=8) 切分後,7 筆是訓練集、3 筆是測試集,下表就是實跑切出來的結果。上方切換兩種寫法,看 StandardScaler 學到的 mean_、scale_ 與每筆資料轉換後的 z 分數;再拖動「測試集整體偏移」,模擬上線後的新會員消費普遍變高。假設下游有一條規則:z 分數的絕對值大於 3 就標成「異常消費」。

這次執行的程式

scaler = StandardScaler().fit(X_tr)   # 只用 7 筆訓練集
z_tr = scaler.transform(X_tr)
z_te = scaler.transform(X_te)         # 測試集套用訓練集的尺
每位測試會員的消費都加上這個數(百元,示意);0 代表原始資料

數線與 z 分數

🎮 互動實驗室三:這段程式有沒有洩漏

每張卡是一小段原創的 sklearn 程式,每一段都能正常執行。請判斷它有沒有資料洩漏,有的話是哪一種。判斷時對每一個 fit、fit_transform、fit_resample 或「拿分數來挑」的動作問同一個問題:它看過的資料裡,有沒有之後要拿來評估的那一份?答完會說明理由,旁邊的分類表會亮起正解。

得分 0 / 0
連續答對 0
畫面說明:先找出程式裡所有會學東西的動作。

📘 原理補完

1. 一套介面,兩種角色

scikit-learn 官方文件把凡是有 fit 方法的物件都稱為估計器(estimator)。為了好記,可以把它們分成兩種角色:一種是轉換器(transformer),例如 StandardScaler、OneHotEncoder、SimpleImputer,負責把資料變形,有 fit、transform、fit_transform;另一種是模型,官方稱為預測器(predictor),例如 LogisticRegression、RandomForestClassifier,有 fit、predict,分類器多半還有 predict_proba。地圖節點裡說的「估計器」指的就是這一類會預測的模型。

不管哪一種,fit 學到的東西一律存在名稱結尾有底線的屬性:標準化器的 mean_、scale_,編碼器的 categories_,模型的 coef_、classes_。還沒 fit 就呼叫 transform 或 predict,會得到 NotFittedError。fit 會回傳物件本身,所以可以寫成 StandardScaler().fit(X_tr) 一行建好並學完。

轉換器 transformer StandardScaler、OneHotEncoder… fit transform fit_transform 輸出:轉換後的 X(形狀可能改變) fit 後才有:mean_、scale_、 categories_、statistics_ 模型 predictor LogisticRegression、RandomForest… fit predict predict_proba score 輸出:預測值、機率或一個分數 fit 後才有:coef_、classes_、 feature_importances_ 黃色的 fit_transform 與所有 fit:只能給訓練資料 白色的 transform、predict、predict_proba、score:測試資料可以用
左邊藍框是轉換器,右邊綠框是模型,兩者都有 fit,學到的值都存在結尾有底線的屬性。底部黃框是整頁最重要的一句:有「fit」字樣的方法只碰訓練資料,白色按鈕才是測試集可以用的。
方法做什麼誰有回傳測試集可以用嗎
fit(X, y)從資料學參數,存進結尾底線的屬性所有估計器物件本身不行
transform(X)用已學到的參數轉換資料轉換器轉換後的 X可以
fit_transform(X)先 fit 再 transform 同一份資料轉換器轉換後的 X不行
predict(X)用已學到的參數預測模型預測標籤或數值可以
predict_proba(X)各類別機率,欄位順序依 classes_多數分類器(樣本數, 類別數) 機率可以
score(X, y)先 predict 再算預設指標(分類 accuracy、迴歸 R2)模型一個數字可以,但只在最後用一次

2. fit_transform 為什麼只能給訓練集

fit_transform(X) 的結果和 fit(X).transform(X) 相同,只是寫在一起,有些轉換器還有更省計算的實作。問題不在它本身,而在你把什麼資料交給它。對測試集呼叫 fit_transform,標準化器會改用測試集自己的平均與標準差,等於訓練集和測試集各用一把不同的尺:同樣是消費 65 百元,在訓練集的尺上是 0.955,對測試集 fit_transform 卻會變成 −1.354(測試集 84、65、92 自己的平均是 80.33),連正負號都反了,模型學到的規則就對不上了。上線時一次只來一筆資料,標準差是 0,這種寫法甚至算不出來。

訓練集(7 筆,示意) 52 58 63 7055 61 60 fit_transform學+套用 z:−1.46 −0.345 0.5841.884 −0.902 0.212 0.027 mean_ ≈ 59.86scale_ ≈ 5.38 同一組參數 測試集(3 筆) 84 65 92 transform只套用,不學 z:4.485 0.955 5.971
上排的訓練集經過 fit_transform,學到中間藍色那組 mean_ 與 scale_;下排的測試集只經過 transform,套用的是同一組參數。數字是實驗室二的示意資料,以 scikit-learn 實跑核對;測試集的 84 與 92 離訓練集很遠,z 分數就很大,這正是我們希望模型與下游規則看到的真相。

下面是不用 Pipeline 時的完整手動寫法。每一個會學東西的動作都只拿到 X_tr,測試集只出現在 transform、predict 與最後的評分;註解裡的輸出是 scikit-learn 1.9.1 實際執行的結果。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

X, y = load_breast_cancer(return_X_y=True)              # (569, 30),二元標籤
X_tr, X_te, y_tr, y_te = train_test_split(               # 1. 第一步就切分
    X, y, test_size=0.2, stratify=y, random_state=42)    #    回傳順序固定
print(X_tr.shape, X_te.shape)                            # (455, 30) (114, 30)

scaler = StandardScaler()                                # 轉換器:還沒學任何東西
X_tr_s = scaler.fit_transform(X_tr)                      # 2. fit + transform 只給訓練集
X_te_s = scaler.transform(X_te)                          # 3. 測試集只 transform
print(scaler.mean_[:2].round(2))                         # [14.07 19.25] 來自 455 筆訓練資料

clf = LogisticRegression(max_iter=1000)                  # 模型
clf.fit(X_tr_s, y_tr)                                    # 4. 模型也只看訓練集
y_pred = clf.predict(X_te_s)                             # 5. 預測測試集
print(round(accuracy_score(y_te, y_pred), 3))            # 0.982,最後評分一次
print(round(clf.score(X_te_s, y_te), 3))                 # 0.982,分類器的 score 就是 accuracy

3. 先切分:train_test_split 的參數

train_test_split(X, y) 回傳四個東西,順序固定是 X_train, X_test, y_train, y_test:先是兩份 X,再是兩份 y。變數名稱寫錯順序時程式不會報錯,只是 y_tr 裡裝的其實是測試集的 X,這是程式閱讀題很愛用的陷阱。test_size 和 train_size 都沒給時,測試集預設占 25%;10 筆資料會切成 7 筆訓練、3 筆測試,因為測試集的筆數是無條件進位。

shuffle 預設是 True,切分前會先打亂;random_state 固定打亂的亂數,讓每次執行切出同樣的結果,方便重現與比較,它不影響切分「好不好」。stratify=y 讓訓練集與測試集的類別比例和整體一致,類別不平衡時特別重要;它需要打亂才能運作,shuffle=False 時不能同時指定 stratify。資料有時間順序時則反過來,不能打亂,要依時間先後切,見第 6 節。

回傳順序:先兩份 X,再兩份 y X_train X_test y_train y_test 寫成 X_tr, y_tr, X_te, y_te 時不會報錯,但 y_tr 拿到的是 X_test 100 筆、正類 20 筆,切出 25 筆測試集(示意) stratify=y 其餘 20 筆是負類 每次都是 5 筆正類=20%,和整體一致 不加 stratify rs=0:4 rs=1:7 rs=2:4 rs=3:6 rs=4:6 rs=5:2 正類筆數隨 random_state 浮動,從 2 筆到 7 筆都有(8% 到 28%) random_state 只決定「抽哪幾筆、能不能重現」;比例要靠 stratify
上排是回傳順序。下排用 100 筆、正類 20 筆的示意資料切出 25 筆測試集:加了 stratify 每次都剛好 5 筆正類;不加時,random_state 換成 0 到 5 抽到的正類筆數各不相同(以 scikit-learn 實跑核對)。測試集如果只有 2 筆正類,recall 只能是 0、0.5、1 三種值,評估就很不穩。

4. 資料洩漏從哪裡來

判斷洩漏只要問一個問題:評估用的資料,有沒有參與任何一個會學東西的步驟?「會學東西」不只模型本身,還包括所有從資料算出統計量或做出選擇的動作。下表整理最常見的六種來源,最後一欄是改法。

來源典型寫法為什麼分數會虛高改法
前處理在切分前 fit先 StandardScaler().fit_transform(X)、fillna(df.mean())、TfidfVectorizer().fit(全部文件) 再切平均、補值、詞彙表與 IDF 含測試資料的資訊先切分;或放進 Pipeline
特徵選擇看過全部資料先 SelectKBest(k=10).fit_transform(X, y) 再交叉驗證挑特徵時已經用到驗證折的標籤把選擇器放進 Pipeline
過採樣碰到評估資料先 SMOTE().fit_resample(X, y) 再切分或交叉驗證合成樣本由驗證列內插而來,驗證時等於看見親戚用 imbalanced-learn 的 Pipeline,只在訓練折過採樣
用測試集挑模型或調參換 10 組參數都看測試分數,挑最高的報告測試集變成另一個訓練集,挑中的是「剛好適合這份測試集」的設定用交叉驗證或驗證集挑,測試集只用一次
用到未來的資料時間序列打亂切分、rolling(center=True)、shift(-1)訓練時看過評估時間點之後的資訊TimeSeriesSplit、只往過去看的特徵
特徵藏著答案用「是否已退款」預測「是否詐騙」特徵在預測當下根本還不存在,是結果的一部分只保留預測當下拿得到的欄位
特徵選擇(accuracy) 過採樣(F1) 0.83 0.58 亂猜 0.5 先挑再驗證 放進 Pipeline 0.975 0.067 先過採樣 放進 Pipeline 兩組都是純亂數資料(示意),任何「學得很好」的分數都來自洩漏
左邊用 60 筆、2000 個亂數特徵,右邊用 300 筆、20 個亂數特徵且正類約 9%,特徵和標籤都毫無關係(以 scikit-learn 1.9.1 與 imbalanced-learn 0.14 實跑)。紅色長條是先對全部資料做選擇或過採樣再交叉驗證,藍色是把同一個步驟放進 Pipeline。紅色看起來像好模型,其實只是驗證資料早被看過。

遇到一段陌生的程式,可以照下面四步檢查,也可以搭配下一張流程圖:

  1. 圈出所有會學東西的動作:fit、fit_transform、fit_resample、fillna(用統計量),以及「看分數挑參數或挑模型」。
  2. 對每一個動作問:它拿到的資料是哪一份?裡面有沒有之後要評估的列(測試集或交叉驗證的驗證折)?
  3. 資料有時間順序時,再問:訓練用的資料是不是都早於評估的資料?特徵有沒有偷看未來?
  4. 最後檢查每個特徵在「做預測的那一刻」拿不拿得到;拿不到的就是目標洩漏。
這個動作會從資料學東西嗎? 不會 transform、predict 會 它看到的資料含評估資料嗎? 含 洩漏:移到切分後或放進 Pipeline 不含 資料有時間順序嗎? 有 訓練都早於評估?否=時間洩漏 沒有,或已依時間切 特徵在預測當下拿得到嗎? 拿不到 目標洩漏 拿得到 沒有洩漏,分數可信 「學東西」包括:fit、 fit_transform、fit_resample、 用統計量補值、看分數挑選
由上往下問四個問題,任何一關走到右邊的紅框或黃框就是洩漏。第一關最常被跳過:transform 和 predict 本身不學東西,所以「對測試集 transform」完全正常,真正要追查的是每一個 fit 看過什麼。

5. Pipeline 與 cross_val_score 怎麼自動避免

手動寫法要靠人記得「每個轉換器只在訓練集 fit」,步驟一多就容易漏。Pipeline 把多個步驟串成一個物件,除了最後一步,前面都必須是轉換器。呼叫 pipe.fit(X_tr, y_tr) 時,每個轉換器依序 fit_transform,最後的模型 fit;呼叫 pipe.predict(X_te) 時,轉換器只做 transform,模型做 predict,不會重新學。make_pipeline 會自動用小寫類別名稱當步驟名,例如 standardscaler、logisticregression。

pipe.fit(X_tr, y_tr):每一步都學 X_tr SimpleImputerfit_transform StandardScalerfit_transform LogisticRegressionfit statistics_mean_、scale_coef_ pipe.predict(X_te):只套用 X_te SimpleImputertransform StandardScalertransform LogisticRegressionpredict → y_pred
上排黃色是 fit 階段,每一站都從訓練集學出自己的參數;藍色虛線表示這些參數往下傳給 predict 階段使用。下排白色的每一站都只套用,不學新東西,所以測試集從頭到尾沒有被 fit 過。

Pipeline 真正的價值出現在交叉驗證。K 折交叉驗證(K-fold cross-validation)把訓練集切成 K 份,每次用 K−1 份訓練、1 份驗證。cross_val_score(pipe, X_tr, y_tr, cv=5) 每一折都會複製一份全新的 Pipeline,只在該折的訓練部分 fit 標準化器與模型,再拿驗證那一份評分,回傳 5 個分數。如果你在迴圈外先把整個訓練集標準化,再丟一個單純的模型進 cross_val_score,每一折的驗證資料早就參與過平均與標準差的計算。cv 給整數且模型是分類器時,預設使用 StratifiedKFold,保持每折的類別比例,而且預設不打亂。

cross_val_score(pipe, X_tr, y_tr, cv=5) 第 1 折第 2 折第 3 折第 4 折第 5 折 每一折都重來 複製一份全新 Pipeline 藍色 4 份:fit scaler 與模型 橘色 1 份:只 transform 再評分 回傳 5 個分數 若在迴圈外先把整個訓練集標準化,每一折的橘色驗證份早就被看過
每一列是一折,橘色是這一折的驗證資料,藍色是訓練資料。把前處理放在 Pipeline 裡,標準化器會跟著模型在每一折重新 fit,只看那一折的藍色部分;這就是 cross_val_score 能自動防洩漏的原因,前提是你交給它的是整條 Pipeline。

挑超參數時把同一條 Pipeline 交給 GridSearchCV,參數名稱寫成「步驟名__參數名」。它對每組參數各做一次 K 折,總 fit 次數是「組合數 × K」,refit=True(預設)時再用最佳組合對整個訓練集 fit 一次。best_score_ 是交叉驗證的平均分數,不是測試分數;測試集要在全部定案後才評分一次。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)

pipe = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
print(pipe.steps[0][0], pipe.steps[1][0])         # standardscaler logisticregression

scores = cross_val_score(pipe, X_tr, y_tr, cv=5)  # 每一折重新 fit scaler 與模型
print(scores.shape, round(scores.mean(), 3))      # (5,) 0.98

grid = {"logisticregression__C": [0.1, 1, 10]}    # 步驟名__參數名
gs = GridSearchCV(pipe, grid, cv=5)               # 3 組 x 5 折 = 15 次 fit,再 refit 1 次
gs.fit(X_tr, y_tr)                                # 只用訓練集調參
print(gs.best_params_, round(gs.best_score_, 3))  # {'logisticregression__C': 0.1} 0.98
print(round(gs.score(X_te, y_te), 3))             # 0.974,測試集只在最後用一次

過採樣是例外:scikit-learn 本身的 Pipeline 不接受 SMOTE 這類會改變樣本數的步驟,要改用 imbalanced-learn 套件的 imblearn.pipeline.Pipeline(或它的 make_pipeline),它只在 fit 時過採樣,predict 與評分時不會碰驗證資料。

6. 時間序列:不能打亂

銷售量、感測器讀數、網站流量這類資料有先後順序。train_test_split 預設會打亂,切出來的訓練集可能包含 12 月的資料、測試集卻是 6 月,模型等於用未來預測過去。正確做法是依時間切:最簡單的是 shuffle=False 讓最後一段當測試集;交叉驗證則用 TimeSeriesSplit,每一折的驗證段都在訓練段之後。特徵工程也一樣,rolling(7, center=True) 的視窗會包含後面三天,shift(-1) 會拿到明天的值,都屬於偷看未來。

打亂切分:用未來預測過去 1 月 2 月 3 月 4 月 5 月 6 月 7 月 8 月 9 月 10 月 11 月 12 月 訓練時看過 11、12 月,卻要「預測」6 月 TimeSeriesSplit:驗證永遠在訓練之後 第 1 折 第 2 折 第 3 折 時間 藍=訓練橘=驗證
上排是一般 train_test_split 打亂後的結果(月份分配為示意),橘色的測試月份夾在訓練月份中間。下排是 TimeSeriesSplit 的樣子:每一折的訓練段只往前延伸,驗證段永遠在它後面,評估的情境和真正上線時一樣,只能用過去預測未來。

容易寫錯或考錯的地方

回傳順序:題目把 train_test_split 的左邊寫成 X_tr, y_tr, X_te, y_te,再問某個變數的 shape。程式不會報錯,答案要照「X_train, X_test, y_train, y_test」的真實順序推。

「分數比較高,所以比較好」:洩漏題的干擾選項幾乎都這樣寫。洩漏版本的分數本來就比較高,高分正是問題所在;正確選項通常描述的是流程,例如「每一折只用該折訓練資料 fit」。

「它不是模型,所以不會洩漏」:SelectKBest、SimpleImputer、TfidfVectorizer、SMOTE 都會從資料學東西。判斷依據是有沒有 fit,而不是它叫不叫模型。

「折數加大就沒事」:cv=5 改成 cv=10 不會修好洩漏,只要前處理在交叉驗證之外看過全部資料,每一折都一樣被污染。

對測試集 fit_transform:看起來兩邊都「標準化過」,其實是兩把不同的尺,屬於錯誤寫法;正確選項是測試集只呼叫 transform。測試集標準化後的平均不一定是 0,這是正常現象。

best_score_ 不是測試分數:它是交叉驗證的平均;題目若問「最後要報告哪個數字代表新資料表現」,答案是定案後在測試集算一次的分數。

stratify 與 random_state:前者讓類別比例一致,後者讓結果可以重現,兩者不能互相取代。時間序列兩個都不適用,要改依時間切分。

版本:本頁程式以 scikit-learn 1.9.1(並以 1.8 核對)與 imbalanced-learn 0.14 實際執行;fit、transform、predict、Pipeline、cross_val_score 這套介面在 1.x 版之間沒有改變。

✅ 自我檢測

以下 6 題都是原創的程式閱讀題,輸出都以 scikit-learn 1.9.1 實際執行核對。選完會立即顯示對錯與解析,全部作答後會出現總分。目前得分:0 / 6

🎯 重點整理

  1. fit 學參數(存在結尾底線的屬性),transform 套用,predict 預測;fit_transform 等於 fit 再 transform,只用在訓練集。
  2. 會學東西的不只模型:標準化、補值、編碼、TF-IDF、特徵選擇、過採樣,以及「看分數挑選」都算,全部只能看訓練資料。
  3. 先切分再做任何會學的步驟;train_test_split 回傳 X_train, X_test, y_train, y_test,測試集預設 25%。
  4. stratify=y 保持類別比例,random_state 讓結果可重現,兩者作用不同;時間序列不能打亂,改用 TimeSeriesSplit。
  5. 把前處理和模型綁成 Pipeline,交給 cross_val_score 或 GridSearchCV,每一折都只在該折訓練部分重新 fit;SMOTE 要用 imbalanced-learn 的 Pipeline。
  6. 測試集只在最後評分一次;best_score_ 是交叉驗證平均,不是測試分數。洩漏版本分數比較高,高分本身就是警訊。