【テーブルデータ】定番の機械学習アルゴリズムの使い方まとめ

table_algo_summary scikit-learn

エクセルに代表される表形式のデータをテーブルデータと呼びます。この記事では、テーブルデータを対象とした定番の機械学習アルゴリズムの実装方法及び、Optunaを用いたハイパーパラメータのチューニング方法を紹介します。

この記事で学べる内容
  • テーブルデータ向けの機械学習アルゴリズム(線形回帰, ランダムフォレスト, XGBoostなど)の実装方法

データセットについて

この記事では、scikit-learnで簡単に取得できるボストンの住宅価格データを利用します。

  • scikit-learnによるボストン住宅価格データの取得
from sklearn.datasets import load_boston

boston = load_boston() # ボストン住宅価格データの取得
data = boston['data'] # 説明変数
target = boston['target'] # 目的変数

print(data.shape, target.shape)

# (506, 13) (506,)

データを取得できたら、次にtrain_test_spilt()関数を用い学習データと検証データを分離しておきます。

from sklearn.model_selection import train_test_split

xs, xs_valid, ys, ys_valid = train_test_split(data, target)
# xs, ys: 学習データ
# xs_valid, ys_valid: 検証データ

print(xs.shape, xs_valid.shape, ys.shape, ys_valid.shape)
# (379, 13) (127, 13) (379,) (127,)

これで学習データ(xs, ys)と、検証データ(xs_valid, ys_valide)の準備が完了しました。
また、

アルゴリズムの実装方法

テーブルデータの機械学習における定番のアルゴリズムを紹介します。
kaggleなどのデータサイエンスのコンペティションではXGBoostやLightGBMといった勾配ブースティングのアルゴリズムが人気です。

評価指標

予測結果の評価方法には、真値と予測結果の差分(誤差)の絶対値の平均Mean Absolute Error(MAE)や、誤差の2乗の平方根Root Mean Squared Error(RMSE)など様々な指標があります。
この記事では、scikit-learnが提供しているMAEを利用します。

from sklearn.metrics import mean_absolute_error as mae

線形回帰

線形回帰では、重み付けしたバイアス項($\theta_0$)と説明変数($\theta_ix_i$)の和を用い、目的変数の予測(回帰分析)を行うモデルを構築します。

  • 線形回帰モデル

$$ \hat{y} = \theta_0 + \theta_1 x_1 + \theta_2 x_2 + \cdots + \theta_n x_n$$

  • scikit-learnによる線形回帰モデルの実装
from sklearn.linear_model import LinearRegression

model = LinearRegression()
model.fit(xs, ts) # モデル学習

ys_valid = model.predict(xs_valid) # 検証データの予測
  • 引数
    • fit_intercept: 切片を使用するかを指定。デフォルト=True
    • normalize: 入力Xを正規化するかを指定。fit_intercept=Trueの場合に有効、デフォルト=False
  • 線形回帰モデルの係数

線形回帰モデルの係数は、coef_属性(($\theta_i, i \neq 0$))intercept_属性($\theta_0$)から確認できます。

print(f'coefficient: {model.coef_}') # モデルの係数
print(f'intercept: {model.intercept_}') # モデルの切片

# coefficient: [-7.21213036e-02  3.78200228e-02  4.11169066e-02  3.38988096e+00
#  -1.82004469e+01  4.37822777e+00 -1.11305172e-02 -1.34646662e+00
#   2.63968602e-01 -1.27300068e-02 -9.11833000e-01  1.00175626e-02
#  -4.07895159e-01]
# intercept: 31.00919287802391

リファレンス:線形回帰

coef_属性では、説明変数の種類の数(例では13種)だけ結果が得られます。

線形回帰では学習データに過剰に適応する過学習が起こります。そこで過学習を抑制するために、線形回帰に正則化項(モデルへの制約)を追加した手法として、Ridge回帰Lasso回帰Elastic Netがあります。

Ridge回帰

線形回帰の学習時にL2正則化項$ \alpha \sum_{i=1}^{n}\theta^2_i $を追加したのがRidge回帰です。正則化項の追加は、モデルの主に対する制限をかけることになるため、モデルの過学習が抑制されます。

  • scikit-learnによるRIdge回帰モデルの実装
from sklearn.linear_model import Ridge

model = Ridge(alpha=0.2)
model.fit(xs, ts)

ys_valid = model.predict(xs_valid) # モデル学習

print(ys_valid[:10])
print(ts_valid[:10])

print(f'mae: {mae(ys_valid, ts_valid)}')
  • Ridge回帰の引数
  • alpha: L2正則化項の重み$\alpha$
  • max_iter: 最大反復回数
  • fit_intercept: 切片を使用するか。デフォルト=True
  • normalize: 入力Xを正規化するかを指定。fit_intercept=Trueの場合に有効、デフォルト=False
  • solver: 最適な係数($\theta$)の探索手法。デフォルト=autoは入力データの種類に応じて自動選択される

リファレンス:Ridge回帰

Ridge回帰も線形回帰同様にモデル係数と切片を得ることができます。

print(f'coefficient: {model.coef_}')
print(f'intercept: {model.intercept_}')

# coefficient: [-7.03912590e-02  3.84352192e-02  3.09217711e-02  3.32428791e+00
#  -1.55181104e+01  4.38485561e+00 -1.37049847e-02 -1.30531520e+00
#   2.56493860e-01 -1.28878289e-02 -8.79934478e-01  1.00954657e-02
#  -4.12053130e-01]
# intercept: 29.17905486372011

Lasso回帰

線形回帰の学習時にL1正則化項($ \alpha \sum_{i=1}^{n}|\theta_i| $)を追加したのがLasso回帰です。

  • scikit-learnによるLasso回帰モデルの実装
sklearn.linear_model.Lasso

model = Ridge(alpha=0.2)
model.fit(xs, ts)

ys_valid = model.predict(xs_valid)

引数

  • alpha: L1正則化項の重み$\alpha$
  • fit_intercept: 切片を使用するか。デフォルト=True
  • normalize: 入力Xを正規化するかを指定。fit_intercept=Trueの場合に有効、デフォルト=False
  • max_iter: 最大反復回数
  • tol: 最適化の許容誤差。反復結果がtolより小さくなった場合、双対性ギャップを確認しより誤差の小さい結果を探索する。デフォルトはtol=0.0001
  • positive: 係数を正の数に限定するかを指定
  • selection: 反復時の係数の選択方法

リファレンス:Lasso回帰

  • Lasso回帰モデルの係数
print(f'coefficient: {model.coef_}')
print(f'intercept: {model.intercept_}')

Elastic Net

Elastic Netは、Ridge回帰とLasso回帰の中間的な位置付けで、正則化項としてL1正則化項とL2正則化項を混ぜ合わせた $r \alpha \sum_{i=1}^{n}|\theta_i| + \frac{1-r}{2} \alpha \sum_{i=1}^{n}\theta^2_i$ を用います。
rを調整することでL1とL2の混ぜ合わせ度合いを調整し、r=0の場合はRidge回帰、r=1の場合はLasso回帰と等しくなります。

  • scikit-learnによるElastic Netの実装
from sklearn.linear_model import ElasticNet
model = ElasticNet(alpha=0.2)
model.fit(xs, ts)

ys_valid = model.predict(xs_valid)

print(f'mae: {mae(ys_valid, ts_valid)}')
  • Elastic Netの引数
  • alpha: 正則化項の重み$\alpha$
  • l1_ratio: L1正則化とL2正則化の重みr
  • fit_intercept: 切片を使用するかを指定。デフォルト=True
  • normalize: 入力Xを正規化するかを指定。fit_intercept=Trueの場合に有効、デフォルト=False
  • max_iter: 最大反復回数
  • tol: 最適化の許容誤差。反復結果がtolより小さくなった場合、双対性ギャップを確認し、より誤差の小さい結果を探索する。デフォルトはtol=0.0001
  • positive: 係数を正の数に限定するかを指定
  • selection: 反復時の係数の選択方法
  • Elastic Netの係数
print(f'coefficient: {model.coef_}')
print(f'intercept: {model.intercept_}')

# coefficient: [-0.07163301  0.04678398 -0.01569789  0.52660146 0 2.95293733
#  -0.01358388 -1.00387016  0.25703745 -0.01542844 -0.74269403  0.00988768
#  -0.55154959]
# intercept: 29.366098879207556

ランダムフォレスト

ランダムフォレストは、複数の決定木を学習し、予測のときにはそれらの結果の多数決を取って最終的な予測結果とするアルゴリズムです。

  • scikit-learnによるランダムフォレストの実装
from sklearn.ensemble import RandomForestRegressor

model = RandomForestRegressor(n_estimators=100)
model.fit(xs, ts)

ys_valid = model.predict(xs_valid)

print(f'mae: {mae(ys_valid, ts_valid)}')
  • ランダムフォレストの引数
  • n_estimators: 使用する決定木の数
  • criterion: 分割を判断する際の基準値。msemae
  • max_depth: 決定木の最大の深さ
  • min_samples_split: ノードを分割する際に必要な最小のサンプル数。デフォルト=2
  • min_samples_leaf: 葉ノードに必要な最小のサンプル数。デフォルト=1
  • min_weight_fraction_leaf: 葉ノードに必要な重みの最小比率
  • max_features: 最適な分割を探索する際に考慮される特徴(feature)の数
  • max_leaf_nodes: 最大の葉ノードの数。デフォルト=None
  • min_impurity_decrease: ノードを分割させるための最小の不純度。デフォルト=0
  • 特徴の重要度
    • ランダムフォレストでは、説明変数ごとの予測への寄与度(説明変数の重要度)を確認できます。
# 説明変数の重要度
print(f'feature_importances_: {model.feature_importances_}')

# feature_importances_: [0.03473706 0.0012504  0.00925615 0.00228069 0.02416805 0.30717044
#  0.01658086 0.04940798 0.00311589 0.01954188 0.01789754 0.01378952
#  0.50080353]

リファレンス:ランダムフォレスト

XGBOOST

XGBoostは勾配ブースティングの機械学習フレームワークです。非常に強力なアルゴリズムとしてkaggleなどのデータサイエンスコンペティションでも頻繁に用いられています。

from xgboost import XGBRegressor

model = XGBRegressor()
model.fit(xs, ts)

ys_valid = model.predict(xs_valid)

print(f'mae: {mae(ys_valid, ts_valid)}')
  • XGBoostの引数(抜粋)
  • n_estimators: 使用する勾配ブースト決定木の数。ブースティングラウンド数と等価。
  • max_depth: 決定木の最大の深さ
  • learning_rate: 学習率
  • objective: 目的関数。自作の目的関数を使用することもできる。デフォルト='reg:squarederror'
  • booster: ブースター(gbtree, gblinear, dartから選択)の指定
  • tree_method: 決定木のメソッドの指定。デフォルトではXGBoostが最も安定したメソッドを選択します。詳細はこちら
  • gamma: 葉ノードの分割に必要となる最小の損失削減度合い
  • min_child_weight: 子ノードに必要な最小の重み
  • max_delta_step: 許容する最大の重み変化量
  • reg_alpha: L1正則化の重み
  • reg_lambda: L2正則化の重み
  • scale_pos_weight: 正もしくは負となる重みの比率
  • base_score: 初期の予測スコア
  • missing: 必要な欠損値の数

リファレンス:XGBoost

LightGBM

LightGBMもXGBoost同様にデータ分析コンペで頻出のアルゴリズムで、高速かつメモリ効率も良く高い精度を出せるため人気です。基本的な使い方もXGBoostとほぼ同じです。

import lightgbm as lgb

# ハイパーパラメータの指定
params = {
    'objective': 'regression',
    'metric': 'rmse',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'n_estimators': 100
}

# ハイパーパラメータの設定および、モデル学習
model = lgb.LGBMRegressor(**params)
model.fit(xs, ts)

# モデルによる推論
y_pred = model.predict(xs_valid)

# 評価
print(f'mae: {mae(ys_valid, ts_valid)}')

っx

  • objective:
    • 説明: 目的関数の指定する。LightGBMは多くの目的関数をサポートしており、回帰、分類、ランキングなどのタスクに対応
    • 例: 'regression'(回帰)、'binary'(2クラス分類)、'multiclass'(多クラス分類)
  • metric
    • 説明: モデル学習中に用いられる評価指標を指定する。MSEやMAEなどが設定できる。
  • num_leaves:
    • 説明: 木の葉ノード(leaf)の最大数を設定する。大きい値はモデルの複雑さを増加させ、過剰適合のリスクが高まる。
  • learning_rate:
    • 説明: 勾配降下法の学習率を指定する。小さい値を選ぶと、学習が安定しますが、収束に時間がかかる可能性がある。
  • n_estimators:
    • 説明: ブーストラウンド(Boosting Rounds)の反復回数を指定する。大きい値を設定すると、モデルの性能が向上するが、過学習のリスクも高まる。
  • max_depth:
    • 説明: 決定木の最大深さを指定する。決定木が深いほどモデルは複雑になり、過学習のリスクが高まる。
  • min_child_samples:
    • 説明: 一つの葉ノードに必要な最小サンプル数を指定する。これにより、過学習を抑制する。例: 20
  • feature_fraction:
    • 説明: トレーニングデータの特徴量の一部をランダムに選択する割合を指定。これは特徴量サブサンプリング(Feature Subsampling)と呼ばれ、過学習を抑制するのに役立つ。例: 0.8
  • bagging_fraction:
    • 説明: トレーニングデータのサブサンプルの割合を指定する。例: 0.8
  • boosting_type:
    • 説明: ブースティングのタイプを指定する。通常は'gbdt'(Gradient Boosting Decision Tree)を選択するが、'dart'や'goss'などの異なるブースティング手法も選べる。例: 'gbdt'

リファレンス:LightGBM

おまけ:正規方程式と勾配降下法

線形回帰モデル(Ridge回帰やLasso回帰含む)には、コスト関数を最小にする$\theta$の値を直接求める正規方程式が存在します。この正規方程式を用いることで、探索的に最適解を求める代わりに、数学的に直接最適値を導出できます。
ただし、正規方程式を計算するには$X^T \cdot X$の逆行列が必要であり、その計算量は特徴量数に対して指数的に増加してしまいします。
そのため、正規方程式を解く代わりに勾配降下法による探索的な手法も用いられており、どちらの手法が良いかは扱うデータセットによって検討が必要です。

「scikit-learnとTensorFlowによる実践機械学習」の紹介

今回紹介した線形回帰、Ridge回帰、Lasso回帰、Elastic Net、ランダムフォレストの理解と実装において、書籍「scikit-learnとTensorFlowによる実践機械学習」が非常に分かりやすかったので、紹介しておきます。
本書を読むことで、scikit-learnのライブラリを使用する際に必要となる前提知識について学ぶことができるため、独自でモデルのチューニングを行う手助けになると思います。

参考リンク

コメント

タイトルとURLをコピーしました