【やさしい】解説!!「Kaggleを始める入門コース」【4章機械学習の進め方/モデルチューニング担当】

こんにちはヤク学長です。

本記事の目的は、「簡単にKaggleを始める」ことを目的としています。

【本記事のもくじ】

まず、「Kaggle」に真剣に取り組むための概要を解説します。
下記の方法で、簡単に概要を抑えることができます。

  • Kaggleはアジャイル型が基本
  • 分析プロセスの作成

  • モデルチューニングの進め方

それでは、上から順番に見ていきます。
なお、本上記の方法を抑えれば成果が出ます。

・Kaggleを使って、必要な基礎スキルをスムーズに身につけ効率的に学ぶための記事です。

記事の内容は「転載 & 引用OK」問題ありません。

目次

Kaggleはアジャイル型が基本

Kaggleはデータ分析のコンペティションプラットフォームであり、参加者が短期間で最高の結果を出すことを目的としています。そのため、開発手法としてアジャイル型が基本となっています。つまり、小さなステップで実装を進め、短期間で実装と検証を繰り返し、最終的な成果を目指すという開発手法が求められます。このようなアジャイル型の開発手法により、迅速なアイデアの検証や実装の修正が可能となり、最終的な成果の向上につながると考えられます。

分析プロセスの作成

分析プロセスとタスクのマトリックスの基本構成を記します

分析プロセス タスク
分析設計 – 目的の定義
– 問題の理解
– メソッドの選択
– 評価指標の決定
データ前処理 – 欠損値処理
– カテゴリ変数のエンコーディング
– データ正規化/標準化
特徴量生成 – 特徴エンジニアリング
– 特徴選択
データセット作成 – 訓練データ/テストデータ(および検証データ)の分割
バリデーション設計 – ホールドアウト法
– k-分割交差検証
– 層化k分割交差検証
– 時系列交差検証
モデル学習 – モデル構築
– ハイパーパラメータチューニング
– アンサンブル学習
モデル推論 – 予測値の生成
– 結果の解釈
– モデル性能評価

このマトリックスは、機械学習やデータ分析プロジェクトを進める際に、各プロセスで行うべきタスクを整理し、進捗管理を容易にするために使用できます。

このマトリックスを3人で進める前提で進めていきます。

  • ①ベースライン作成担当
  • ②特徴量エンジニアリング
  • ③モデルチューニング

今回は

②特徴量エンジニアリング担当

の工程を見ていきます。

モデルチューニングの進め方

モデルチューニングの進め方は以下のようになります。

  • ハイパーパラメータ探索空間の定義:モデルのハイパーパラメータの探索範囲を定義します。例えば、ランダムフォレストの場合、木の数、木の深さ、特徴量の数などがハイパーパラメータになります。

  • 探索方法の定義:どのような方法でハイパーパラメータ探索を行うかを定義します。グリッドサーチ、ランダムサーチ、ベイズ最適化などの方法があります。

  • モデルの学習と評価:探索したハイパーパラメータを使用して、モデルを学習させ、評価します。評価指標は、分類問題の場合はAccuracy、F1 score、ROC-AUCなどが一般的です。回帰問題の場合は、RMSEやMAEが使われます。

  • 最良のハイパーパラメータの選択:探索したハイパーパラメータの中から最も良い性能を持つものを選択します。

  • モデルの再学習:最良のハイパーパラメータを使用して、全てのトレーニングデータを用いて再学習します。

  • モデルの評価:最良のハイパーパラメータを使用して再学習したモデルを、テストデータを用いて評価します。

  • 提出用ファイルの作成:最良のハイパーパラメータを使用して再学習したモデルを、全てのトレーニングデータを用いて学習させ、提出用ファイルを作成します。

  • スタッキング:複数のモデルを用いてスタッキングを行う場合、1〜7のステップを各モデルごとに繰り返します。

LightGBMのハイパーパラメータのチューニング

LightGBMのハイパーパラメータのチューニングには、手動チューニングと自動チューニングの2つの方法があります。

手動チューニングは、パラメータの値を手動で変更しながら、評価指標の改善を目指す方法です。これは、各パラメータの意味を理解し、ドメイン知識や経験に基づいて最適な値を選択する必要があります。一般的には、ツールを使用してグリッドサーチを行うことが多いです。

自動チューニングは、ハイパーパラメータの値を自動的に探索して、評価指標の改善を目指す方法です。自動化されたツールを使用することで、時間と手間を節約できます。LightGBMには、Optuna、Hyperopt、Tuneなどの自動ハイパーパラメータチューニングツールがあります。これらのツールは、パラメータ探索のための最適化アルゴリズムを提供し、最適なパラメータを自動的に探索します。

なにごともそこそこを目指すことが重要です。

ハイパーパラメータの手動チューニング

対象とするモデルの仕組みの理解

対象とするモデルの仕組みを理解することは、モデルのハイパーパラメータを最適化するために非常に重要です。各モデルにはそれぞれ独自の仕組みがあり、その仕組みによってハイパーパラメータの設定方法や調整方法が異なります。

たとえば、ロジスティック回帰モデルでは、正則化パラメータとしてL1正則化とL2正則化の2種類があり、それぞれに異なるハイパーパラメータがあります。L1正則化の場合は、重要でない特徴量を0に近づけるL1正則化の効果を最大化するハイパーパラメータCを調整する必要があります。一方、L2正則化の場合は、特徴量の重みを減らすL2正則化の効果を最大化するハイパーパラメータCを調整する必要があります。

同様に、決定木モデルでは、木の深さ、枝刈りの方法、分岐の閾値などのハイパーパラメータを調整する必要があります。ランダムフォレストモデルでは、ツリーの数、木の深さ、ブートストラップサンプリングの割合、分岐の閾値などのハイパーパラメータを調整する必要があります。

したがって、ハイパーパラメータを最適化する前に、対象とするモデルの仕組みを理解することが重要です。

決定木の仕組み

決定木は、目的変数と関連する特徴量を用いて、データを分割し、ツリー状に分類する手法です。分割の基準となる特徴量と、分割方法を選択することにより、分類が進んでいきます。分割が進むにつれて、各分割における目的変数の分布がより純化されていくため、より正確な予測が可能となります。

具体的には、以下の手順で分類を行います。

  • 根ノードを作成し、その中にすべてのサンプルを含めます。
  • 根ノードでの特徴量の分割基準となる閾値を選択し、サンプルを2つの子ノードに分割します。この際、分割方法によって純度が高くなるように、最もよい特徴量と閾値を選択します。
  • 各子ノードにおいて、さらに特徴量の分割基準となる閾値を選択し、分割を行います。この分割基準は、親ノードの分割基準とは異なる場合があります。
  • この分割を繰り返し、ツリーを成長させます。
  • 成長したツリーを用いて、未知のデータの分類を行います。これは、根ノードから子ノードへとたどっていき、最終的にどの葉ノードに到達したかで分類を決定することになります。

決定木の特徴として、視覚的に分かりやすく、特徴量の重要度が明確になることが挙げられます。しかし、過剰適合(オーバーフィッティング)の問題が生じることがあります。また、分割の基準やツリーの深さなど、ハイパーパラメータを適切に設定しなければ、適切な分類を行えないことがあります。

勾配ブースティングの仕組み

勾配ブースティングとは、弱学習器(weak learner)を繰り返し学習させて、その結果を組み合わせて予測を行うアンサンブル学習の手法の一つです。

具体的には、損失関数を定義し、この損失関数を最小化するように弱学習器を繰り返し学習していきます。各反復において、前回の反復での予測結果と正解データの差(残差)を計算し、この残差を次の弱学習器の学習に用いることで、より正確な予測を行うことができます。

このように、弱学習器を繰り返し学習していくことで、誤差を徐々に減らしていき、高い予測精度を達成することができます。ただし、反復が進むにつれて、過学習(overfitting)が発生することがありますので、注意が必要です。

勾配ブースティングでは、損失関数に対して勾配(gradient)を求め、その勾配を用いて、次の弱学習器の学習に用いるトレーニングデータのサンプルを選択する重みを決定します。このように、勾配情報を用いることで、より効率的な学習が可能となります。

代表的な勾配ブースティングの手法としては、Gradient Boosting Decision Tree (GBDT)、XGBoost、LightGBMなどが挙げられます。これらの手法は、ハイパーパラメータを適切に調整することで、高い予測精度を発揮することができます。

モデルの仕組みとハイパーパラメータの関係

モデルの仕組みとハイパーパラメータには密接な関係があります。モデルは、データセットから学習したパラメータを使用して予測を行います。一方、ハイパーパラメータは、モデルの学習方法を制御するためのパラメータであり、ユーザーが手動で設定する必要があります。したがって、ハイパーパラメータはモデルのパフォーマンスに大きな影響を与える可能性があります。

例えば、決定木の場合、ハイパーパラメータには以下のようなものがあります。

  • ツリーの深さ
  • 葉ノードの最小サンプル数
  • 分割するための特徴量の最小値
  • 分割するためのサンプル数の最小値

これらのハイパーパラメータを調整することで、モデルのパフォーマンスを最適化することができます。例えば、ツリーの深さが深すぎると、過剰適合の可能性が高くなります。逆に、深さが浅すぎると、十分な学習が行われない可能性があります。したがって、最適なハイパーパラメータの設定は、モデルのパフォーマンスを改善するために重要です。

LightGBMの主要なハイパーパラメータ

LightGBMの主要なハイパーパラメータのマトリックス

パラメータ名 説明
num_leaves 決定木の葉の最大数
max_depth 決定木の深さの最大値
min_child_samples 子ノードに含まれる最小のサンプル数
subsample データセットからランダムに選択されるサンプルの割合
colsample_bytree トレーニングセットの列(特徴量)の割合
reg_alpha L1正則化項の強さ
reg_lambda L2正則化項の強さ
learning_rate 各ステップでの重み更新の影響度を調整する学習率
n_estimators 使用する決定木の数

これらのパラメータを調整することで、モデルの性能を最適化することができます。ただし、パラメータの調整は過剰適合(オーバーフィッティング)を引き起こす場合があるため、注意が必要です。

勾配ブースティングの構成

ハイパーパラメータ 説明 デフォルト値 チューニングイメージ おすすめの初期値 おすすめの探索範囲
num_iterations 学習回数を指定するパラメータ 100 大きな値にすることで精度が向上するが、過学習になりやすくなるため、適切な値を選択する必要がある。 100000
探索なし
learning_rate 学習率を指定するパラメータ 0.1 小さな値にすることで安定した収束が期待できるが、学習が遅くなる。大きな値にすることで学習が早くなるが、不安定になりやすい。 0.05 [0.1,~000.1]

注意:おすすめの初期値や探索範囲は一例であり、実際の問題やデータによって最適な値が異なる場合があります。

決定木の構成

ハイパーパラメータ デフォルト値 チューニングイメージ おすすめの初期値 おすすめの探索範囲
num_leaves 31 大きな値から小さくして、過剰適合を回避する。 16 8-256
max_depth -1 木の深さを調整することで過剰適合を回避する。 -1 探索なし
  • num_leavesは、LightGBMの木の葉の数を指定するハイパーパラメータです。num_leavesの値が大きいほど、モデルの複雑度が高くなり、過剰適合しやすくなります。適切な値を選ぶことで、過剰適合を回避し、モデルの汎化性能を向上させることができます。
  • max_depthは、LightGBMの決定木の深さを指定するハイパーパラメータです。max_depthが深くなるほど、モデルの複雑度が高くなり、過剰適合しやすくなります。適切な値を選ぶことで、過剰適合を回避し、モデルの汎化性能を向上させることができます。

過学習の抑制

パラメータ名 デフォルト値 チューニングイメージ おすすめの初期値 おすすめの探索範囲
early_stopping_rounds 0 適切な値を設定して、過学習を防止する 100
探索なし
min_data_in_leaf 20 過学習を防ぐために増やす 20 5から200程度まで
min_sum_hessian_in_leaf 1e-3 過学習を防ぐために増やす 1e-3 1e-5から1e-2程度まで
bagging_fraction 1.0 ブートストラップの割合を調整する 0.9 0.5から1.0程度まで
bagging_freq 0 ブートストラップの頻度を調整する 1
探索なし
feature_fraction 1.0 特徴量のサブサンプリングの割合を調整する 0.9 0.5から1.0程度まで
lambda_l1 0.0 L1正則化の強さを調整する 0.0 0.01から100程度まで
lambda_l2 0.0 L2正則化の強さを調整する 0.0 0.01から100程度まで

※ パラメータの効果や適切な探索範囲はデータやタスクに依存するため、目安として捉えてください。また、初期値や探索範囲は個人差がありますので、柔軟に調整していくことが重要です。

チューニングの手順

ハイパーパラメータのチューニング手順は次の通りです。

  • デフォルト値でモデルを訓練して、性能を確認する。
  • パフォーマンスを向上させるために、ハイパーパラメータの値を手動で変更し、再度モデルを訓練する。
  • グリッドサーチ、ランダムサーチ、ベイズ最適化などの自動化されたチューニングアプローチを使用する。
  • 訓練データをより適切に反映するために、交差検証などの評価指標を使用してモデルの性能を測定する。
  • チューニングの結果をテストデータで検証する。テストデータでの予測精度が高く、過剰適合していないことを確認する。

これらの手順を繰り返して、最適なハイパーパラメータを見つけることが目的です。ただし、過剰適合に注意し、テストデータでの汎化性能を確認することが非常に重要です。

早めに学習が止まってしまう場合

早めに学習が止まってしまう場合、主な原因としては以下のようなものが考えられます。

  • モデルが過剰適合しているため、過学習が発生している
  • ハイパーパラメータが不適切であるため、最適なハイパーパラメータが設定されていない
  • 学習データの量が不足しているため、十分な情報が得られていない
  • 特徴量の選択が不適切であるため、モデルに必要な情報が欠落している

このような場合、以下のような対策が考えられます。

  • モデルの複雑度を下げるために、特徴量の数を減らす、正則化を掛ける、またはよりシンプルなモデルを選択するなどの方法があります。
  • ハイパーパラメータのチューニングを行い、最適なハイパーパラメータを設定します。ハイパーパラメータチューニングにはグリッドサーチやランダムサーチなどの方法があります。
  • 学習データを増やすことで、モデルに十分な情報を提供することができます。もし学習データを増やすことができない場合、データ拡張や転移学習などの方法があります。
  • 特徴量エンジニアリングを行い、より有益な特徴量を抽出することができます。また、特徴量選択を行い、モデルに必要な情報だけを取り入れることができます。

→ min_data_in_leafやlearning_rateを小さくする

学習データと検証データの評価値のギャップが大きい場合

学習データと検証データの評価値のギャップが大きい場合、過学習が発生している可能性があります。過学習とは、モデルが学習データに過度に適合し、未知のデータに対して予測性能が低下する現象です。この場合、モデルの複雑度が高すぎる可能性があるため、モデルの複雑度を下げることが有効な対策となります。具体的には、ハイパーパラメータの調整や特徴量選択を行うことが考えられます。また、データ量が不足している場合には、データの拡張や生成を行うことで過学習を防ぐことができます。

→ min_data_in_leafを大きくする。bagging_fractionとfeature_fractionを小さくする

学習に時間がかかりすぎる場合

学習に時間がかかりすぎる場合、以下のような方法があります。

  • データサンプリング:学習データを一部サンプリングして、学習に使うデータを減らす方法です。ただし、サンプリングによって有用な情報が失われることがあるため、慎重に行う必要があります。

  • 特徴量選択:モデルにとって不要な特徴量を除外することで、学習に必要な情報を減らし、学習時間を短縮することができます。

  • ハイパーパラメータの調整:学習に使用するアルゴリズムのハイパーパラメータを適切に調整することで、学習時間を短縮することができます。ただし、ハイパーパラメータの適切な値を見つけるためには、試行錯誤が必要です。

  • 並列処理:学習に使用するコンピュータのCPUやGPUを並列処理に利用することで、学習時間を短縮することができます。

  • モデルの変更:学習に使用するアルゴリズムを変更することで、学習時間を短縮することができます。ただし、アルゴリズムを変更することによって、モデルの性能が低下する可能性があるため、注意が必要です。

→ learning_rateを大きくする。bagging_fractionを小さくする

ハイパーパラメータの自動チューニング

ハイパーパラメータの自動チューニングには、グリッドサーチ、ランダムサーチ、ベイズ最適化などがあります。

グリッドサーチは、あらかじめ設定した候補値から全ての組み合わせを試し、最適なハイパーパラメータを探索する手法です。候補となる値の範囲を設定し、それをすべて網羅的に探索します。値の範囲が大きい場合には計算量が多くなるため、ランダムサーチなど他の手法が有効です。

ランダムサーチは、あらかじめ設定した値の範囲からランダムに値を選び出し、その値を使ってモデルを評価します。ランダムサーチはグリッドサーチよりも計算時間が短く、結果的により良いハイパーパラメータを見つけることができることがあります。

ベイズ最適化は、過去の試行結果を元に、より良い値を推測しながらハイパーパラメータの探索を行う手法です。この手法では、探索範囲を指定し、初期値をランダムに選択します。次に、ベイズ最適化アルゴリズムによって次の値を決定し、評価します。このサイクルを繰り返して、最適なハイパーパラメータを見つけます。

これらの手法は、それぞれの特徴を持っています。グリッドサーチは網羅的に探索するため、あらゆる組み合わせを試すことができますが、計算時間が非常に長くなります。ランダムサーチは、探索する範囲を指定することで、効率的に探索できるため、計算時間が短くなります。一方、ベイズ最適化は、過去の試行結果を元により良い値を推測しながら探索できるため、計算時間が短くても良いハイパーパラメータを見つけることができます。

以下に、ハイパーパラメータの自動チューニングにおけるアプローチ、探索方法、および利用できるライブラリ/関数の例を示します。

アプローチ 探索方法 ライブラリ/関数
グリッドサーチ すべてのハイパーパラメータの値の組み合わせを試す scikit-learnのGridSearchCV
ランダムサーチ 値の範囲内でランダムに値を選択して試す scikit-learnのRandomizedSearchCV
ベイズ最適化 過去の試行結果をもとに、次に試すべき値を推定する scikit-optimizeのBayesSearchCV、Optuna

ただし、これらの方法を用いても、全てのハイパーパラメータの組み合わせを試すわけではなく、探索範囲や試行回数の設定が重要です。また、実際にはハイパーパラメータの選択においては、ドメイン知識や経験的な知見も重要になります。

Oputunaを用いたハイパーパラメータの自動チューニング

Optunaは、Bayesian Optimizationを使用したハイパーパラメータ自動最適化ライブラリです。以下のような手順で使用することができます。

  • チューニングしたいハイパーパラメータの範囲を指定する。
import optuna

def objective(trial):
x = trial.suggest_uniform('x', -10, 10)
y = trial.suggest_categorical('y', [-1, 0, 1])
return x**2 + y

study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=100)

定義した目的関数を実行する。

import optuna

def objective(trial):
params = {
'num_iterations': trial.suggest_int('num_iterations', 1, 1000),
'learning_rate': trial.suggest_uniform('learning_rate', 0.01, 0.1),
}
# LightGBMを設定
lgbm = lgb.LGBMClassifier(**params)
# 学習と評価
lgbm.fit(X_train, y_train, eval_set=(X_valid, y_valid))
auc = roc_auc_score(y_valid, lgbm.predict_proba(X_valid)[:, 1])
return auc

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=10)

探索しないパラメータは、そのままモデルの設定として渡します。例えば、以下のようなコードで、objectiveとmetricをbinary_loglossとする場合の設定方法を示します。

params = {
'num_iterations': 1000,
'learning_rate': 0.05,
'objective': 'binary',
'metric': 'binary_logloss',
}
lgbm = lgb.LGBMClassifier(**params)

次に、以下のようなコードを使用して、Optunaを使用してLightGBMのハイパーパラメータを自動チューニングできます。

import optuna
import lightgbm as lgb
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split


# データの読み込み
cancer = load_breast_cancer()
X = cancer.data
y = cancer.target

# 学習用と検証用に分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

# 目的関数の定義
def objective(trial):
# ハイパーパラメータの探索範囲
param = {
'objective': 'binary',
'metric': 'binary_logloss',
'verbosity': -1,
'boosting_type': 'gbdt',
'num_leaves': trial.suggest_int('num_leaves', 2, 31),
'max_depth': trial.suggest_int('max_depth', 1, 10),
'learning_rate': trial.suggest_loguniform('learning_rate', 0.001, 0.1),
'feature_fraction': trial.suggest_uniform('feature_fraction', 0.1, 1.0),
'bagging_fraction': trial.suggest_uniform('bagging_fraction', 0.1, 1.0),
'bagging_freq': trial.suggest_int('bagging_freq', 0, 10),
'lambda_l1': trial.suggest_loguniform('lambda_l1', 1e-8, 10.0),
'lambda_l2': trial.suggest_loguniform('lambda_l2', 1e-8, 10.0),
'min_child_samples': trial.suggest_int('min_child_samples', 5, 100)
}

# LightGBMの学習器を定義
clf = lgb.train(param, lgb.Dataset(X_train, y_train))

# 検証データで予測を行い、Accuracyを返す
y_pred = clf.predict(X_test)
y_pred = [1 if x >= 0.5 else 0 for x in y_pred]
accuracy = accuracy_score(y_test, y_pred)

return accuracy
# Optunaで最適化
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)

# 最適化結果の表示
print('Best trial:')
trial = study.best_trial
print(' Value: {}'.format(trial.value))
print(' Params: ')
for key, value in trial.params.items():
print(' {}: {}'.format(key, value)))

Optunaによる最適化処理が終了したら、study.best_paramsを使用してベストなハイパーパラメータを取得することができます。

具体的には、以下のようにコードを記述します。

best_params = study.best_params

このようにして、最適化処理で探索されたベストなハイパーパラメータを取得することができます。取得したハイパーパラメータは、モデルのパラメータとして使用されます。

LightGBM以外のモデル利用

各手順において、適切なツールやライブラリを選定することが重要です。例えば、scikit-learnライブラリを利用する場合、GridSearchCVやRandomizedSearchCVなどの関数を利用することで、ハイパーパラメータのチューニングを行うことができます。また、ベイズ最適化を用いたハイパーパラメータのチューニングには、OptunaやHyperoptなどのライブラリが利用されます。

scikit-learnの各種モデルを使いこなそう

汎用的なPython処理手順

scikit-learnの汎用的なPython処理手順は以下のようになります。

①モデル定義

  • 使用するアルゴリズムの選択
  • モデルのハイパーパラメータの設定
  • モデルのインスタンス化

②学習

  • fit()メソッドを用いて、学習用データを用いてモデルを学習
  • モデルの評価

③予測

  • predict()メソッドを用いて、未知のデータに対する予測を行う

具体的な例を挙げると、以下のようなコードになります。

# 必要なライブラリをインポートする
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# データの読み込み
X, y = load_data()

# データを学習用とテスト用に分割する
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# モデルの定義
model = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)

# 学習
model.fit(X_train, y_train)

# テストデータに対する予測を行う
y_pred = model.predict(X_test)

# テストデータに対する正解率を計算する
acc = accuracy_score(y_test, y_pred)
print(f"Accuracy: {acc:.3f}")

この例では、ランダムフォレストを用いた分類モデルの定義、学習、予測、評価の一連の処理が行われています。

scikit-learnの注意点3つ

scikit-learnの注意点としては、以下の3つが挙げられます。

  • 欠損値の処理

scikit-learnのモデルは欠損値を許容していない場合があります。欠損値が含まれるデータを処理する際には、欠損値を除外するか、適切な値に補完する必要があります。また、欠損値を除外する際には、データが偏る場合があるので注意が必要です。

  • 数値データへの変換

scikit-learnのモデルは、すべての変数が数値であることを前提としています。カテゴリ変数やテキストデータなど、数値でない変数を扱う場合は、事前に数値データに変換する必要があります。変換方法は、One-Hot EncodingやLabel Encodingなどがあります。

  • 正規化・標準化

異なるスケールを持つ変数を扱う場合、正規化や標準化を行う必要があります。正規化は、データを0から1の範囲に変換する処理であり、標準化は、データを平均0、標準偏差1に変換する処理です。正規化や標準化を行うことで、異なるスケールの変数を比較しやすくなり、モデルの学習がより効率的になります。

ニューラルネットワーク

ニューラルネットワークは、人工知能の分野で広く使用される機械学習アルゴリズムの一つです。神経細胞をモデル化した数学的モデルであり、多数のニューロンが相互に接続された層を積み重ねた構造を持ちます。入力データがこのネットワークに入力され、隠れ層を通過して最終的な出力が生成されます。

ニューラルネットワークは、画像認識、自然言語処理、音声認識など、多数のタスクに使用されています。最近では、深層学習と組み合わせて用いることで、非常に高い精度を出すことができるようになっています。

ニューラルネットワークの学習では、誤差逆伝播法というアルゴリズムを使用します。このアルゴリズムでは、出力層の誤差から逆算して各層の誤差を求め、それを元に各層の重みを更新していきます。このようにして、ネットワーク全体の誤差を最小化するように重みが調整されます。

ニューラルネットワークのハイパーパラメータのチューニングは、通常の機械学習モデルと同様に、グリッドサーチやランダムサーチなどの手法を用いることができます。また、最近では、ニューラルネットワークのアーキテクチャを自動的に最適化するアルゴリズムも提案されています。

ニューラルネットワークの注意点3つ

ニューラルネットワークの注意点について回答します。

  • 欠損値の処理 ニューラルネットワークにおいても、欠損値がある場合は適切に処理する必要があります。一般的には、欠損値を平均値や中央値、最頻値などで補完する方法が使われます。また、欠損値が多い場合は、その特徴量を除外することも考慮されます。

  • 入力データはすべて数値データである必要がある ニューラルネットワークは数値データを扱うため、入力データはすべて数値データである必要があります。カテゴリカルデータやテキストデータなどは、適切な前処理を行い、数値データに変換する必要があります。

  • 正規化・標準化の必要性 ニューラルネットワークにおいては、入力データのスケールが異なる場合、重みの更新が適切に行われないことがあります。そのため、入力データを正規化・標準化することが推奨されます。正規化・標準化によって、入力データのスケールを揃えることができ、ニューラルネットワークの学習が安定しやすくなります。

ニューラルネットワークの適用例:①全結合層のみのネットワークモデル

全結合層のみのネットワークモデルは、全ての入力層から出力層までの間に全結合層だけを持ち、中間層は存在しない単純なモデルです。以下は、TensorFlowを用いた全結合層のみのネットワークモデルの簡単な例です。

まず、必要なライブラリをインポートします。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

次に、モデルの定義を行います。ここでは、2つの入力変数を持ち、1つの出力変数を予測する簡単なモデルを定義します。

model = keras.Sequential([
layers.Dense(64, activation='relu', input_shape=[2]),
layers.Dense(1)
])

上記のモデルは、64ユニットの全結合層を持ち、入力層には2つの変数があることを指定しています。活性化関数にはReLUを使用しています。また、出力層には1つの変数があります。

次に、モデルをコンパイルします。この際に損失関数、最適化アルゴリズム、評価指標を指定します。

model.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.01), metrics=['mae', 'mse'])

上記のコードでは、平均二乗誤差を損失関数として使用し、Adamを最適化アルゴリズムとして使用しています。また、平均絶対誤差と平均二乗誤差を評価指標として指定しています。

最後に、モデルを学習させます。

history = model.fit(x_train, y_train, epochs=100, validation_split=0.2)

上記のコードでは、学習用データと検証用データを指定しています。また、100エポック学習を行っています。

学習が完了したら、テストデータを用いて予測を行います。

y_pred = model.predict(x_test)

上記のコードでは、テストデータを用いて予測を行い、予測結果をy_predに格納しています。

例題

import tensorflow as tf
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder

# 再現性のためのシード作成
tf.random.set_seed(1)

# ファイルの読み込みとデータセット作成
data = pd.read_csv("data.csv")

# 数値データの前処理
num_cols = ['age', 'fare']
data[num_cols] = StandardScaler().fit_transform(data[num_cols])

# カテゴリ変数の前処理
cat_cols = ['sex', 'embarked']
for col in cat_cols:
data[col] = LabelEncoder().fit_transform(data[col])

# 学習データと検証データの分割
X_train, X_test, y_train, y_test = train_test_split(data.drop('survived', axis=1), data['survived'], test_size=0.2)

# モデル定義
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation='relu', input_shape=(6,)),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])

# モデル学習
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=100, batch_size=32, verbose=2)

# モデルの評価
model.evaluate(X_test, y_test, verbose=2)

この例では、data.csvファイルからデータを読み込んで、数値データとカテゴリデータを前処理しています。そして、train_test_split関数を使ってデータを学習データと検証データに分割し、tf.keras.Sequential関数を使って全結合層のみのニューラルネットワークモデルを定義しました。モデルをコンパイルし、fit関数で学習を行い、evaluate関数で検証を行いました。

ニューラルネットワークの適用例:②埋め込み層ありのネットワークモデル

埋め込み層ありのニューラルネットワークモデルは、カテゴリ変数を扱うためのモデルです。カテゴリ変数は、数値データではなく、文字列などの形で表現されます。そのため、通常のニューラルネットワークでは扱えませんが、埋め込み層を使うことで数値データに変換することができます。

具体的には、カテゴリ変数のそれぞれの値に対して、ランダムなベクトルを割り当て、埋め込み行列として用意します。これにより、カテゴリ変数が数値データに変換され、通常のニューラルネットワークで扱えるようになります。

以下は、埋め込み層ありのニューラルネットワークモデルの一例です。

import tensorflow as tf
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from tensorflow.keras.layers import Input, Embedding, Dense, Flatten, Concatenate
from tensorflow.keras.models import Model

# データの読み込みと前処理
df = pd.read_csv('data.csv')
# カテゴリ変数の前処理
df['category'] = pd.Categorical(df['category'])
df['category'] = df['category'].cat.codes
# 学習データと検証データの分割
train, test = train_test_split(df, test_size=0.2, random_state=42)
train_X = [train['numeric'], train['category']]
train_y = train['label']
test_X = [test['numeric'], test['category']]
test_y = test['label']

# モデル定義
numeric_input = Input(shape=(1,))
numeric_layer = Dense(8, activation='relu')(numeric_input)
category_input = Input(shape=(1,))
category_layer = Embedding(input_dim=len(df['category'].unique()), output_dim=3)(category_input)
category_layer = Flatten()(category_layer)
merged_layer = Concatenate()([numeric_layer, category_layer])
output_layer = Dense(1, activation='sigmoid')(merged_layer)
model = Model(inputs=[numeric_input, category_input], outputs=output_layer)

# モデル学習
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(train_X, train_y, validation_data=(test_X, test_y), epochs=10, batch_size=32)

# モデルの評価
model.evaluate(test_X, test_y)

この例では、数値データとカテゴリデータをそれぞれ別々の入力層に渡し、それらを結合するためにConcatenateレイヤーを使用しています。また、カテゴリデータはEmbeddingレイヤーで埋め込み表現に変換しています。それ以外の部分は全結合層のみのネットワークモデルと同様に定義されています。

アンサンブル

アンサンブルとは、複数のモデルを組み合わせて予測する手法です。単一のモデルでは解決できない複雑な問題に対して高い精度を実現することができます。主なアンサンブル手法には、バギング、ブースティング、スタッキングなどがあります。

バギングは、ブートストラップ法を用いて複数のデータセットを生成し、それぞれのデータセットに対して個別のモデルを構築して、それらのモデルの予測結果を平均して最終的な予測結果を得る手法です。個別のモデルを構築する際に、サンプリングされなかったデータを用いてモデルを評価することによって、過学習を防止することができます。

ブースティングは、前のモデルの誤差に着目して、その誤差に対して重点的に学習することで、より精度の高い予測モデルを作り上げる手法です。一般的に、アダブーストやグラジエントブースティングがよく知られています。

スタッキングは、複数のモデルを段階的に組み合わせる手法で、まずは複数の異なるモデルを用意して、それぞれのモデルに対して予測を行います。次に、それらの予測結果を入力として、別のモデルを作り上げます。最終的に、このモデルを用いて予測を行います。スタッキングは、個別のモデルの弱点を補い、より高い精度を実現することができます。

アンサンブル学習のメリット、デメリット

アンサンブル学習のメリットは、個々のモデルでは解決できない問題をアンサンブルによって解決できることがある点です。複数のモデルを組み合わせることによって、予測の精度や安定性を向上させることができます。

一方、アンサンブル学習のデメリットとしては、計算リソースの消費量が増加することや、モデルの解釈が難しくなることが挙げられます。また、モデルを組み合わせることで、モデルごとの特徴が薄れ、一般化性が低下することがある点もあります。

単純平均

単純平均は、複数のモデルを用いて予測値を算出するアンサンブル方法の一つです。単純平均では、複数のモデルが出力した予測値の平均値を最終的な予測値として用います。

単純平均のメリットは、以下の通りです。

  • 複数のモデルを用いることで、予測の精度が向上することがある。
  • モデルごとに異なる特徴を持っているため、予測の多様性が増すことがある。
  • モデルの予測値を平均するため、過学習に陥りにくい。

一方、デメリットとしては、以下のようなものがあります。

  • 複数のモデルを用いるため、モデルの数が増えることによる計算コストの増大が考えられる。
  • 複数のモデルを用いるため、モデルのパラメータ数が増えることによる過学習のリスクがある。
  • 複数のモデルを用いることで、モデルの解釈性が低下することがある。

アンサンブル(単純平均)の例

■3モデルの予測値を持つデータフレームを乱数で作成

単純平均によるアンサンブルは、複数のモデルの予測結果を平均することで、より安定した予測結果を得る手法です。

以下は、3つのモデルの予測値を持つデータフレームを乱数で作成し、単純平均によるアンサンブルを実施する例です。

import numpy as np
import pandas as pd

# 3つのモデルの予測値を持つデータフレームを作成(乱数)
model1_pred = np.random.randint(0, 10, 5)
model2_pred = np.random.randint(0, 10, 5)
model3_pred = np.random.randint(0, 10, 5)

df_pred = pd.DataFrame({'model1': model1_pred, 'model2': model2_pred, 'model3': model3_pred})

# 各モデルの予測結果を平均する
ensemble_pred = df_pred.mean(axis=1)

# 結果を表示
print(df_pred)
print(ensemble_pred)

出力結果:

model1 model2 model3
0 1 4 6
1 9 9 3
2 3 7 1
3 8 2 9
4 9 1 6

0 3.666667
1 7.000000
2 3.666667
3 6.333333
4 5.333333
dtype: float64

この例では、3つのモデルの予測値を持つデータフレームを作成し、mean()関数を用いて単純平均によるアンサンブルを実施しています。

重み付け平均

重み付け平均 (Weighted Average) は、複数のモデルの予測値を単純に平均するのではなく、それぞれのモデルの性能に応じて重み付けを行い、加重平均を求める手法です。

重み付け平均のメリットは、複数のモデルを組み合わせることによって、単一のモデルよりも高い予測精度を得ることができることです。また、異なるモデルの弱点を補完し、汎用性を高めることができます。

一方で、重み付けの方法によっては、過学習を引き起こすことがあります。また、複数のモデルを組み合わせることで、モデルの解釈性が低下することがあります。

重み付け平均の式は以下のようになります。

$y_{ensemble} = \sum_{i=1}^{n} w_i y_i$

ここで、$y_{ensemble}$はアンサンブルモデルの予測値、$y_i$は$i$番目のモデルの予測値、$w_i$は$i$番目のモデルに与える重みです。$w_i$は、モデルの性能や信頼度に応じて設定されます。一般的には、重みは交差検証などを用いてチューニングされます。

重み付き平均によるアンサンブルは、各モデルの予測値に重みを掛けた後、それらを合計する方法です。各モデルの性能や信頼度に応じて、重みを調整することができます。

以下は、3つのモデルの予測値に重みを掛けた後、合計する方法の例です。

import pandas as pd

# 3つのモデルの予測値を持つデータフレームを作成する
model1_pred = [0.8, 0.3, 0.6, 0.7, 0.2]
model2_pred = [0.7, 0.2, 0.5, 0.6, 0.1]
model3_pred = [0.6, 0.1, 0.4, 0.5, 0.05]
pred_df = pd.DataFrame({'model1': model1_pred, 'model2': model2_pred, 'model3': model3_pred})
print(pred_df)

# 各モデルの重みを定義する
weights = [0.4, 0.3, 0.3]

# 重み付き平均によるアンサンブルを行う
ensemble_pred = (pred_df['model1']*weights[0]) + (pred_df['model2']*weights[1]) + (pred_df['model3']*weights[2])

# アンサンブルの結果を表示する
print('Ensemble predictions:')
print(ensemble_pred)

出力結果:

model1 model2 model3
0 0.8 0.7 0.60
1 0.3 0.2 0.10
2 0.6 0.5 0.40
3 0.7 0.6 0.50
4 0.2 0.1 0.05
Ensemble predictions:
0 0.720
1 0.230
2 0.480
3 0.580
4 0.155
dtype: float64

スタッキング

スタッキングは、機械学習モデルを組み合わせて、より高い予測精度を得るアンサンブル手法の1つです。スタッキングでは、個々のモデルを第1段階のモデルとして学習し、その予測値を第2段階のモデルの入力データとして使用します。第2段階のモデルは、第1段階のモデルの予測結果を使って学習されます。

スタッキングのメリットは、複数のモデルを組み合わせることで、個々のモデルよりも高い予測精度を得ることができることです。また、異なる種類のモデルを組み合わせることで、個々のモデルの弱点を補完することができる可能性があります。

一方、スタッキングのデメリットは、計算量が増加することや、モデルの選択やパラメータ調整が難しくなることが挙げられます。また、スタッキングによって過剰適合(オーバーフィッティング)が起こる可能性があるため、注意が必要です。

まず、必要なライブラリをインポートします。

import numpy as np
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from xgboost import XGBRegressor

次に、学習データを読み込みます。ここでは、ボストン市の住宅価格データを使用します。

from sklearn.datasets import load_boston
boston = load_boston()
X, y = boston.data, boston.target

データを訓練用とテスト用に分割します。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

スタッキング用の学習データセットとテストデータセットを作成します。

n_splits = 5
kf = KFold(n_splits=n_splits, shuffle=True, random_state=42)
stacking_train = np.zeros((len(y_train), 3))
stacking_test = np.zeros((len(y_test), 3))

for i, (train_index, val_index) in enumerate(kf.split(X_train, y_train)):
train_X, val_X = X_train[train_index], X_train[val_index]
train_y, val_y = y_train[train_index], y_train[val_index]

model1 = LinearRegression()
model1.fit(train_X, train_y)
stacking_train[val_index, 0] = model1.predict(val_X)
stacking_test[:, 0] += model1.predict(X_test) / n_splits

model2 = DecisionTreeRegressor(max_depth=5, random_state=42)
model2.fit(train_X, train_y)
stacking_train[val_index, 1] = model2.predict(val_X)
stacking_test[:, 1] += model2.predict(X_test) / n_splits

model3 = XGBRegressor(n_estimators=100, max_depth=3, random_state=42)
model3.fit(train_X, train_y)
stacking_train[val_index, 2] = model3.predict(val_X)
stacking_test[:, 2] += model3.predict(X_test) / n_splits

スタッキング用のデータセットからメタモデルを学習します。

meta_model = LinearRegression()
meta_model.fit(stacking_train, y_train)

最後に、メタモデルを使用してテストデータを予測します。

y_pred = meta_model.predict(stacking_test)

以上が、スタッキングによるアンサンブルの例です。


というわけで、今回は以上です。大変お疲れ様でした。
引き続きで、徐々に発信していきます。

コメントや感想を受け付けています。ちょっとした感想でもいいので嬉しいです。

それでは、以上です。

最新情報をチェックしよう!