🗺️ AI 學習與考證地圖
中級科目三程式實戰 · 前處理與資料洩漏

尺在訓練集刻一次:
fit_transform 給訓練、transform 給測試

同一題標準化,四種寫法。實跑結果:沒有漂移時四方同分 0.7767——分數完全看不出誰作弊;等測試集漂移 +2.5(上線常態),誠實的 B 掉到 0.5000(模型把 300 筆全判 1=丟銅板),兩把尺的 C 卻假報 0.7767——那成績上線兌現不了。A 更陰:合併刻尺讓模型跟著考卷變——訓練集一個字沒動,換一批測試集,coef_ 最大差 0.2247、f3 係數從 +0.07 翻成 -0.15。正解只有一段:尺在訓練集刻一次,兩邊用同一把

閱讀模式

00題目

下列哪一段標準化程式能避免把測試集統計量洩漏到訓練流程

# 已有 X_train 與 X_test
from sklearn.preprocessing import StandardScaler   # 拿出標準化工具(每欄減平均、除以標準差)

# A.
scaler = StandardScaler().fit(pd.concat([X_train, X_test]))   # 訓練+測試黏成一包,一起算 mean/std
X_train_s = scaler.transform(X_train); X_test_s = scaler.transform(X_test)   # 用這把「混合尺」量兩邊

# B.
scaler = StandardScaler()                             # 先造一把空白的尺
X_train_s = scaler.fit_transform(X_train)            # 在訓練集上刻尺+量
X_test_s = scaler.transform(X_test)                  # 測試集只量,用同一把尺

# C.
X_train_s = StandardScaler().fit_transform(X_train)   # 訓練集刻自己的尺、量自己
X_test_s = StandardScaler().fit_transform(X_test)    # 測試集另刻一把尺、量自己

# D.
scaler = StandardScaler().fit(X_test)                 # 用測試集刻尺
X_train_s = scaler.transform(X_train); X_test_s = scaler.transform(X_test)   # 用這把「測試尺」量兩邊

先說:磅秤是在工廠校準的,不是在你家

合格的磅秤出廠前,用標準砝碼校準好刻度;到你家之後,它只做一件事——照著已刻好的刻度秤你。標準化的尺(每欄的平均與標準差)也一樣:在訓練集上刻一次(fit),之後訓練集、測試集、上線資料通通用同一把尺量(transform)。

四個選項就是四種校秤方式:B 工廠校準、全世界同一把尺(正解);A 把你家的東西也搬進工廠一起校——秤的刻度摻了「未來要秤的東西」;D 乾脆只用你家的東西校;C 最妙——每家自己校自己的秤,於是你家的「1 公斤」和工廠的「1 公斤」不是同一個重量,東西一過門,重量就變了。

三個先立好的事實: StandardScaler 的「尺」= mean_scale_fit 給誰,尺就是誰刻的 題目問的是「洩漏到訓練流程」——只要測試統計量影響了 X_train_s(模型的教材),就是洩漏:A 與 D 都中。 兩邊必須同一把尺——尺不同,同一個原始值會落在不同座標:C 的病根。

先點開看:StandardScalerfit 該餵誰同一把尺

不熟 AI 專有名詞?你需要先認識下列名詞

點擊後出現漸進式說明:白話說明 → 說清楚一點 → 常見錯誤與考點。

尺與刻度
StandardScalerz 分數mean_ 與 scale_同一把尺
三個動詞
fit:刻尺transform:量fit_transformfit 該餵誰
洩漏的去向
資料洩漏洩進訓練流程洩進評估樂觀偏誤
上線的現實
資料漂移上線單筆參數凍結Pipeline 防呆版

不熟 Python?你需要先認識下列名詞

點擊後出現漸進式說明

把工具拿進來
importfrom
資料的動作
pd.concat 黏資料StandardScaler().fit() 鏈式寫法
名字與呼叫
= 指派變數 scaler( ) 呼叫括號_s 命名慣例

01逐行拆解:題幹一行+正解 B 的三行

題幹只給了一行 import,勝負全在四個選項的寫法。先把正解 B 一行一行走完,其他三個選項在 03~05 節逐一開庭。

題幹拿出標準化工具
from sklearn.preprocessing import StandardScaler   # 從前處理抽屜拿出「刻尺器」

StandardScaler 把每個特徵欄調成「平均 0、標準差 1」:z = (x − mean_) ÷ scale_。它是系列的老面孔——第 7 頁(分群前的 StandardScaler)講為什麼要縮放、第 14 頁講fit/predict 誰學誰用,本頁講尺該在哪裡刻。注意題目說「已有 X_train 與 X_test」——切分已經完成,現在的問題純粹是:刻尺的資料,該餵誰?

相關名詞:StandardScalerz 分數from

B 第 1 行造一把空白的尺
scaler = StandardScaler()   # 尺造好了,還沒刻度——mean_ 與 scale_ 都不存在

先把尺存進變數 scaler——這個動作是 B 能贏的第一步:尺有了名字,才能「刻一次、用兩次」。對照選項 C:它從頭到尾沒把尺存起來,兩行各自 StandardScaler() 造了兩把匿名的尺,用完即丟——兩把尺,就是兩套座標

相關名詞:變數 scaler= 指派( ) 呼叫括號

B 第 2 行在訓練集上「刻尺+量」——只這一次
X_train_s = scaler.fit_transform(X_train)   # 刻尺(學 mean_/scale_)+馬上量訓練集

fit_transform = 先 fit(把訓練 700 筆的每欄平均與標準差刻上尺)再 transform(用剛刻好的尺量訓練集自己)。本站實跑刻出來的尺(f0 欄):mean_ = 0.5133、scale_ = 1.2672——注意,這兩個數只來自訓練集,X_test 連一根汗毛都沒參與。整場流程裡「fit」這個字只出現這一次、只餵訓練集——這正是題目要的「不洩漏」。

相關名詞:fit_transformmean_ 與 scale_fit 該餵誰

B 第 3 行測試集只「量」,用同一把尺
X_test_s = scaler.transform(X_test)   # 不重刻——拿訓練刻好的尺量測試集

同一個 scaler、只呼叫 transform——測試集被訓練刻的尺量:(x − 0.5133) ÷ 1.2672(f0 欄)。於是兩件好事同時成立: 測試統計量從未流進任何「學」的動作(不洩漏); 訓練與測試活在同一套座標系——模型在哪個空間學,就在哪個空間考。上線時這把尺跟著模型一起凍結交付,一筆一筆來的新資料照量不誤——第 14 頁 predict 的機制在這裡完整重演。

一句話記住本題:尺在訓練集刻一次——fit_transform 給訓練、transform 給測試。寫成兩個 fit_transform(選項 C)、或讓 X_test 進到任何 fit 的括號裡(選項 A、D),都是丟分的寫法。

相關名詞:transform:量同一把尺參數凍結

02三把尺對照器:fit 給誰,刻度就是誰的

四個選項其實只差一件事:fit 的括號裡放了誰。本站實跑(1000 筆 × 5 特徵、70/30 切分),把三把尺的刻度全部翻出來:

互動實驗室:三把尺對照器訓練尺/合併尺/測試尺——刻度差在哪
本站實跑(f0 欄的 mean_):訓練尺 0.5133、合併尺 0.5051、測試尺 0.4860——平時三把尺長得像,你感覺不到差別;等測試集漂移 +2.5,測試尺的 mean_ 跳到 2.9860、合併尺被拉到 1.2551——只有訓練尺一動也不動。尺穩,量出來的座標才穩;尺跟著資料漂,模型的世界就跟著晃。

相關名詞:mean_ 與 scale_fit 該餵誰資料漂移

03四選項計分板:分數看不出誰作弊——直到漂移來敲門

四段程式各自配一顆 LogisticRegression(max_iter=1000) 訓練、評分。兩個場景(全部實跑):

互動實驗室:四選項計分板無漂移 vs 漂移 +2.5——誰的分數是真的
本站實跑計分:場景一:A、B、C、D 全部 0.7767——四方同分,乾淨與骯髒的流程考出一樣的分數,這正是洩漏可怕的地方:它平時不發作。場景二(測試 f0 整批 +2.5,模擬感測器漂移/物價上漲這類上線常態):B 誠實掉到 0.5000——模型把 300 筆全判成 1(正類比例 0.5,等於丟銅板),這就是你交付的凍結系統上線會拿到的真實成績;A 0.5000、D 0.5000(同一把尺量兩邊,漂移照樣現形);C 卻報 0.7767——它的第二把尺把測試集自己標準化回原點,漂移被悄悄抹掉,差距 +0.2767 全是假象。
為什麼 C 的 0.7767 是假的:那個分數靠的是「整批測試集互相取暖」——先看完全批 300 筆、算出批內平均再自我修正。上線你交付的是 B 那套凍結參數,資料一筆一筆來,沒有「批」可取暖(下一節開庭)——0.7767 這張支票,上線兌現不了,真實成績就是 0.5 那個。這是「不報錯的錯」家族第五案(第 9、10、12、14 頁之後)。

相關名詞:樂觀偏誤資料漂移洩進評估

04A 的罪:模型跟著考卷變

題目問的是洩漏到「訓練流程」。A 的 pd.concat 讓合併統計量進了 X_train_s——模型的教材被測試集污染。抓現行的方法:訓練集一個字不動,只換測試批次,看模型變不變。

互動實驗室:換考卷實驗同一份訓練集+兩批測試集——誰的模型變了
A:合併刻尺(洩漏)
B:訓練刻尺(乾淨)
本站實跑判決:換一批測試集之後——A 的 coef_ 最大差 0.2247,其中 f3 的係數從 +0.0742 翻成 -0.1505(連正負號都翻面)、合併尺的 f0 mean_ 從 0.5051 被拉到 1.2551;B 呢?兩批之下 coef_ 以 np.array_equal 比對完全相同、對同一筆資料的機率永遠是 0.5849。「你的模型長什麼樣,居然由測試集決定」——這就是「洩漏到訓練流程」六個字的具體樣貌。D 連遮羞布都不要(整把尺都是測試集的),罪名同款、加重量刑。

相關名詞:洩進訓練流程pd.concat 合併 fitfit(X_test)

05C 的罪:兩把尺——同值異座標,上線單筆全零

C 看起來最無辜:測試統計量確實沒碰到訓練側。但它犯了另一條罪——訓練與測試各用一把尺。開庭,兩件展品(全部實跑):

互動實驗室:兩把尺展品同一個 1.00 的兩個座標;上線單筆的下場
判決:同一個原始值 1.00——訓練尺量出 z = 0.384(略高於平均),漂移後的測試自尺量出 z = -1.6397(遠低於平均)——同一個數字,兩個世界;模型在訓練座標系學的一切,到測試座標系全部對不上號。而上線資料一筆一筆來:單筆自己 fit_transform → 平均=自己 → 五個特徵全變 0 → 人人 σ(0.1027) = 0.5256(這筆的正解其實是 0.7768)——第 14 頁「重新 fit 的世界」原案重演。C 的病名:評估時靠不住、部署時做不到

相關名詞:兩次 fit_transform同一把尺上線單筆

06誰洩漏了什麼:一張表收工,加一個防呆版

把四個選項的罪狀排成一張表——考場上掃一眼 fit( 的括號就能判案:

選項fit 看到誰洩漏去向兩邊同尺?上線單筆可用?
A 合併刻尺訓練+測試訓練流程+評估同尺(混合尺)尺含歷史測試集,換批就變
B 訓練刻尺只有訓練集同尺(訓練尺)可以——尺凍結隨模型交付
C 各刻各的各自(訓練側乾淨)評估(批內取暖)兩把尺、兩套座標不行——單筆全零
D 測試刻尺只有測試集訓練流程+評估(最赤裸)同尺(測試尺)不行——上線沒有「測試集」

防呆版:B 的兩行手寫,正是 Pipeline([('scaler', StandardScaler()), ('model', LogisticRegression())]) 內部自動做的事——本站實跑:Pipeline 的分數 0.7767、300 筆機率與 B 逐位元相同(np.array_equal True)。B 是 Pipeline 的手寫展開;Pipeline 是 B 的防呆包裝——機制拆解在第 14 頁(fit 學、predict 用)、配交叉驗證的完整版在第 1 頁:CV 裡每一折都要「重刻訓練尺」,把 pipe 整顆丟進 cross_val_score 就自動做對。

洩漏家族點名(系列第四案):第 1 頁洩的是全資料統計量(先選特徵再切折,純亂數假造 AUC 0.929)、第 3 頁洩的是先 SMOTE 再切分、第 10 頁洩的是未來資料(KFold 打散時間)、本頁洩的是測試集統計量——四案同一個病根:「學」的動作看到了不該看的資料;同一帖藥方:Pipeline + 只在訓練側 fit。

相關名詞:Pipeline 防呆版每折重刻尺資料洩漏

07四個選項收工

Ascaler = StandardScaler().fit(pd.concat([X_train, X_test])),再各自 transform合併刻尺=洩漏

尺的刻度由訓練+測試 1000 筆一起算——測試統計量經由 X_train_s 流進模型教材,正是題目點名的「洩漏到訓練流程」。實跑抓現行:訓練集一字不動、只換一批(漂移)測試集,A 的 coef_ 最大差 0.2247、f3 係數從 +0.0742 翻成 -0.1505——模型跟著考卷變。順帶一提:它的分數平時跟 B 一模一樣(0.7767)——分數看不出這種弊,流程才看得出。

Bscaler = StandardScaler();X_train_s = scaler.fit_transform(X_train);X_test_s = scaler.transform(X_test)正確

尺在訓練集刻一次、兩邊用同一把:fit 只餵訓練 700 筆(f0 的 mean_ 0.5133、scale_ 1.2672),測試集只被 transform。三重驗收全過:測試統計量從未進任何「學」的動作(不洩漏);訓練測試同座標系(漂移來了誠實現形:0.5000,全判 1——這才是上線的真話);尺凍結可交付,單筆照量。與 Pipeline 逐位元同分——它就是 Pipeline 的手寫展開

CX_train_s 與 X_test_s 各自 StandardScaler().fit_transform()兩把尺=經典新手雷

訓練側確實乾淨,但訓練與測試各用一把尺:同一個 1.00,訓練尺說 z=0.384、漂移測試自尺說 z=-1.6397——座標系裂開。更毒的是它的分數最好看:漂移場景 B 誠實 0.5000、C 假報 0.7767——兩把尺把漂移悄悄抹掉,而上線單筆 fit_transform 全零、人人 0.5256,那成績根本兌現不了。分數越好看、流程越骯髒的活教材

Dscaler = StandardScaler().fit(X_test),再各自 transform整把尺都是測試集的

最赤裸的一款:刻度百分之百來自 300 筆測試集——訓練特徵、模型係數全部踩在測試統計量上,訓練流程與評估一起淪陷。上線更尷尬:正式環境沒有「測試集」這種東西可以刻尺,這段程式根本無法部署。考場判法:X_test 出現在 fit 的括號裡,直接出局——A 和 D 都是這一刀。

回到題目:現在再作答一次

再看一次四段程式。這次你手上有判案口訣了:掃一眼 fit( 的括號——X_test 在裡面就出局;再數尺的把數——兩把也出局

scaler = StandardScaler()                    # 正解 B:一把尺
X_train_s = scaler.fit_transform(X_train)   # 刻尺只在訓練集——f0 尺:mean_ 0.5133
X_test_s = scaler.transform(X_test)          # 同一把尺量測試——漂移來了誠實現形

08自我檢測

八題,全部都是本題的延伸。答錯會直接告訴你錯在哪。

09重點整理

  1. 題幹一行 import 拿出 StandardScaler;勝負在四個選項:差別只有一件事——fit 的括號裡放了誰、尺共幾把
  2. 正確答案 Bscaler.fit_transform(X_train)scaler.transform(X_test)——尺在訓練集刻一次,兩邊用同一把
  3. 判案口訣:① fit( 的括號裡出現 X_test → 出局(A 的 concat、D 的直接 fit);② 出現兩次 fit_transform → 兩把尺,出局(C)。
  4. 尺=mean_ 與 scale_(實跑):訓練尺 f0 = 0.5133/1.2672;合併尺 0.5051、測試尺 0.4860——漂移後測試尺跳到 2.9860、合併尺被拉到 1.2551,只有訓練尺不動
  5. 分數看不出誰作弊(實跑):無漂移場景四個選項同分 0.7767——洩漏平時不發作,所以要用流程判案、不能用分數判案。
  6. 漂移場景(實跑):測試 f0 整批 +2.5 → B 誠實 0.5000(300 筆全判 1=丟銅板,這是上線真話);A、D 同為 0.5;C 假報 0.7767——兩把尺把漂移悄悄抹掉,+0.2767 全是假象。
  7. A 的罪(實跑):訓練集一字不動、換一批測試集——coef_ 最大差 0.2247、f3 係數 +0.0742 翻成 -0.1505——模型跟著考卷變=「洩漏到訓練流程」的具體樣貌;B 的 coef_ 兩批之下 array_equal 完全相同。
  8. C 的罪(實跑):同一個 1.00——訓練尺 z=0.384、漂移測試自尺 z=-1.6397(同值異座標);上線單筆 fit_transform → 全零 → 人人 σ(0.1027)=0.5256(正解 0.7768)——評估靠不住、部署做不到
  9. D 的罪:整把尺由 300 筆測試集刻——訓練與評估一起淪陷,而且上線沒有「測試集」可刻尺,根本無法部署。
  10. B ≡ Pipeline(實跑):Pipeline([('scaler',…),('model',…)]) 與 B 逐位元同分(0.7767、機率 array_equal True)——B 是手寫展開、Pipeline 是防呆包裝;機制見第 14 頁、配 CV 的完整版見第 1 頁(每折重刻訓練尺)。
  11. 洩漏家族第四案:第 1 頁全資料統計量、第 3 頁先 SMOTE 再切分、第 10 頁未來資料、本頁測試統計量——同病根(「學」看到不該看的)、同藥方(Pipeline+只在訓練側 fit)。
  12. 考場口訣尺在訓練集刻一次;fit_transform 給訓練、transform 給測試;X_test 進了 fit 就洩漏
完整程式碼