Skip to content

Sklearn train_test_split:Pythonで機械学習用データを分割する方法

Updated on

評価に使用するのと同じデータで機械学習モデルを訓練すると、誤解を招く高い精度が得られます。モデルは一般化可能なパターンを学習する代わりに訓練データを記憶してしまいます——これは過学習と呼ばれる問題です。正直な性能指標を得るには、訓練中にモデルが一度も見ない別のテストセットが必要です。

Scikit-learnのtrain_test_split()は、データセットを訓練セットとテストセットに分割する標準的な方法です。配列、DataFrame、スパース行列を処理でき、層化抽出、再現性、カスタム分割比率のオプションがあります。

📚

基本的な使い方

from sklearn.model_selection import train_test_split
import numpy as np
 
# サンプルデータ:100サンプル、5特徴量
X = np.random.randn(100, 5)
y = np.random.randint(0, 2, 100)  # 二値ラベル
 
# 分割:80%訓練、20%テスト
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)
 
print(f"訓練セット:{X_train.shape[0]} サンプル")
print(f"テストセット:{X_test.shape[0]} サンプル")
# 訓練セット:80 サンプル
# テストセット:20 サンプル

主要パラメータ

パラメータデフォルト説明
test_size0.25テストサンプルの比率(0.0-1.0)または絶対数
train_sizeNone訓練サンプルの比率または数(test_sizeの補数)
random_stateNone再現可能な分割のためのシード
shuffleTrue分割前にデータをシャッフルするかどうか
stratifyNone層化分割に使用する配列

Pandas DataFrameとの使用

from sklearn.model_selection import train_test_split
import pandas as pd
 
df = pd.DataFrame({
    'age': [25, 30, 35, 40, 45, 50, 55, 60, 28, 33],
    'income': [40, 50, 60, 70, 80, 90, 100, 110, 45, 55],
    'purchased': [0, 0, 1, 1, 1, 1, 1, 1, 0, 0]
})
 
X = df[['age', 'income']]
y = df['purchased']
 
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)
 
print(f"訓練形状:{X_train.shape}")  # (7, 2)
print(f"テスト形状:{X_test.shape}")   # (3, 2)
print(type(X_train))  # <class 'pandas.core.frame.DataFrame'>

分割後もDataFrameはDataFrameのまま保持されます——列名とインデックスが保存されます。

random_state:再現可能な分割

random_stateがない場合、毎回異なる分割になります:

from sklearn.model_selection import train_test_split
import numpy as np
 
X = np.arange(10).reshape(5, 2)
y = np.array([0, 0, 1, 1, 1])
 
# random_stateなし:実行ごとに異なる分割
_, X_test1, _, _ = train_test_split(X, y, test_size=0.4)
_, X_test2, _, _ = train_test_split(X, y, test_size=0.4)
print(np.array_equal(X_test1, X_test2))  # おそらくFalse
 
# random_stateあり:毎回同じ分割
_, X_test3, _, _ = train_test_split(X, y, test_size=0.4, random_state=42)
_, X_test4, _, _ = train_test_split(X, y, test_size=0.4, random_state=42)
print(np.array_equal(X_test3, X_test4))  # True

**再現性のために常にrandom_stateを設定してください。**任意の整数を使用できます——42が慣例ですが、具体的な数字は重要ではありません。

層化分割

不均衡なデータセットでは、ランダム分割により少数派クラスのサンプルの大半が一方のセットに入る可能性があります。層化により、両方のセットが同じクラス比率を持つことが保証されます:

from sklearn.model_selection import train_test_split
import numpy as np
from collections import Counter
 
# 不均衡データセット:90%がクラス0、10%がクラス1
np.random.seed(42)
X = np.random.randn(200, 4)
y = np.array([0] * 180 + [1] * 20)
 
# 層化なし
_, _, y_train_bad, y_test_bad = train_test_split(
    X, y, test_size=0.2, random_state=42
)
print("層化なし:")
print(f"  訓練:{Counter(y_train_bad)}")
print(f"  テスト:{Counter(y_test_bad)}")
 
# 層化あり
_, _, y_train_good, y_test_good = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
print("\nstratify=yあり:")
print(f"  訓練:{Counter(y_train_good)}")
print(f"  テスト:{Counter(y_test_good)}")
# 訓練:Counter({0: 144, 1: 16})  -- 10%がクラス1
# テスト:Counter({0: 36, 1: 4})    -- 10%がクラス1

層化を使うべき場面

シナリオ層化を使う?
バランスの取れたクラス (50/50)任意
不均衡なクラス (90/10)はい
多クラス分類はい
回帰(連続目標)いいえ(サポートなし)
小さなデータセット (< 100サンプル)はい(空のクラスを防ぐ)

訓練/検証/テストの分割

ハイパーパラメータ調整には、訓練、検証、テストの3つのセットが必要です。train_test_splitを2回呼び出します:

from sklearn.model_selection import train_test_split
import numpy as np
 
X = np.random.randn(1000, 10)
y = np.random.randint(0, 3, 1000)
 
# 1回目の分割:80%訓練+検証、20%テスト
X_temp, X_test, y_temp, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
 
# 2回目の分割:75%訓練、25%検証(80%の25% = 全体で60/20/20)
X_train, X_val, y_train, y_val = train_test_split(
    X_temp, y_temp, test_size=0.25, random_state=42, stratify=y_temp
)
 
print(f"訓練:      {X_train.shape[0]} サンプル (60%)")
print(f"検証:      {X_val.shape[0]} サンプル (20%)")
print(f"テスト:    {X_test.shape[0]} サンプル (20%)")

完全な機械学習パイプライン例

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report
import numpy as np
 
# サンプルデータを生成
np.random.seed(42)
X = np.random.randn(500, 8)
y = (X[:, 0] + X[:, 1] > 0).astype(int)
 
# データを分割
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
 
# 特徴量のスケーリング(訓練データのみでfit!)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)  # 訓練の統計量を使用
 
# モデルを訓練
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train_scaled, y_train)
 
# 評価
y_pred = model.predict(X_test_scaled)
print(f"精度:{accuracy_score(y_test, y_pred):.4f}")
print(classification_report(y_test, y_pred))

**重要なルール:**スケーラー(およびすべての前処理)は訓練セットのみでフィットしてください。同じ変換をテストセットに適用します。完全なデータセットでフィットするとデータリークが発生します。

一般的な分割比率

分割訓練テストいつ使う
80/2080%20%デフォルトの選択、ほとんどのデータセット
70/3070%30%小さなデータセット、大きなテストセットが必要
90/1090%10%大きなデータセット(10k+サンプル)
60/20/2060%20%検証 + 20%テストハイパーパラメータ調整時

モデル結果の探索

分割してモデルを訓練した後、PyGWalker (opens in a new tab)を使えば、Jupyterで予測vs実測値、訓練/テストセットの特徴分布、エラーパターンをインタラクティブに探索できます:

import pandas as pd
import pygwalker as pyg
 
results = pd.DataFrame({
    'actual': y_test,
    'predicted': y_pred,
    'correct': y_test == y_pred
})
walker = pyg.walk(results)

よくある質問

sklearnのtrain_test_splitは何をする?

train_test_split()は配列やDataFrameをランダムに2つのサブセットに分割します:訓練用とテスト用。モデル評価が訓練中に見たことのないデータを使用することを保証し、正直な性能推定を提供します。

最適な訓練/テスト分割比率は?

80/20が標準のデフォルトです。信頼性の高いテストセットが必要な小さなデータセットには70/30を、大きなデータセット(10k+サンプル)には90/10を使用します。ハイパーパラメータ調整には60/20/20(訓練/検証/テスト)を使用します。

train_test_splitのrandom_stateは何をする?

random_stateは分割前のシャッフルのランダムシードを設定します。同じrandom_state値を使用すると毎回同じ分割が生成され、結果が再現可能になります。任意の整数が使えます。

train_test_splitでいつstratifyを使うべき?

ターゲット変数が不均衡な場合(例:95%が負、5%が正)や、データセットが小さい場合にstratify=yを使用します。層化により、訓練セットとテストセットの両方が各クラスの同じ比率を持つことが保証されます。

データを訓練セット、検証セット、テストセットに分割するには?

train_test_splitを2回呼び出します。最初に訓練+検証とテストに分割(例:80/20)。次に訓練+検証を訓練と検証に分割(例:80%の75/25で、全体で60/20/20)。あるいは、交差検証にsklearn.model_selection.KFoldを使用します。

まとめ

train_test_split()はPythonのすべての機械学習ワークフローの基盤です。訓練前に必ず使用してください——訓練データで評価してはいけません。再現性のためにrandom_stateを設定し、不均衡なクラスにはstratify=yを使用し、前処理ステップは訓練セットのみでフィットすることを忘れないでください。モデル選択には、3分割(訓練/検証/テスト)するか、より堅牢な推定のために交差検証を使用してください。

📚