見出し画像

train_test_split 関数

train_test_split 関数は、Scikit-learn(機械学習用のPythonライブラリ)に属しています。

この関数を使うことで、データセットを訓練用データとテスト用データに簡単に分割することができます。

その前に特徴量とターゲットの説明をしておきましょう。

特徴量(Features)とは?

特徴量とは、モデルが学習するために使用するデータのことです。

例:

  • 身長(cm)

  • 体重(kg)

  • 年齢(歳)

これらの特徴量を使用して、ターゲット変数を予測するためのモデルを作成します。

ターゲット(Target)

ターゲットとは、モデルが予測しようとするデータのことです。

例:

上記の特徴量を使って、人があるスポーツに適しているかどうかを予測する場合、ターゲット変数は「スポーツ適性」となります。例えば、「スポーツ適性」は0(適していない)または1(適している)といったラベルで表されることがあります。

train_test_split関数の基本的な使い方

from sklearn.model_selection import train_test_split

# データセットの作成(例として、特徴量とラベルの配列)
X = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
y = [0, 1, 0, 1, 0]

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

引数の詳細

train_test_split 関数の主な引数は以下の通りです:

  • X: 特徴量データセット(2次元配列やデータフレーム)

    • 訓練や予測に使用するデータです。
      行毎に1つのデータポイントを表し、各列はそれぞれの特徴を表します。

  • y: ターゲットデータセット(1次元配列やデータフレーム)

    • 予測する目標値やラベルです。各行は対応する特徴量の行に対応します。

  • test_size: テストデータの割合または個数(省略可能)

    • データの何割をテストデータとして使用するかを指定します。0より大きく1未満の小数(例えば、0.2)を指定すると、全データの20%をテストデータとして使用します。

    • または整数を指定することで、テストデータの個数を直接指定することもできます。

  • train_size: 訓練データの割合または個数(省略可能)

    • データの何割を訓練データとして使用するかを指定します。test_sizeと同様に小数や整数を使用できます。通常は省略します。

  • random_state: 乱数シード(省略可能)

    • 乱数シードを指定することで、データの分割が再現可能になります。同じシード値を使えば、何度実行しても同じ結果が得られます。再現性を持たせたい場合に便利です。

  • shuffle: データをシャッフルするかどうか(省略可能、デフォルトはTrue)

    • データをシャッフル(ランダムに並び替える)するかどうかを指定します。通常はシャッフルします。
      シャッフルすると、データがランダムに並び替えられ、訓練データとテストデータがバランス良く分かれます。
      シャッフルしない場合はデータの順序が維持され、特定の順序に基づくバイアスが生じる可能性があります。

  • stratify: ストラティファイドサンプリング(層化抽出)のための配列(省略可能)

    • y配列を指定すると、各クラスの割合を保ちながらデータを分割します。クラス不均衡があるデータセットで使用されます。
      (クラス不均衡は後で解説します。)

3. 返り値

train_test_split 関数は以下の4つのデータセットを返します:

  • X_train: 訓練用の特徴量データセット

  • X_test: テスト用の特徴量データセット

  • y_train: 訓練用のターゲットデータセット

  • y_test: テスト用のターゲットデータセット

4. 具体例

train_test_split 関数を使ってデータを分割し、その内容を表示する具体例です。

import numpy as np
from sklearn.model_selection import train_test_split

# 特徴量データの作成
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])

# ターゲットデータの作成
y = np.array([0, 1, 0, 1, 0])

# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 分割されたデータの表示
print("X_train:", X_train)
print("X_test:", X_test)
print("y_train:", y_train)
print("y_test:", y_test)

この例では、データセットを80%:20%の割合で訓練用とテスト用に分割し、乱数シードを設定して再現性を持たせています。

結果

X_train: [[7 8]
          [3 4]
          [1 2]
          [5 6]]
X_test: [[ 9 10]]
y_train: [1 1 0 0]
y_test: [0]
  • X_train: 訓練用の特徴量データセット

  • X_test: テスト用の特徴量データセット

  • y_train: 訓練用のターゲットデータセット

  • y_test: テスト用のターゲットデータセット

これにより、データの一部を訓練用としてモデルの学習に使用し、残りのデータをテスト用としてモデルの性能評価に使用します。

クラス不均衡とは?

例えば、病気の診断データセットがあるとします。

その中で「陽性(病気あり)」のデータポイントが少なく、「陰性(病気なし)」のデータポイントが非常に多い場合、このデータセットはクラス不均衡があるといいます。

具体例:

- 陽性(病気あり): 10例
- 陰性(病気なし): 90例

この場合、陽性のデータは全体の10%、陰性のデータが90%と大きく比率が異なります。

このような状況をクラス不均衡と呼びます。

クラス不均衡の問題

  • モデルのバイアス:
    データの分布が偏っているため、機械学習モデルは多数派のクラス(この例では陰性)に偏った予測をしやすくなります。

  • 性能評価の難しさ:
    クラス不均衡がある場合、モデルの精度(accuracy)だけでは性能を正しく評価できません。
    例えば、単純に陰性と予測するだけであれば90%の精度が得られますが、陽性は正しく予測できていないかもしれません。

例:

from sklearn.model_selection import train_test_split
import numpy as np

# 特徴量データの作成
X = np.arange(100).reshape(-1, 1)  # 100個のデータポイント
# ターゲットデータの作成(極端なクラス不均衡の例)
y = np.concatenate([np.ones(5), np.zeros(95)])  # 5個の陽性(1)と95個の陰性(0print("全データセットのクラス分布:")
print("陽性(1): {:.2f}".format(sum(y == 1) / len(y)))
print("陰性(0): {:.2f}".format(sum(y == 0) / len(y)))

# データの分割(stratify を使用しない場合)
X_train_ns, X_test_ns, y_train_ns, y_test_ns = train_test_split(X, y, test_size=0.2, random_state=42, stratify=None)

print("\nstratify を使用しない場合のクラス分布:")
print("訓練データ中のクラス分布: {{0: {:.2f}, 1: {:.2f}}}".format(sum(y_train_ns == 0) / len(y_train_ns), sum(y_train_ns == 1) / len(y_train_ns)))
print("テストデータ中のクラス分布: {{0: {:.2f}, 1: {:.2f}}}".format(sum(y_test_ns == 0) / len(y_test_ns), sum(y_test_ns == 1) / len(y_test_ns)))

# データの分割(stratify を使用する場合)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

print("\nstratify を使用する場合のクラス分布:")
print("訓練データ中のクラス分布: {{0: {:.2f}, 1: {:.2f}}}".format(sum(y_train == 0) / len(y_train), sum(y_train == 1) / len(y_train)))
print("テストデータ中のクラス分布: {{0: {:.2f}, 1: {:.2f}}}".format(sum(y_test == 0) / len(y_test), sum(y_test == 1) / len(y_test)))

このコードを実行すると、stratifyの有無でどう違うかがわかります。

データセットのクラス分布:
陽性(1): 0.05
陰性(0): 0.95

stratify を使用しない場合のクラス分布:
訓練データ中のクラス分布: {0: 0.96, 1: 0.04}
テストデータ中のクラス分布: {0: 0.90, 1: 0.10}

stratify を使用する場合のクラス分布:
訓練データ中のクラス分布: {0: 0.95, 1: 0.05}
テストデータ中のクラス分布: {0: 0.95, 1: 0.05}

いいなと思ったら応援しよう!