エクセルに代表される表形式のデータをテーブルデータと呼びます。この記事では、テーブルデータを対象とした定番の機械学習アルゴリズムの実装方法及び、Optunaを用いたハイパーパラメータのチューニング方法を紹介します。
データセットについて
この記事では、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) # 検証データの予測
- 線形回帰モデルの係数
線形回帰モデルの係数は、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回帰の引数
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回帰モデルの係数
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の引数
- 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)}')
- ランダムフォレストの引数
- 特徴の重要度
- ランダムフォレストでは、説明変数ごとの予測への寄与度(説明変数の重要度)を確認できます。
# 説明変数の重要度
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の引数(抜粋)
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'
おまけ:正規方程式と勾配降下法
線形回帰モデル(Ridge回帰やLasso回帰含む)には、コスト関数を最小にする$\theta$の値を直接求める正規方程式が存在します。この正規方程式を用いることで、探索的に最適解を求める代わりに、数学的に直接最適値を導出できます。
ただし、正規方程式を計算するには$X^T \cdot X$の逆行列が必要であり、その計算量は特徴量数に対して指数的に増加してしまいします。
そのため、正規方程式を解く代わりに勾配降下法による探索的な手法も用いられており、どちらの手法が良いかは扱うデータセットによって検討が必要です。
「scikit-learnとTensorFlowによる実践機械学習」の紹介
今回紹介した線形回帰、Ridge回帰、Lasso回帰、Elastic Net、ランダムフォレストの理解と実装において、書籍「scikit-learnとTensorFlowによる実践機械学習」が非常に分かりやすかったので、紹介しておきます。
本書を読むことで、scikit-learnのライブラリを使用する際に必要となる前提知識について学ぶことができるため、独自でモデルのチューニングを行う手助けになると思います。
コメント