機械学習におけるデータ前処理の基礎~欠損値・カテゴリ変数・スケーリング~

機械学習

こんにちは、ぼりたそです!

機械学習を始めたばかりの頃よく、

「モデルにデータを入れたらエラーになってしまった…」
「文字データがあると学習できないのはなぜ?」

ということが多くありました。

実は、機械学習モデルは「生のデータ」をそのまま扱えないことが多いんです。
そこで必要になるのが データ前処理(Preprocessing)

この記事では初心者がまず押さえるべき以下のポイントをまとめています。

Point
  • 欠損値処理
     
  • カテゴリ変数の変換
     
  • スケーリング

以上の3つのポイントをPythonコードの実装例とともに、メリット・デメリット・使いどころまで整理して解説します。

スポンサーリンク

データ前処理とは?

データ前処理とは、そのままでは機械学習モデルに入れられないデータを整える作業です。

例えば:

  • 欠損値(NaN)があればエラーになる
  • 「赤・青・緑」といった文字列は数値に直す必要がある
  • 年齢(20〜60)と年収(200万〜1000万)のようにスケールが違うと、学習が偏る

こうした問題を解決して初めて、モデルが正しく学習できるようになります。

ちなみに機械学習において「データの準備が7割、モデリングが3割」 と言われており、データ前処理の方が時間を要する場合がほとんどです。


欠損値処理

機械学習に使用する生データでは、欠損値(NaN)に必ずといっていいほど遭遇します。
例えば「年齢データが入力されていない」「アンケートで無回答」といったケースです。

欠損値をどう扱うかによってモデルの性能が大きく変わるため、欠損値処理は非常に重要となります。

今回は欠損値処理について3つの手法をご紹介します。

削除

まずは削除について紹介します。

手法としては単純に欠損行のある行や列を削除する方法となります。

メリット:シンプル・処理が早い
デメリット:データが減り、学習に使える情報が少なくなる

使いどころとしては欠損値が全体の数%以下で、削除しても影響が小さい場合のみに留めておくのが良いでしょう。

統計量を用いた補完

次に統計量を用いた補完です。

手法としては欠損値を平均値・中央値・最頻値等の統計量で補完する方法となります。

メリット:手軽に欠損値を埋められる
デメリット:データの分布を歪める可能性

使いどころとしては数値データなら平均or中央値、カテゴリデータなら最頻値で補完するのが安全です。

参考までに以下に統計量を用いた補完を実行するPythonコードを記載します。

import pandas as pd
from sklearn.impute import SimpleImputer

df = pd.DataFrame({
    "age":[25, 30, None, 45],
    "score":[80, None, 70, 90]
})

imputer = SimpleImputer(strategy="mean")  # 平均で補完
df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
print(df_imputed)

予測を用いた補完

最後に予測を用いた補完について紹介します。

手法としては少し高度ですがK近傍法(KNN)、回帰モデルなどで欠損値を推定して埋める方法となります。

メリット:補完の精度が高い
デメリット:データが少なく、予測精度が低い場合はデータを歪める可能性あり

使いどころとしてはデータが豊富で、欠損補完の正確性がある程度担保されている場合が挙げられます。

参考までに以下にKNN法を用いて欠損値補完するPythonコードを記載します。

KNN法とはざっくり、

  1. 欠損がある行を見つける
    例:「年齢=30, 年収=???, 学歴=大学」
  2. その行に似ている(特徴が近い)他の行を探す
    → 例えば「年齢が近い、学歴も同じ」といったレコード
  3. 近い行の「年収」の値を平均して、欠損を埋める

つまり、「似た情報から足りないデータを推測する」 という方法です。

import numpy as np
import pandas as pd
from sklearn.impute import KNNImputer

# --- サンプルデータ(数値のみ)---
df = pd.DataFrame({
    "x1": [1.2, 0.9, np.nan, 2.1, 1.8],
    "x2": [3.0, np.nan, 2.5, 2.9, 3.2],
    "y":  [10, 12, 11, np.nan, 13]
})

# --- 予測補完(KNN)---
imputer = KNNImputer(n_neighbors=2, weights="distance")  # 近い行ほど重みを大きく
df_knn = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)

print("== KNNImputer ==")
print(df_knn)

カテゴリ変数の変換

次に問題になるのが、カテゴリ変数(文字列データ)です。
「赤」「青」「緑」といった文字列は、そのままでは学習できません。
数値に変換してあげる必要があります。

今回はカテゴリ変数の変換の手法を2つ紹介します。

Label Encoding

まずはLabel Encodingという手法について説明します。

手法としては「赤=0, 青=1, 緑=2」とカテゴリ変数を整数に変換する方法になります。

メリット:新たに列が増えない
デメリット:「0<1<2」という順序が数値的な意味を持ってしまう

使いどころとしては、ラベルを記号扱いできるランダムフォレストや決定木などの木系モデルが好ましいです。

以下にLabel Encodingを実行するPythonコードを記載します。

import pandas as pd
from sklearn.preprocessing import LabelEncoder

df = pd.DataFrame({"color":["赤","青","緑","青","赤"]})

le = LabelEncoder()
df["color_le"] = le.fit_transform(df["color"])

print("=== Label Encoding ===")
print(df)
print("クラス対応:", dict(zip(le.classes_, le.transform(le.classes_))))

One-Hot Encoding

次にOne-Hot Encodingについて説明します。

手法としては、「赤→[1,0,0], 青→[0,1,0], 緑→[0,0,1]」と新たな列(例では赤列、青列、緑列の3列)を作成し、該当すれば「1」、該当しなければ「0」とする方法です。

メリット:カテゴリ変数間で大小関係を持たないので安全
デメリット:カテゴリ数が多いと列が爆発的に増える(次元の呪い)

使いどころとしては連続値を扱うことが多い線形回帰、SVM、ニューラルネットワークなどに使用することが多いです。

参考としてOne-Hot Encodingを実行するPythonコードを記載します。

import pandas as pd
from sklearn.preprocessing import OneHotEncoder

# サンプルデータ
df = pd.DataFrame({"color": ["赤","青","緑","青","赤"]})

# One-Hot Encoding
ohe = OneHotEncoder(sparse=False)  # ← 出力をnumpy配列にする
encoded = ohe.fit_transform(df[["color"]])

# 列名を取得
cols = ohe.get_feature_names_out(["color"])

# DataFrameに変換して結合
df_encoded = pd.DataFrame(encoded, columns=cols)
out = pd.concat([df, df_encoded], axis=1)

print(out)
スポンサーリンク

スケーリング

最後に紹介するのが スケーリング です。
機械学習において「年齢(20〜60)」と「年収(200〜1000万)」をそのまま使うと、年収の方が大きな数字なのでモデルに強い影響を与えてしまいます。

そこで「値の大きさを揃える」処理を行います。今回は3つのスケーリング手法についてご紹介します。


標準化(StandardScaler)

まずは標準化について紹介します。

手法としては各変数(列)ごとにデータを平均=0、分散=1に変換する方法になります。

メリット:多くのモデルで安定して学習できる
デメリット:外れ値に弱い

使いどころとしては特徴量間のばらつきが重要となるSVM、線形回帰、ロジスティック回帰、ニューラルネットワーク等での使用が多い。

参考として以下に標準化を実行するPythonコードを記載します。

import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# サンプルデータ
df = pd.DataFrame({
    "age": [20, 30, 40, 50],
    "income": [200, 400, 800, 1600]
})
print("=== 元のデータ ===")
print(df)

# 標準化(平均0・分散1)
scaler = StandardScaler()
df_std = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
print("\n=== 標準化 ===")
print(df_std)

正規化(MinMaxScaler)

次に正規化について紹介します。

手法としては各変数(列)ごとに最小値=0、最大値=1に変換する手法になります。

メリット:範囲を統一できる
デメリット:外れ値の影響を受けやすい

使いどころとしては特徴量の範囲を統一することが重要となるKNN(距離ベース)、PCA、ニューラルネットワークに使用することが多い。

参考として以下に正規化を行うPythonコードを記載します。

import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# サンプルデータ
df = pd.DataFrame({
    "age": [20, 30, 40, 50],
    "income": [200, 400, 800, 1600]
})
print("=== 元のデータ ===")
print(df)

# 正規化(0~1にスケーリング)
minmax = MinMaxScaler()
df_mm = pd.DataFrame(minmax.fit_transform(df), columns=df.columns)
print("\n=== 正規化 ===")
print(df_mm)

ロバストスケーリング(RobustScaler)

最後にロバストスケーリングについて説明します。

手法としては中央値=0、四分位範囲(標準化で言うところの分散)=1としてスケーリングする方法になります。

メリット:外れ値の影響を受けにくい
デメリット:標準化ほど「分布を揃える力」は弱い

使いどころとしては外れ値が多いデータへの使用が多いです。

参考として、以下にロバストスケーリングを実行するPythonコードを記載します。

import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler

# サンプルデータ
df = pd.DataFrame({
    "age": [20, 30, 40, 50],
    "income": [200, 400, 800, 1600]
})
print("=== 元のデータ ===")
print(df)

# 外れ値に強いスケーリング(RobustScaler)
robust = RobustScaler()
df_rb = pd.DataFrame(robust.fit_transform(df), columns=df.columns)
print("\n=== RobustScaler ===")
print(df_rb)

参考:標準化+正規化の組み合わせ

参考として 標準化のあとに正規化 を行う組み合わせ手法についてもご紹介します。

  1. 標準化で「分布を揃える」
  2. 正規化で「範囲を揃える」

こうすることで、特にニューラルネットワークやSVMのように入力スケールが重要なアルゴリズムで学習が安定します。

標準化 → 正規化 が基本です。
逆にすると正規化の意味が薄れるので注意が必要です。

以下に参考として標準化+正規化を実行するコードを記載します。

import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
from sklearn.pipeline import Pipeline

# サンプルデータ
df = pd.DataFrame({
    "age": [20, 30, 40, 50],
    "income": [200, 400, 800, 1600]
})
print("=== 元のデータ ===")
print(df)

# 標準化+正規化の組み合わせ
pipeline = Pipeline([
    ("std", StandardScaler()),   # 分布を揃える
    ("mm", MinMaxScaler())       # 範囲を0〜1に収める
])
df_combo = pd.DataFrame(pipeline.fit_transform(df), columns=df.columns)
print("\n=== 標準化+正規化 ===")
print(df_combo)

まとめ

今回はデータ前処理の基礎として、

  • 欠損値処理(削除・補完・高度な補完)
  • カテゴリ変数の変換(Label vs One-Hot)
  • スケーリング(標準化・正規化・RobustScaler・組み合わせ)

を紹介しました。

ポイントは:

  • 欠損は「削除か補完」で対応。平均・中央値補完は初心者にもおすすめ
  • カテゴリ変数は「木系ならLabel、線形系ならOne-Hot」
  • スケーリングは「モデルに応じて適切な手法を選ぶ」。外れ値が多いならロバストスケーリング、NNやSVMなら標準化+正規化の組み合わせも検討

データ前処理は地味ですが、モデルの精度を大きく左右する非常に重要なステップです。適切な前処理を行い、意味のある学習モデルの構築を目指していきたいですね。

この記事が少しでも皆様の手助けとなれば幸いです。

スポンサーリンク
タイトルとURLをコピーしました