StandardScalerで未知データへの性能を評価するなら、先に訓練用とテスト用へ分け、平均と標準偏差は訓練データだけで求めます。 テストデータは、訓練時に作った同じ変換器のtransformへ渡します。テスト側でもう一度fitする方法は、同じ基準での変換になりません。

対象は、Pythonで表を読み込める段階から、scikit-learnの予測モデルへ進む人です。今回は分類精度の比較ではなく、どの行から変換の基準を作ったかを六行で検算します。大きく離れた値を置いた架空教材であり、実際の業務データの分布や予測成績を表すものではありません。

公式資料確認日:2026年10月21日。StandardScaler、データリークを含む注意点、Pipeline、交差検証の解説を確認しました。掲載コードの実行環境はPython 3.12.14、NumPy 2.5.4、scikit-learn 1.9.1です。教材の数値は編集部が実行して確かめた結果です。

六行を訓練四行とテスト二行に分け、平均4と標準偏差約2.236を訓練側だけで求める。テスト101と103は同じ変換器で変換し、基準を作り直さない。
編集部作成。テストを変換する矢印と、平均を学習する矢印を分けて示しています。

StandardScalerの順番を、六行の平均と変換値で確かめる

fitは変換の基準を覚え、transformはその基準を使う

標準化は、列の値から平均を引き、標準偏差で割る変換です。StandardScalerでは、どのデータで平均と標準偏差を求めたかが重要になります。同じ数値を入力しても、覚えた基準が違えば、変換後の値は変わります。

fitは、その基準を学習する操作です。transformは、学習済みの基準を使う操作です。fit_transformは、渡したデータで基準を学習してから変換します。この三つを、単に長さが違う書き方だと捉えると、テスト側でも基準を学習し直してしまいます。

未知のデータを評価するために残したテストは、平均を計算する段階でも混ぜないようにします。「正解ラベルを渡していないから問題ない」とは限りません。特徴量の分布から求める前処理でも、評価用の行を先に見ることになります。

例えば、ある期間のデータでモデルを作り、その後に届くデータへ適用する場面を考えます。将来の値を見てから過去の平均を調整するのは、実際の予測時点ではできない作業です。評価でも、使える情報の範囲を揃える必要があります。

ただし、これだけで予測の成績がどの程度変わるかは分かりません。データ、モデル、他の前処理によって影響は変わります。本稿は「順番を間違えると精度が何ポイント上がる」といった数値を示しません。まず前処理の基準を作った行を特定します。

用語が難しい場合は、三つを「基準を作る」「基準を使う」「作ってから使う」とメモしてからコードを読みましょう。どの変数が訓練用で、どれがテスト用かを、呼び出しの横に一つずつ書くだけでも確認しやすくなります。

訓練四行から作る基準は、平均4・分散5になる

架空の一列データとして、1、3、5、7、101、103を用意します。最初の四行を訓練用、後ろの二行をテスト用に固定します。数字を離したのは、混ぜた場合の平均の違いを見やすくするためです。この六行でモデルの汎化性能は評価しません。

一列でも、入力は二次元の表として作ります。形は六行一列です。shuffle=Falseは教材の分割位置を固定するための指定で、実務でどの分割方法を選ぶかを決めるものではありません。時間やグループの制約がある場合は、後述の確認が必要です。

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

X = np.array([[1.], [3.], [5.], [7.], [101.], [103.]])
X_train, X_test = train_test_split(
    X, test_size=2, shuffle=False
)

scaler = StandardScaler()
Z_train = scaler.fit_transform(X_train)
Z_test = scaler.transform(X_test)

np.testing.assert_allclose(scaler.mean_, [4.])
np.testing.assert_allclose(scaler.var_, [5.])
np.testing.assert_allclose(scaler.scale_, [np.sqrt(5.)])
assert scaler.n_samples_seen_ == 4
print(np.round(Z_test.ravel(), 3).tolist())

最後の出力は[43.38, 44.274]です。テストの値が大きいことは、ここではエラーではありません。訓練側の平均四から大きく離れているので、同じ基準で変換すると大きな値になります。テスト側の平均をゼロへ合わせ直す必要はありません。

平均は、1、3、5、7の合計十六を四で割った四です。平均との差はマイナス三、マイナス一、一、三で、二乗した値の合計が二十です。StandardScalerがこの例で使う分散は、二十を四で割った五になり、標準偏差は五の平方根になります。

101を変換すると、101から四を引いた97を、約2.236で割ります。結果は約43.380です。103も同じ基準なので、99を約2.236で割った約44.274になります。元の二行を別々の基準へ動かしていないことを確認できます。

訓練側の変換値は、約マイナス1.342、マイナス0.447、0.447、1.342です。この値とテスト側の値を見て、二つの集合をそれぞれ平均ゼロにする処理ではないと説明できることが、この練習の確認点です。

全件をfitしてから分割すると、テストが平均へ混ざる

次に、同じ六行すべてから平均を求めます。合計は二百二十、行数は六なので、平均は約36.667です。訓練四行だけで求めた四とは違います。正解ラベルを使わなくても、テスト側に置いた101と103が基準へ影響しています。

以下は比較のための誤った前処理例です。評価用の手順として採用するコードではありません。fitへ渡した変数が全件のXであることに注目してください。前の例と同じStandardScalerでも、学習した行の範囲が違います。

all_rows_scaler = StandardScaler().fit(X)
print(round(float(all_rows_scaler.mean_[0]), 3))
print(int(all_rows_scaler.n_samples_seen_))
# 36.667
# 6

この比較では、何点の予測が出るかを見なくても、テスト用の二行が基準へ混ざったと分かります。学習した行数が六、平均が約36.667だからです。評価の数字を見てから原因を推測する前に、前処理そのものを点検できます。

実際のノートブックでは、途中に標準化済みの変数があると、後から分割しているように見えることがあります。X_scaledのような名前だけでは判断せず、その変数を作った場所まで戻ります。分割前の全件が、どこかのfitへ渡されていないかを追いましょう。

同じ注意は、検証用のデータにも当てはまります。モデルを選ぶための検証部分から平均を求め、その基準で候補を評価すると、訓練だけで準備した状態との条件が違います。交差検証の各分割でも、学習部分の範囲を守る必要があります。

最終的に採用するモデルを、別に保管したテストを残して訓練・検証データへ再学習させる設計はあり得ます。その場合は、モデル選択中の評価と、採用後の再学習を区別して記録してください。段階を分けずに「全件fitでもよい」と一般化しないようにします。

テスト側でfitし直すと、数値の意味が変わる

もう一つの誤りは、テストにもfit_transformを使うことです。101と103だけから基準を作ると、平均は102、標準偏差は一です。変換結果はマイナス一と一になり、訓練の平均四を使った約43.380と約44.274とは異なります。

test_only_scaler = StandardScaler()
wrong_test = test_only_scaler.fit_transform(X_test)
print(test_only_scaler.mean_.tolist())
print(wrong_test.ravel().tolist())
# [102.0]
# [-1.0, 1.0]

小さく整った数値になっても、学習したモデルへ同じ意味の入力を渡せているとは言えません。訓練側の一が何を表すかと、テスト側の一が何を表すかが変わるためです。数値の見た目を揃えることより、同じ変換基準を使うことが大切です。

既存のscalerへfit(X_test)を呼ぶ場合は、さらに注意が必要です。同じ変数名でも、覚えた平均はテスト側のものへ更新されます。その後に新しいデータを変換すると、訓練時とは違う基準を使うことになります。

比較用の例では変換器を別々に作りました。実際の処理でも、途中の実験と採用する変換器を混同しないよう、検証用の名前を分ける方法があります。ただし、名前を分けるだけで正しい順番になるわけではないので、呼び出しへ渡す行も確認します。

もしノートブックで誤って上書きしたなら、変換済みの値へつぎ足しで合わせるより、元の訓練データから採用する変換器とモデルを作り直します。どのセルを再実行したかを記録し、古いモデルと新しい基準を組み合わせないようにしてください。

同じ六行でも、fitへ渡す範囲で基準が変わる
方法平均を作る行この教材での確認
分割後、訓練だけをfit1・3・5・7平均4、学習4行。テストは同じ変換器を使う
全件をfitしてから分割六行すべて平均約36.667、学習6行。テストの値が混ざる
テストだけを別にfit101・103平均102。テスト値は-1と1になり、基準が違う
訓練後のscalerをテストで再fit最後のfitで渡した行同じ変数名でも学習済みの基準が上書きされる

mean_と学習件数は、入力の行・列と一緒に照合する

StandardScalerの学習後には、平均や分散などの属性を確認できます。今回の欠損も重みもない一列の教材なら、mean_が四、n_samples_seen_が四になっているかが手掛かりです。数値だけでなく、どの列と行から出た値かを書き添えます。

列が増えた場合は、平均も列ごとに並びます。注文数と金額の二列なら、どちらの平均が何番目にあるかを確認します。NumPy配列は列名を持たないため、同じ列数でも順序が逆なら意味が変わります。列の定義と順番は、入力仕様として残しましょう。

CSVを読み込む段階でIDの先頭ゼロが消えたり、金額が文字列のままだったりすると、標準化以前の問題になります。CSVの先頭ゼロと文字コードの確認や、pandasの数値変換を検算する方法を使い、変換前の列も点検してください。

欠損や重みを含む処理では、学習件数の属性が単純な行数の整数にならない場合があります。今回の== 4を、そのままどの表にも当てはめないでください。確認用の条件は、入力の仕様と、採用した前処理に合わせて作ります。

テストの変換値が大きく出たら、即座に平均を作り直さず、単位の違い、列の取り違え、データ分布の変化などを調べます。この教材では意図して値を離しましたが、実データでは金額の円と千円が混ざるだけでも大きな差が出ます。

最後に、標準化の前後で行数とIDが保たれているかも見ます。前処理が正しい基準でも、特徴量と目的変数の対応がずれていれば、別の問題が残ります。pandasの結合で行数とキーを確認する手順のように、表の対応を別途検算しましょう。

手計算と合わないときは、標準偏差の定義も照合できます。この教材の訓練四行では、平均との差の二乗和が二十です。四で割った分散五を使うと標準偏差は約2.236ですが、三で割る計算なら約2.582になります。入力の四行が同じでも、採用した定義が違えば値は揃いません。

StandardScalerの標準偏差は、この例ではNumPyのddof=0に相当します。別の集計関数の既定を使って照合する場合は、分母が同じかを確認してください。違いを見つけたときにテスト側で平均を作り直しても、定義のずれを解消したことにはなりません。

逆変換も、小さな教材の検算に使えます。今回の同じscalerで変換したテストを、そのscalerのinverse_transformへ渡すと、元の101と103へ戻せます。ただし、逆変換できることだけではデータリークの有無を判定できません。全件から学んだ変換器でも、同じ変換器で戻すこと自体はできるためです。

例えば確認条件を「元へ戻る」だけにすると、訓練四行で学習した場合と、全六行で学習した場合を区別できません。そこで、学習件数、平均、入力の列、逆変換の結果を組み合わせます。一つの成功したassertだけで、処理全体の条件を満たしたと考えないことが大切です。

入力列を増やす場合も、同じ考え方を使えます。「一列目は件数、二列目は円」という定義を残してから、各列の学習平均を照合します。変換後に値の大きさが似ると、列を取り違えても見た目で気づきにくくなります。標準化で単位感が薄れる分、元の項目と順序の記録が役立ちます。

このような検算は、すべての実データへ固定の数値を押し付けるものではありません。四行の教材では平均四と書けますが、入力が変われば期待値も作り直します。変わるべきものと、保つべき条件を分け、行が増えた後も参照範囲を説明できるようにします。

Pipelineと交差検証でも、平均を学習する範囲を守る

Pipelineへ変換器とモデルを入れ、元の訓練データを渡す

前処理とモデルの処理を別々のセルへ分散すると、どこで学習した基準を使ったか追いにくくなります。Pipelineは、変換とモデルを一つの流れにまとめる方法です。ここではStandardScalerとRidgeを組み合わせ、訓練四行へ学習させます。

以下は手順を確かめるための教材です。目的変数も架空で、現実の予測精度を示す設計ではありません。出力した予測値を成功の証拠にせず、内部のStandardScalerが四行から平均四を作ったことを確認します。

from sklearn.pipeline import make_pipeline
from sklearn.linear_model import Ridge

y_train = np.array([2., 4., 6., 8.])
pipe = make_pipeline(StandardScaler(), Ridge())
pipe.fit(X_train, y_train)

learned = pipe.named_steps["standardscaler"]
np.testing.assert_allclose(learned.mean_, [4.])
assert learned.n_samples_seen_ == 4
pred = pipe.predict(X_test)
assert pred.shape == (2,)

fitへ渡すのは、標準化前の訓練データです。predictへも、同じ列を持つ標準化前のテストデータを渡します。外で作った変換済みのテストを入れると、Pipeline内でもう一度変換することになり、入力の意味が変わります。

Pipelineへ入れる前に全件の標準化を終えていたら、その時点の混入は取り消されません。便利な仕組みを使うことと、入力の作り方が正しいことは別です。最初の入力が何かを、処理の入口から確認してください。

採用した処理を記録するときは、変換器とモデルを一組として扱います。モデルだけを別の前処理と組み合わせないようにします。保存・読込の実装は本稿の範囲外ですが、将来の入力にも、学習時に決めた列と単位を要求する点は同じです。

交差検証では、各分割の訓練部分ごとにfitする

交差検証では、訓練に使う行と検証に使う行を複数回入れ替えます。そのため、最初に全件を標準化してから交差検証する方法では、各回の検証部分が基準へ混ざります。変換器を含むPipelineを、交差検証へ渡します。

次の例も、分割の範囲を確認するための六行です。三分割なら各回の訓練は四行で、検証は二行になります。どの分割も同じ平均になるという意味ではありません。各回の平均は、それぞれの訓練行から計算されます。

from sklearn.model_selection import KFold, cross_validate

y = np.array([2., 4., 6., 8., 9., 10.])
result = cross_validate(
    make_pipeline(StandardScaler(), Ridge()),
    X, y, cv=KFold(n_splits=3),
    return_estimator=True
)
counts = [
    int(model.named_steps["standardscaler"].n_samples_seen_)
    for model in result["estimator"]
]
assert counts == [4, 4, 4]
print(counts)

出力は[4, 4, 4]です。これは、この教材の各回で変換器が四行を学習した確認です。六行では、モデルを実務で採用できる精度や、適切な分割数を評価できません。本稿では計算されたスコアを比較材料として使いません。

また、最後に保管するテストデータがある設計なら、それをモデル選択用の交差検証へ混ぜません。訓練・検証の繰り返しと、最終評価を分けることで、設定を選ぶたびにテストへ合わせることを防ぎます。

分割でクラス数のエラーが出る場合は、標準化の問題と切り分けます。train_test_splitのstratifyエラーを件数から調べる方法で、クラスごとの件数と、分割後に残るラベルを確認できます。scalerの設定を変えても、分割側の不足は直りません。

欠損補完・特徴選択も、データから学ぶ処理かを確認する

平均による欠損補完、特徴量の選択、次元の削減なども、データから何らかの基準を学ぶ処理です。StandardScalerだけを分割後へ移し、その前の学習処理が全件を見ていれば、評価用の情報が混ざる可能性は残ります。

ノートブックを読むときは、関数名の一覧より、「この処理は入力から何を覚えるか」と考えます。平均、中央値、選ぶ列、カテゴリ一覧などがデータから決まるなら、学習対象の範囲を確認する候補です。単なる表示や固定の単位換算とは区別します。

例えば、欠損値を訓練側の中央値で補う設計と、全件の中央値で補う設計では、参照した情報が違います。値が偶然同じでも、処理の順番を直さなくてよい理由にはなりません。別の入力で違いが出る可能性があるためです。

一方、業務で事前に決まっている「センチメートルをメートルへ換算する」といった固定の規則は、訓練データから平均を学ぶ処理とは役割が異なります。すべての計算を同じ理由で禁止するのではなく、決めた根拠と参照した行を説明します。

特徴量を作るタイミングにも注意します。予測の後に確定する完了日や結果を入力へ入れれば、分割後にscalerを学習していても、予測時点で使えない情報が混ざります。前処理の順番と、入力項目の時点を両方確認しましょう。

教材が複雑になったら、最初に小さな表へ戻します。列の名前、使える時点、データから学ぶ処理、学習に使う行を四列で書くと、何を分割後へ移すかを説明しやすくなります。コードが短いことだけを修正の基準にしないようにします。

標準化で変わることと、変わらない問題を区別する

標準化したから、どのモデルでも成績が改善するとは限りません。必要性は使う手法や特徴量によります。単位の異なる列を扱うときに検討する処理ですが、データの不備や、予測対象の定義を直す処理ではありません。

例えば行IDを数値として標準化しても、それが予測に使える情報になるとは限りません。欠損の理由、重複するID、目的変数の誤りなどは別に確認します。「数値に変換できた」「平均を引けた」という結果と、適切な特徴量であることを分けてください。

StandardScalerの公式説明では、外れ値への感度や、疎な行列を中心化する場合の制約も案内されています。外れ値を見つけたら、勝手に削除して見た目を整える前に、単位違いか実際の大きな値かを確認します。別の変換を使う場合も、比較は訓練・検証の設計内で行います。

一定値しかない列では、標準偏差で単純にゼロ除算するという読み方も避けます。StandardScalerには一定列の扱いがあります。欠損も、標準化すれば埋まるわけではありません。使うモデルが欠損をどう扱うかは、別途確かめる必要があります。

この教材では、学習範囲を見やすくするために後ろ二行をテストへ固定しました。実データが時系列なら将来を過去へ混ぜない分割、同じ人や端末の繰り返しならグループを分ける設計などを考えます。ラベル比率だけを揃えても、これらの条件を満たすとは限りません。

学習中の支援を相談したい人は、AIスクールの無料相談で聞くことも使えます。処理を動かす練習と、なぜその順番にするか説明する練習を組み合わせると、講師へ質問する箇所が具体的になります。

標準化の順番とデータリークのFAQ

よくある質問

Q. train_test_splitの前にStandardScalerを使ってはいけませんか?
A.

未知データの性能を評価する設計では、先に分割し、訓練データだけで平均などを学習します。単なる全件の記述的な分析と、未使用データによる予測評価を区別してください。

Q. テストデータにもfit_transformを使いますか?
A.

訓練で学習した同じ変換器のtransformを使います。テストでfitし直すと平均と標準偏差の基準が変わり、モデル学習時と同じ意味の数値ではなくなります。

Q. テストの平均がゼロにならなくてもよいですか?
A.

訓練側で作った基準を使うため、テストの平均がゼロになるとは限りません。大きな値が出たら、基準を作り直す前に、単位・列順・分布の違いを確認します。

Q. Pipelineへ入れれば、その前に全件fitしてもよいですか?
A.

Pipelineの外で全件から学んだ前処理は取り消されません。Pipelineへ渡す入力の作り方と、各fitがどの行を参照したかを確認してください。

Q. 標準化の順番を直すと予測精度は上がりますか?
A.

改善量は一律ではありません。評価用データが混ざる手順を修正することと、実際の予測性能の改善は別です。本稿の六行は学習範囲を確認する教材で、精度を示していません。

Q. 平均と学習件数だけ合えば、データリークはありませんか?
A.

それだけでは判断できません。入力に予測後の情報がないか、同一グループが分割をまたがないか、他の学習型前処理が全件を見ていないかも確認します。