正規化とは?標準化との違い・使い分けとタイミングをPythonで解説(統計・機械学習)

統計や機械学習でいう正規化(スケーリング)とは、単位や大きさの違うデータを同じ物差しで比べられるように変換することです。代表的なのは、最小値を0・最大値を1にそろえる「Min-Max正規化」と、平均を0・標準偏差を1にそろえる「標準化(Zスコア)」の2つです。

この記事では、正規化と標準化の違い、外れ値に強いロバストスケーリング、名前がまぎらわしい scikit-learn の Normalizer、そして「いつ正規化するか」というタイミングの問題を、Pythonの実行結果で確かめながら説明します。コードは Python 3.12.15・NumPy 2.5.4・pandas 3.0.6・scikit-learn 1.9.1 で実行しました(2026年10月14日確認)。

正規化と標準化の違い

手法 計算式 変換後 外れ値の影響 scikit-learn
Min-Max正規化 (x − 最小値) ÷ (最大値 − 最小値) 0〜1の範囲 大きい(最大・最小が外れ値に引っ張られる) MinMaxScaler
標準化(Zスコア) (x − 平均) ÷ 標準偏差 平均0・標準偏差1 中程度 StandardScaler
ロバストスケーリング (x − 中央値) ÷ 四分位範囲 中央値0 小さい RobustScaler
ベクトルの正規化(L2) 各行をその行の長さで割る 各行の長さが1 行ごとの処理なので別物 Normalizer

「正規化」という言葉は、狭い意味では Min-Max正規化を指し、広い意味では標準化も含めたスケーリング全般を指します。資料によって使い方が違うので、どの計算式のことかを確認するのが確実です。同じ5人の身長に2つの方法を当てはめると、次のようになります。

import numpy as np

x = np.array([150, 160, 170, 180, 190], dtype=float)

minmax = (x - x.min()) / (x.max() - x.min())
z = (x - x.mean()) / x.std()
print("min-max:", minmax)
print("z-score:", z.round(3))
print("平均", z.mean().round(3), "標準偏差", z.std().round(3))

実行結果:

min-max: [0.   0.25 0.5  0.75 1.  ]
z-score: [-1.414 -0.707  0.     0.707  1.414]
平均 0.0 標準偏差 1.0

Min-Max正規化は「一番低い人が0、一番高い人が1」、標準化は「平均からどれだけ離れているかを標準偏差の何倍かで表したもの」です。標準化した値は偏差値と同じ考え方で、偏差値は標準化した値を10倍して50を足したものにあたります。標準化だけを詳しく知りたい場合はZスコア正規化(標準化)とは?を参照してください。

pandasで複数の列をまとめて変換する

表データなら pandas の演算で列ごとに計算できます。ただし pandas の std() は標本標準偏差(ddof=1、n−1で割る)を使うため、scikit-learn の StandardScaler(ddof=0、nで割る)とは結果が少しずれます。

import pandas as pd

df = pd.DataFrame({"身長": [150, 160, 170, 180, 190], "体重": [45, 55, 60, 72, 90]})
print(((df - df.min()) / (df.max() - df.min())).round(2))
print(((df - df.mean()) / df.std()).round(2))
print(df.std(ddof=0).round(3).tolist(), df.std().round(3).tolist())

実行結果:

     身長    体重
0  0.00  0.00
1  0.25  0.22
2  0.50  0.33
3  0.75  0.60
4  1.00  1.00
     身長    体重
0 -1.26 -1.12
1 -0.63 -0.54
2  0.00 -0.25
3  0.63  0.44
4  1.26  1.48
[14.142, 15.474] [15.811, 17.3]

最後の行が ddof=0 と ddof=1 の標準偏差です。scikit-learn のStandardScaler のドキュメントには、numpy.std(x, ddof=0) と同じ偏りのある推定量を使うこと、ddof の違いがモデルの性能に影響することはまずないことが書かれています。統計の課題で値を照合するときだけ、どちらを使ったかに注意してください。

外れ値があるときはどれを選ぶか

年収のデータに1件だけ極端な値(5,000万円)が混ざっている場合を考えます。3つの方法で変換すると、違いがはっきり出ます。

import numpy as np
from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler

# 年収(万円)に1件だけ極端な値がある
x = np.array([[300], [400], [450], [500], [550], [5000]], dtype=float)

for scaler in [MinMaxScaler(), StandardScaler(), RobustScaler()]:
    y = scaler.fit_transform(x).ravel()
    print(f"{type(scaler).__name__:15}", y.round(2))

実行結果:

MinMaxScaler    [0.   0.02 0.03 0.04 0.05 1.  ]
StandardScaler  [-0.53 -0.47 -0.44 -0.41 -0.38  2.23]
RobustScaler    [-1.4 -0.6 -0.2  0.2  0.6 36.2]
  • MinMaxScaler:最大値が5,000に引っ張られ、残り5件が0〜0.05の狭い範囲に押し込まれました。普通の人どうしの差がほとんど見えなくなります。
  • StandardScaler:平均と標準偏差も外れ値の影響を受け、5件がほぼ同じ値になっています。
  • RobustScaler:中央値と四分位範囲は外れ値の影響を受けにくいため、5件の差がそのまま残り、外れ値だけが36.2と大きく離れました。

外れ値が多いデータでは RobustScaler を試す価値があります。ただし、どの方法も外れ値そのものを消すわけではありません。入力ミスなのか本当の値なのかを確かめるのが先です。

scikit-learnのNormalizerは「行ごと」の正規化

名前から MinMaxScaler と同じものだと思われがちですが、Normalizer は列(特徴量)ではなく行(サンプル)ごとに、ベクトルの長さが1になるよう割り算します。scikit-learn のユーザーガイドでも、Normalization は「個々のサンプルを単位ノルムにする処理」として、列ごとのスケーリングとは別の節で説明されています。

import numpy as np
from sklearn.preprocessing import Normalizer, MinMaxScaler

X = np.array([[3.0, 4.0],
              [1.0, 0.0],
              [10.0, 10.0]])
print(Normalizer().fit_transform(X).round(3))   # 行ごと
print(MinMaxScaler().fit_transform(X).round(3))  # 列ごと

実行結果:

[[0.6   0.8  ]
 [1.    0.   ]
 [0.707 0.707]]
[[0.222 0.4  ]
 [0.    0.   ]
 [1.    1.   ]]

[3, 4] は長さ5なので [0.6, 0.8] になります。文章をベクトルにして向き(コサイン類似度)で比べるときなどに使うもので、身長と体重のような特徴量の大きさをそろえる目的には使いません。

正規化・標準化のタイミング:分割してから、訓練データだけで fit

もっとも間違えやすいのが、いつ正規化するかです。正しい順番は次のとおりです。

  1. データを訓練用とテスト用に分ける
  2. 訓練データだけで平均・標準偏差(または最小・最大)を計算する(fit)
  3. その値を使って、訓練データとテストデータの両方を変換する(transform)
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

rng = np.random.default_rng(0)
X = rng.normal(50, 10, size=(100, 1))
X_train, X_test = train_test_split(X, test_size=0.2, random_state=0)

scaler = StandardScaler()
scaler.fit(X_train)                   # 平均と標準偏差は訓練データだけで計算
X_train_s = scaler.transform(X_train)
X_test_s = scaler.transform(X_test)   # テストデータには同じ値を使う
print("訓練データの平均:", scaler.mean_.round(2), "標準偏差:", scaler.scale_.round(2))
print("変換後の訓練データ 平均:", X_train_s.mean().round(3), "標準偏差:", X_train_s.std().round(3))
print("変換後のテストデータ 平均:", X_test_s.mean().round(3), "標準偏差:", X_test_s.std().round(3))

実行結果:

訓練データの平均: [51.33] 標準偏差: [10.]
変換後の訓練データ 平均: 0.0 標準偏差: 1.0
変換後のテストデータ 平均: -0.26 標準偏差: 0.757

テストデータの変換後の平均は0ちょうどになりません。それで正しい状態です。分割前に全データで標準化すると、テストデータの情報が訓練に漏れ込み(データリーケージ)、評価が実際より良く見えてしまいます。scikit-learn のよくある落とし穴(Common pitfalls)でも、StandardScaler を含むほぼすべての前処理でこの漏れが起こりうると注意しています。交差検証では、次の節の例のように make_pipeline() で前処理とモデルをまとめておくと、分割ごとに自動で正しく fit されます。データリーケージ全般は過学習とは?でも解説しています。

正規化が効くモデル・効かないモデル

scikit-learn に付属のワインのデータ(13種類の成分)で、k近傍法と決定木を、標準化あり・なしで5分割交差検証して比べました。成分によって値の大きさが100倍以上違うデータです。

from sklearn.datasets import load_wine
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

X, y = load_wine(return_X_y=True)
print("列ごとの最大値(一部):", X.max(axis=0)[[0, 4, 12]])

for name, model in [
    ("k-NN そのまま", KNeighborsClassifier()),
    ("k-NN 標準化あり", make_pipeline(StandardScaler(), KNeighborsClassifier())),
    ("決定木 そのまま", DecisionTreeClassifier(random_state=0)),
    ("決定木 標準化あり", make_pipeline(StandardScaler(), DecisionTreeClassifier(random_state=0))),
]:
    score = cross_val_score(model, X, y, cv=5).mean()
    print(f"{name:12} 正解率 {score:.3f}")

実行結果:

列ごとの最大値(一部): [  14.83  162.   1680.  ]
k-NN そのまま    正解率 0.691
k-NN 標準化あり   正解率 0.949
決定木 そのまま     正解率 0.888
決定木 標準化あり    正解率 0.888

距離で判断する k近傍法は、標準化で正解率が 0.691 から 0.949 に上がりました。標準化しないと、値の大きい成分(最大1,680)だけで距離が決まってしまうためです。一方、決定木は「ある値より大きいか小さいか」で分けるので、標準化しても結果は変わりません。

正規化・標準化が効きやすい ほとんど影響しない
k近傍法、k-means、SVM、主成分分析(PCA)、ニューラルネットワーク、正則化つきの線形回帰・ロジスティック回帰 決定木、ランダムフォレスト、勾配ブースティングなどの木を使うモデル

k近傍法の仕組みはk近傍法(k-NN)とは?、Pipeline を含む scikit-learn の基本はscikit-learnの使い方入門にまとめています。

ほかの分野の「正規化」との違い

「正規化」は分野によってまったく別の意味で使われます。検索結果が混ざりやすいので整理しておきます。

  • データベースの正規化:表を分割して、同じ情報の重複をなくす設計手法です。数値の変換とは関係ありません(基本はデータベースとは?)。
  • 文字列の正規化:全角英数字や半角カナなど、見た目が同じ文字の表記ゆれをそろえる処理です。Python では unicodedata.normalize() を使います。
import unicodedata
print(unicodedata.normalize("NFKC", "ABC123 カタカナ"))

実行結果:

ABC123 カタカナ

よくある質問

Q. 正規化と標準化の違いは何ですか?

Min-Max正規化は最小値を0、最大値を1にそろえる変換で、標準化は平均を0、標準偏差を1にそろえる変換です。値の範囲を決めたいなら正規化、外れ値がある程度あるなら標準化がよく使われます。

Q. 正規化や標準化はいつ行えばよいですか?

訓練データとテストデータに分けた後に行います。平均や最小値などは訓練データだけで計算し、その値でテストデータも変換します。分割前に全体で計算するとデータリーケージになり、評価が実際より良く見えます。

Q. 外れ値がある場合はどの方法を使えばよいですか?

中央値と四分位範囲を使うロバストスケーリング(scikit-learnのRobustScaler)が外れ値の影響を受けにくい方法です。Min-Max正規化は外れ値に最も影響されます。

Q. scikit-learnのNormalizerとMinMaxScalerは同じですか?

違います。MinMaxScalerは列ごとに0〜1にそろえますが、Normalizerは行ごとにベクトルの長さを1にそろえます。特徴量の大きさをそろえる目的ならMinMaxScalerかStandardScalerを使います。

Q. 決定木やランダムフォレストでも正規化は必要ですか?

基本的に不要です。木のモデルは値の大小で分割するため、スケールを変えても分割の結果は変わりません。実際にワインのデータで試しても正解率は同じでした。

まとめ

正規化は値を0〜1に、標準化は平均0・標準偏差1にそろえる変換です。外れ値が多いならロバストスケーリング、行ごとにそろえる Normalizer は別物、と覚えておきましょう。そして、変換のパラメータは必ず訓練データだけで計算し、Pipeline にまとめると間違いが起きにくくなります。距離を使うモデルでは効果が大きく、木のモデルではほとんど影響しないことも実験で確かめられました。

手を動かしながら学びたい方は、テックジムの無料講座から始められます。テックジムは東京・永田町に本校がある通学型のプログラミングスクールで、自分のペースで進め、わからないところはトレーナーに質問できます。

正規化と標準化は、テックジムのAIエンジニア養成コースの第2章「特徴量エンジニアリング」で扱っています。機械学習とディープラーニングを16章で順に学ぶコースで、章ごとに実務での使いどころ(想定案件)が示されています。

機械学習の基礎の関連記事

同じテーマの記事をまとめています。あわせて読むと理解が早くなります。

機械学習の全体像は機械学習とは?初心者でもわかる完全ガイドにまとめています。

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら