カニゲーム攻略日記ブログ

beatmaniaIIDXやハースストーンなどのゲーム攻略日記。主にまったり勢。2016年にIIDX皆伝になった

kaggle expert を目指す 5 カニ完

今回のカニの年齢当てゲームは終わりました

www.kaggle.com

上記の方を参考(コピペ)にさせて頂き
勾配ブースティングをやったところスコアが上がりまくった

得点
ALL 10 2.3
RandomForestClassifier 1.7
LinearRegression 1.6
勾配ブースティング 1.3

勾配ブースティングについては
ほぼ理解していないので
今後、分かるところからやる予定

contents

Regression with a Crab Age Dataset

EDA 1

# 一応欠損値の有無を可視化します
# Search for missing data

msno.matrix(df=data_all, figsize=(10,6), color=(0,.3,.3))

feat_ary = data_all.drop(columns=['id', 'Age']).columns
feat_ary

# Sex : 性別
# Length : 長さ
# Diameter : 直径
# Height : 高さ
# Weight : 重量
# Shucked Weight : 殻をむいた重量
# Viscera Weight : 内臓重量
# Shell Weight : 殻の重量

data_all[feat_ary].describe().T\
        .style.bar(subset=['mean'], color=px.colors.qualitative.G10[0])\
        .background_gradient(subset=['std'], cmap='Greens')\
        .background_gradient(subset=['50%'], cmap='BuGn')

このコードは、データセットの欠損値の有無の可視化と各特徴量の基本的な統計情報の表示を行っています。

まず始めに、msno.matrix(df=data_all, figsize=(10,6), color=(0,.3,.3))この部分で、msno(missingno)というライブラリを用いて、データフレームdata_all内の欠損値の有無をマトリックス形式で可視化しています。各行が各観測値を、各列が各特徴量を示し、白い部分が欠損値を表します。欠損値のパターンや分布を一目で確認できます。

その後、feat_ary = data_all.drop(columns=['id', 'Age']).columnsでデータフレームから'id'と'Age'という列をドロップし、残った列の名前をfeat_aryに格納しています。

そして、data_all[feat_ary].describe().Tfeat_aryに含まれる各特徴量についての基本的な統計量(数値、平均、標準偏差、最小値、四分位数、最大値など)を計算し、転置しています。

最後に、.style.bar(subset=['mean'], color=px.colors.qualitative.G10[0])\ .background_gradient(subset=['std'], cmap='Greens')\ .background_gradient(subset=['50%'], cmap='BuGn')の部分では、pandas の Style メソッドを使用して、データフレームの表示をカスタマイズしています。具体的には、平均値を棒グラフで、標準偏差と中央値(50%四分位数)を色付きの背景グラデーションで表示しています。これにより、これらの統計量の違いを視覚的に理解しやすくしています。

このようなEDA(Exploratory Data Analysis)は、データの理解を深め、前処理の方針を立てる上で非常に有用です。

EDA 2

# 特徴量ごとの分布を可視化
# Visualization of distribution for each feature

figure = plt.figure(figsize=(16, 18))
count = 0
for i in range(len(feat_ary)):
    feat_name = feat_ary[i]
    plt.subplot(5, 2, count+1)
    plt.hist(data_all[feat_name], bins=100)
    plt.title(f'{feat_name}')
    count += 1
figure.tight_layout(h_pad=1.0, w_pad=0.8)
plt.show()

# Ageの分布を可視化
# Histogram of 'Age'

sns.displot(data_all['Age'], height=10)
plt.show()

df_all_data = pd.DataFrame(data = data_all, columns = ['Length', 'Diameter', 'Height'])
plt.figure(figsize=(20,10)) 
sns.boxplot(x="variable", y="value", data=pd.melt(df_all_data)).set_title('Boxplot of each feature',size=15)
plt.xticks(rotation=45)
plt.show()

df_all_data = pd.DataFrame(data = data_all, columns = ['Weight', 'Shucked Weight', 'Viscera Weight', 'Shell Weight'])
plt.figure(figsize=(20,10)) 
sns.boxplot(x="variable", y="value", data=pd.melt(df_all_data)).set_title('Boxplot of each feature',size=15)
plt.xticks(rotation=45)
plt.show()

このコードでは、各特徴量の分布をヒストグラムとボックスプロットで可視化しています。

最初のループでは、feat_aryに格納された各特徴量のヒストグラムをプロットしています。plt.hist(data_all[feat_name], bins=100)で各特徴量のヒストグラムを作成(bin数は100)、plt.title(f'{feat_name}')で各プロットのタイトルに特徴量の名前を設定しています。

その次のsns.displot(data_all['Age'], height=10)で、特徴量'Age'の分布を seaborn の displot 関数を用いて可視化しています。

そして、pd.DataFrame(data = data_all, columns = ['Length', 'Diameter', 'Height'])で'Length', 'Diameter', 'Height'の3つの特徴量を抽出し、新しいデータフレームdf_all_dataを作成しています。sns.boxplot(x="variable", y="value", data=pd.melt(df_all_data))では、このデータフレームをpd.melt()関数で溶解し(各列を縦に並べ、それぞれの変数と値のペアを作成)、それぞれの特徴量に対するボックスプロットを作成しています。

最後の部分も同様で、今度は'Weight', 'Shucked Weight', 'Viscera Weight', 'Shell Weight'の4つの特徴量についてボックスプロットを作成しています。

ヒストグラムは各特徴量の分布を、ボックスプロットは各特徴量の四分位数や外れ値を視覚化するのに役立つため、これらのプロットはデータの全体像を理解するのに非常に有用です。

EDA 3

# データをトレーニング用と予測用に分けます
# Split train and test

train = data_all.iloc[data_t_o.index[0]:data_t_o.index[-1]+1]
test = data_all.iloc[data_t_o.index[-1]+1:]

# 外れ値のデータを削除
# Remove outliers

#train = train.drop(train[train['Length'] <= 0.1875].index)
#train = train.drop(train[train['Diameter'] < 0.4].index)
train = train.drop(train[train['Height'] > 1.0].index)
train = train.drop(train[train['Weight'] > 78].index)
train = train.drop(train[train['Shucked Weight'] > 39].index)
train = train.drop(train[train['Viscera Weight'] > 20].index)
train = train.drop(train[train['Shell Weight'] > 28].index)
train

#Heatmap(train)

corr = train.drop(columns=['id']).corr().round(2)
plt.figure(figsize=(20,10))
sns.heatmap(corr, vmin=-1, vmax=1, center=0, square=False, annot=True, cmap='coolwarm')
plt.show()

#Heatmap(test)

corr = test.drop(columns=['id', 'Age']).corr().round(2)
plt.figure(figsize=(20,10))
sns.heatmap(corr, vmin=-1, vmax=1, center=0, square=False, annot=True, cmap='coolwarm')
plt.show()

このコードでは、最初にデータを訓練用とテスト用に分割しています。ilocを使用して、元のデータフレームdata_allの一部を抽出し、新たにtraintestの2つのデータフレームを作成しています。

次に、特定の条件を満たす行(つまり外れ値)を訓練データから削除しています。これは、特定の特徴量('Height'、'Weight'、'Shucked Weight'、'Viscera Weight'、'Shell Weight')の値が特定の閾値を超える行を指定して削除しています。

その後、特徴量間の相関行列を計算し、それをヒートマップとして可視化しています。sns.heatmap関数は、各特徴量間の相関を色で表現するので、特徴量間の関係性を一覧できるため、特徴選択や多重共線性のチェックに役立ちます。vminvmaxの値を-1と1に設定することで、相関の範囲を-1(完全な負の相関)から1(完全な正の相関)に制限しています。また、annot=Trueオプションを用いて、各セルに値を表示しています。

訓練データとテストデータの両方に対して相関行列のヒートマップを作成していますが、テストデータからはターゲット変数である'Age'を除いています。これは、テストデータにはターゲット変数の値が含まれていない(または含まれていても分析には利用しない)ためです。

ヒートマップ

もちろんです、ヒートマップを簡単に説明しますね。

ヒートマップは、色を使って情報を見せる地図のようなものです。データの大きさや関係性を色で表示します。色が濃いほど値が大きく、色が薄いほど値が小さいという風に解釈します。

例えば、クラスで各生徒がテストで何点取ったかをヒートマップで表示するとします。100点満点のテストで、Aさんが100点、Bさんが70点、Cさんが50点取りました。この時、ヒートマップではAさんのところは一番暗い色(または一番明るい色)、Cさんのところは一番薄い色(または一番暗い色)で、Bさんのところはその中間の色になります。

このプログラムのヒートマップでは、色の濃淡が特徴の間の関係性(相関)を表しています。一つの特徴が増えるともう一つの特徴も増える関係(正の相関)を表す場合、色が明るくなります。一方、一つの特徴が増えるともう一つの特徴が減る関係(負の相関)を表す場合、色が暗くなります。色が中間的な値(灰色など)である場合、その二つの特徴間にはあまり関係がない(相関が0に近い)ことを表しています。

このように、ヒートマップは色を使ってたくさんの情報を一度に見ることができる便利なツールです。

Modeling 1

X = train.drop(columns=['id', 'Age'])
value = train['Age']

# ========================================================================
# 設定
# Setting
# ========================================================================

# 処理コースの選択
# Select processing course
procC = 4 # 1:optunaを使用しない単一モデル(single model unusing optuna)
          # 2:optunaのベストスコアを使用した単一モデル(single model using the best optuna score)
          # 3:optunaを使用し複数モデルの結果をアンサンブル(ensemble result of multiple model using optuna)
          # 4:optunaを使用せず複数モデルの結果をアンサンブル(ensemble result of multiple model unusing optuna)

# optunaを回す回数を指定
# Specify round times for optuna
round_opt = 10

# optunaのターゲットスコアを指定
# Specify a target score for optuna
opt_tscore = 1.36

# GPUを使うかどうかを指定(使うときはACCELERATORを指定する)
# usingGPU(Using GPU or not)
usingGPU = 'n' # 'y' or other

# params

objective = "regression_l1" # regression
metric = "mae" # このコンペでは「mae」で評価されます(mae = l1)
test_size = 0.2

このPythonスクリプトでは、モデルの設定と学習のためのパラメータを指定しています。以下に、各部分の詳細を説明します。

  • X = train.drop(columns=['id', 'Age'])value = train['Age']: この2行では、機械学習モデルの訓練用データを作成しています。Xは説明変数(特徴量)で、'id'と'Age'列を除いたすべての列が含まれています。一方、valueは目的変数(予測したい値)で、'Age'列を指定しています。

  • procC = 4: この行では、モデルの設定を選択しています。4つの選択肢があり、4を選んだ場合は、Optunaを使用せずに複数のモデルの結果をアンサンブル(複数のモデルの予測を組み合わせる手法)するという意味です。

  • round_opt = 10: Optunaの最適化プロセスを実行する回数を指定しています。Optunaはハイパーパラメータ最適化のためのライブラリで、この数値は最適化の試行回数を指定します。

  • opt_tscore = 1.36: これはOptunaの最適化プロセスの目標スコアを指定しています。この値を下回るモデルパラメータが見つかった場合、最適化は早期に終了します。

  • usingGPU = 'n': この行では、学習プロセスにGPUを使用するかどうかを指定しています。値が'y'の場合はGPUを使用し、それ以外の値の場合はCPUを使用します。

  • objective = "regression_l1", metric = "mae", test_size = 0.2: これらの行では、モデルの学習パラメータを設定しています。objective機械学習タスクの種類を指定し、regression_l1はL1正則化付きの回帰タスクを指定します。metricはモデルの性能を評価するためのメトリックで、maeは平均絶対誤差を意味します。test_sizeはデータセットを訓練用とテスト用に分割する際のテスト用データの割合を指定します。

Optuna

もちろんです!Optunaというのは、一種の「探検家」のようなものと考えると分かりやすいです。

あなたが宝探しをするとき、ある地点からスタートし、何かヒントやサインに従って最高の宝を探し出しますよね。ただし、どの方向に進むべきか、またどのくらい進むべきかは最初は分からないため、試行錯誤することになります。

Optunaもそのようなものです。コンピュータプログラムや機械学習モデルには「ハイパーパラメータ」というものがあり、これは各モデルがどのように動作するかを調整するための「ノブ」や「スイッチ」のようなものと考えてください。しかし、これらの最適な設定(つまり、モデルが最高の性能を発揮する設定)を見つけるのは非常に難しく、手作業で行うには時間がかかりすぎます。

そこでOptunaが役立ちます。Optunaは「探検家」として、可能なハイパーパラメータの設定を試し、最高の性能(「宝」)を出す設定を見つけ出します。このように、Optunaは最高の性能を出すハイパーパラメータの設定を見つけ出すための強力なツールとなるのです。

したがって、Optunaはまるで賢い探検家のようなもので、最善の答えを見つけるためにさまざまな可能性を試してくれます。

勾配ブースティング

サッカーチームの例を使って説明しますね。

勾配ブースティングは、サッカーチームの試合で上手くいかなかったことを少しずつ改善していく方法に似ています。

  1. まず、初めての試合をします。結果は完全には上手くいきません。得点は取れたけど、守備で何度もミスをしてしまい、たくさん点を取られてしまったとしましょう。

  2. 次の試合では、前回の試合で上手くいかなかった部分、つまり守備のミスを改善しようとします。守備の練習を増やし、新しい戦略を立てます。こうして、2回目の試合では守備が少し改善されます。

  3. でもまだ完璧ではないので、また試合をして、どの部分が上手くいかなかったかを見つけます。それをまた改善し、さらに次の試合でパフォーマンスを上げます。

このサイクルを繰り返すことで、チームはどんどん上手くなり、強くなるはずです。

勾配ブースティングもこれと同じ考え方です。初めての「試合」は最初の予測モデルを作ることです。そして、そのモデルが間違えたところを見つけて、その部分を改善する新しいモデルを作ります。そして、これを繰り返すことで、全体の予測モデルを徐々に良くしていきます。

つまり、勾配ブースティングは「失敗から学び、その失敗を直す」という方法で、予測のパフォーマンスを少しずつ上げていく方法です。

Modeling 2

# optuna

def tuneParam(X, value, test_size, usingGPU):
    if usingGPU == 'y':
        opt_params = {
            'device': 'gpu',
            "objective" : objective,
            "metric" : metric
        }
    else:
        opt_params = {
            "objective" : objective,
            "metric" : metric
        }


    X_train,X_test,y_train,y_test = train_test_split(
        X,
        value,
        test_size = test_size
    )

    reg_train = lgb.Dataset(
        X_train,
        y_train
    )

    reg_eval = lgb.Dataset(
        X_test,
        y_test,
        reference = reg_train
    )

    opt = lgbo.train(
        opt_params,
        reg_train,
        valid_sets = reg_eval,
        verbose_eval = False,
        num_boost_round = 100,
        early_stopping_rounds = 100
    )
    return opt

このPythonスクリプトは、機械学習のモデルのパラメータを最適化するための関数tuneParam()を定義しています。この関数は、特徴量X、ターゲット変数value、テストサイズtest_size、そしてGPUの使用可否を指定するusingGPUの4つの引数を取ります。

以下に、各部分の詳細を説明します:

  1. if usingGPU == 'y'GPUの使用を指定します。usingGPU'y'の場合、device'gpu'としてパラメータ設定します。そうでない場合は、パラメータにdeviceを含めません。

  2. train_test_split:データセットを訓練データとテストデータに分割します。test_sizeはテストデータの割合を示しています。

  3. lgb.Dataset:LightGBMで使用するために、訓練データとテストデータを特別なデータセット形式に変換します。reference引数は、テストデータセットが訓練データセットと同じ特徴を持つことを確認するために使用されます。

  4. lgbo.train:モデルの訓練を行います。引数として最適化のパラメータ(opt_params)、訓練データ(reg_train)、検証用データセットreg_eval)、そしてその他のハイパーパラメータを渡します。

最終的に、この関数は最適化されたモデル(opt)を返します。このモデルは、後続の予測作業に使用されます。

なお、この関数はOptunaを利用したハイパーパラメータの最適化を行っていません。代わりに、LightGBMの早期停止機能を利用しています。これは、訓練の進行に伴って検証用データセットの性能が改善しなくなった場合に訓練を早期に終了させる機能です。早期停止のラウンド数は100に設定されています。

Modeling 3

%%time

if procC == 1:
    count = 1
elif procC == 2 or procC == 3:
    #score = 401
    count = 0
    param_ary = []
    for i in range(round_opt):
        opt = tuneParam(X, value, test_size, usingGPU)
        score = opt.best_score['valid_0']['l1']
        innerAry = {'score' : score, 'params' : opt.params}
        print('')
        print('=' * 100)
        print('val_score : {}'.format(score))
        print('params : {}'.format(opt.params))

        if score < opt_tscore:
            param_ary.append(innerAry)
            count += 1
            print('Succeed')
        else:
            print('Low Score')

        print(f'Round : {i+1} / {round_opt}')
        print('=' * 100)
        print('')

このコードは、機械学習モデルのハイパーパラメータを調整するための処理を行っています。特に、上述のOptunaというフレームワークを用いて最適なパラメータを探索しています。

このプログラムは主に以下のステップで動作します:

  1. procCに応じて、countの初期値を設定します。これは後続の処理のための条件設定です。

  2. procCが1以外の場合、以下の処理が繰り返されます:

    • round_opt回数分、Optunaを使って最適なパラメータを探索します(これがforループの部分です)。
    • 各ラウンドで、tuneParam関数を呼び出して最適なパラメータを探し、その結果として得られるスコアをscoreに格納します。
    • 得られたスコアとハイパーパラメータを表示し、スコアが目標値opt_tscoreよりも低い(つまり良い)場合は、そのパラメータをparam_aryに保存します。その際にcountを1増やします。
    • スコアが目標値よりも高い(つまり悪い)場合は、その旨を表示します。
    • 各ラウンドの結果と進行状況を表示します。

このコードの目的は、機械学習モデルのパフォーマンスを最適化するためのハイパーパラメータを探索し、それらのパラメータを保存することです。このようにして、最適なパラメータを使ってモデルを訓練することで、未知のデータに対する予測精度を向上させることが可能となります。

Modeling 4

# Params
if procC == 2 or procC == 3:
    if count > 0:
        for i in range(len(param_ary)):
            params = param_ary[i]
            print('')
            print(f'【Param_{i+1}】')
            print(params)
            print('')

        df_params = pd.DataFrame(param_ary)
        df_params.to_csv('/kaggle/working/params.csv')
    else:
        print('Missing parameter due to low score !!')

このコードブロックは、Optunaを使用して調整されたハイパーパラメータの結果を表示し、それらをCSVファイルとして保存する部分です。

コードは以下のように機能します:

  1. procCが2または3で、そして前段階で目標のスコアを下回った(良い結果が得られた)パラメータが存在する場合(つまり、count > 0)に実行されます。

  2. 各パラメータセットについて、その情報を印刷します。これには、それぞれのパラメータセットとそれに対応するスコアが含まれます。

  3. すべてのパラメータセットとそのスコアをparam_aryからpandasのDataFrameへ変換します。

  4. このDataFrameをparams.csvという名前のCSVファイルとして保存します。これにより、後からこのパラメータセットを読み込んで再利用することができます。

  5. count > 0が満たされない(つまり、目標スコアを下回る結果が一つも得られなかった)場合は、エラーメッセージが表示されます。

このコードの目的は、最適化されたパラメータセットを保存して、後で使用するために容易にアクセスできるようにすることです。これにより、モデルのトレーニング時にこれらの最適なパラメータを再利用し、モデルの性能を改善することが可能となります。

Learning and prediction 1

# modeling

def learn_model(X, value, test_size, params):
    learning_rate = 0.0001 # 0.0003
    num_iterations = 300000
    max_depth = -1

    X_train, X_test, t_train, t_test = train_test_split(X, value, test_size=test_size, random_state=0)

    lgb_train = lgb.Dataset(X_train, t_train)
    lgb_eval = lgb.Dataset(X_test, t_test, reference=lgb_train)

    if usingGPU == 'y':
        device = 'gpu'
    else:
        device = ''

    params = {
        'device': device,
        'task': 'train',
        'objective': objective,
        'metric': metric,
        'boosting_type': 'gbdt',
        'learning_rate': learning_rate,
        'num_iterations': num_iterations,
        'max_depth': max_depth,
        'feature_pre_filter': params['feature_pre_filter'],
        'lambda_l1': params['lambda_l1'],
        'lambda_l2': params['lambda_l2'],
        'num_leaves': params['num_leaves'],
        'feature_fraction': params['feature_fraction'],
        'bagging_fraction': params['bagging_fraction'],
        'bagging_freq': params['bagging_freq'],
        'min_child_samples': params['min_child_samples'],
        'verbosity': -1
    }


    evaluation_results = {}                       # 学習の経過を保存する
    model = lgb.train(
        params,
        valid_names=['train', 'valid'],           # 学習経過で表示する名称
        valid_sets=[lgb_train, lgb_eval],         # モデル検証のデータセット
        evals_result=evaluation_results,          # 学習の経過を保存
        train_set=lgb_train,
        early_stopping_rounds=1000,#100
        verbose_eval=1000
    )
    model_ary = {'evaluation_results' : evaluation_results, 'model' : model}
    return model_ary

このコードはLightGBMというツリーベースの勾配ブースティングアルゴリズムを用いてモデルの学習を行う部分です。以下にその詳細を説明します。

  1. learn_modelという関数が定義されています。この関数は入力として特徴量(X)、目標変数(value)、テストサイズ(test_size)、ハイパーパラメータ(params)を受け取ります。

  2. その後、学習率(learning_rate)、反復回数(num_iterations)、ツリーの深さ(max_depth)などのハイパーパラメータを定義します。

  3. 次に、データセットが学習用とテスト用に分割されます。これにより、モデルは一部のデータで学習し、未見のデータでどの程度性能を発揮するかを評価します。

  4. それぞれのデータセットをLightGBMが読み込める形式に変換します。

  5. もしGPUを使用する場合は、deviceパラメータを'gpu'に設定します。

  6. LightGBMの学習のためのパラメータ設定を行います。ここでは、目的変数、評価指標、学習率、反復回数、木の最大深度、正則化パラメータ等を設定します。

  7. lgb.trainメソッドを用いてモデルを学習します。学習の過程(evaluation_results)やモデルそのもの(model)を保存します。学習途中の評価は学習データと検証データの両方で行われ、学習が進行しなくなった場合(早期終了)や一定間隔での進行状況を表示します。

  8. 最後に、学習の評価結果とモデル自体を含むディクショナリを返します。

この関数は、パラメータを指定してモデルを学習し、モデルの性能を評価するための一連のプロセスを実装しています。

Learning and prediction 2

# 学習過程を可視化

def show_train_result(evaluation_results):
    plt.plot(evaluation_results['train']['l1'], label='train')
    plt.plot(evaluation_results['valid']['l1'], label='valid')
    plt.ylabel(metric)
    plt.xlabel('Boosting round')
    plt.title('Training performance')
    plt.legend()
    plt.show()

# Feature importance

def show_feature_importance(model):
    fig, ax = plt.subplots(figsize=(10, 8))
    lgb.plot_importance(model, ax=ax)
%%time

result_ary = []

if procC == 1:
    params = {
        'feature_pre_filter': False,
        'lambda_l1': 6.826353667659448,
        'lambda_l2': 1.0314685004038362e-05,
        'num_leaves': 93,
        'feature_fraction': 0.7,
        'bagging_fraction': 1.0,
        'bagging_freq': 0,
        'min_child_samples': 100
    }
    model_ary = learn_model(X, value, test_size, params)
    evaluation_results = model_ary['evaluation_results']
    model = model_ary['model']
    show_train_result(evaluation_results)
    show_feature_importance(model)
    result = model.predict(test.drop(columns=['id', 'Age']))
    result_ary.append(result)
elif procC == 2:
    if count > 0:
        # ベストパラメーターの選択
        # Choose the best param
        sorted_ary = sorted(param_ary, key=lambda x: x['score']) # scoreでソート
        print('Best Optuna Params')
        print(sorted_ary[0])
        print()
        params = sorted_ary[0]['params']
        model_ary = learn_model(X, value, test_size, params)
        evaluation_results = model_ary['evaluation_results']
        model = model_ary['model']
        show_train_result(evaluation_results)
        show_feature_importance(model)
        result = model.predict(test.drop(columns=['id', 'Age']))
        result_ary.append(result)
elif procC == 3:
    if count > 0:
        for i in range(len(param_ary)):
            print()
            print(f'【Round {i+1} / {len(param_ary)}】')
            score = param_ary[i]['score']
            print(f'Score : {score}')
            print()
            params = param_ary[i]['params']
            model_ary = learn_model(X, value, test_size, params)
            evaluation_results = model_ary['evaluation_results']
            model = model_ary['model']
            show_train_result(evaluation_results)
            print()
            if i == len(param_ary) - 1:
                show_feature_importance(model)
            result = model.predict(test.drop(columns=['id', 'Age']))
            result_ary.append(result)
        print('【Result】')
        print(result_ary)
elif procC == 4:
    # ======================================================================
    param_ary = [
        {
            'feature_pre_filter': False,
            'lambda_l1': 0.0,
            'lambda_l2': 0.0,
            'num_leaves': 95,
            'feature_fraction': 0.7,
            'bagging_fraction': 1.0,
            'bagging_freq': 0,
            'min_child_samples': 100
        },
#        {
#            'feature_pre_filter': False,
#            'lambda_l1': 9.864695859460296,
#            'lambda_l2': 0.014339823264146559,
#            'num_leaves': 154,
#            'feature_fraction': 0.7,
#            'bagging_fraction': 1.0,
#            'bagging_freq': 0,
#            'min_child_samples': 50
#        },
#        {
#            'feature_pre_filter': False,
#            'lambda_l1': 6.435769149646807,
#            'lambda_l2': 1.184436106408238e-05,
#            'num_leaves': 113,
#            'feature_fraction': 0.7,
#            'bagging_fraction': 1.0,
#            'bagging_freq': 0,
#            'min_child_samples': 100
#        },
        {
            'feature_pre_filter': False,
            'lambda_l1': 8.63604892194464,
            'lambda_l2': 9.690759054775228e-07,
            'num_leaves': 90,
            'feature_fraction': 0.7,
            'bagging_fraction': 1.0,
            'bagging_freq': 0,
            'min_child_samples': 100
        },
        {
            'feature_pre_filter': False,
            'lambda_l1': 6.826353667659448,
            'lambda_l2': 1.0314685004038362e-05,
            'num_leaves': 93,
            'feature_fraction': 0.7,
            'bagging_fraction': 1.0,
            'bagging_freq': 0,
            'min_child_samples': 100
        }
    ]
    count = len(param_ary)
    # ======================================================================
    if count > 0:
        for i in range(len(param_ary)):
            print()
            print(f'【Round {i+1} / {len(param_ary)}】')
            print()
            params = param_ary[i]
            model_ary = learn_model(X, value, test_size, params)
            evaluation_results = model_ary['evaluation_results']
            model = model_ary['model']
            show_train_result(evaluation_results)
            print('')
            if i == len(param_ary) - 1:
                show_feature_importance(model)
            result = model.predict(test.drop(columns=['id', 'Age']))
            result_ary.append(result)
        print('【Result】')
        print(result_ary)

このコードはモデルの学習、評価、予測のプロセスを制御する部分です。以下にその詳細を説明します。

  1. show_train_resultという関数は、学習と評価の結果をプロットして表示します。学習データと検証データについての指標(l1)の値がエポック数に応じてどのように変化したかを確認することができます。

  2. show_feature_importanceという関数は、学習したモデルが各特徴量をどれだけ重要と考えたかをプロットして表示します。

  3. 次に、モデルの学習と評価、そしてテストデータに対する予測を行う部分があります。ここでの条件分岐(procC == 1, procC == 2等)は、異なる状況に対応するためのものと思われます。

    • procC == 1の場合、一連のハイパーパラメータを用いてモデルを学習し、学習の結果を表示し、テストデータの予測を行います。

    • procC == 2の場合、count > 0 (つまり、適切なハイパーパラメータセットが存在する)を確認します。そして最も良いスコアを持つパラメータセットを使用してモデルを学習し、学習の結果を表示し、テストデータの予測を行います。

    • procC == 3の場合、それぞれのパラメータセットについてモデルを学習し、学習の結果を表示し、テストデータの予測を行います。それぞれの予測結果はresult_aryに保存されます。

    • procC == 4の場合、設定されたいくつかのパラメータセットについてモデルを学習し、学習の結果を表示し、テストデータの予測を行います。それぞれの予測結果はresult_aryに保存されます。

全体として、このコードはモデルの学習、学習結果の確認、特徴量の重要度の表示、そしてテストデータに対する予測を制御しています。そして、どのハイパーパラメータを用いてモデルを学習するかはprocCの値によって決定されます。

Make submission file

if count > 0:
    df_result = pd.DataFrame(result_ary).transpose().mean(axis=1)
    sample_submission['Age'] = round(df_result)
    print(sample_submission)
    sample_submission.to_csv('submission.csv', index=False)

このスクリプトの目的は、予測結果をファイルとして出力し、そのファイルを提出できる形に整形することです。

まず、if count > 0:は、結果が1つ以上存在するかどうかを確認しています。これは、少なくとも1つの予測結果が得られていることを保証するためです。

次に、df_result = pd.DataFrame(result_ary).transpose().mean(axis=1)は、結果配列result_ary(これには複数の予測結果が含まれている可能性があります)をデータフレームに変換してから、転置(つまり行と列を入れ替え)しています。そして、各行(元のデータフレームの各列に対応)の平均値を計算しています。これは、複数のモデルからの予測を平均化することで、一種の「アンサンブル学習」を実行していると言えます。アンサンブル学習は、複数のモデルの予測を組み合わせることで、予測性能を向上させるテクニックです。

次に、sample_submission['Age'] = round(df_result)は、平均化した予測結果を四捨五入してから、提出データフレームsample_submissionAge列に代入しています。このステップで、提出用データフレームに最終的な予測結果が格納されます。

最後に、sample_submission.to_csv('submission.csv', index=False)は、予測結果が格納されたデータフレームをCSVファイルとして保存します。index=Falseは、データフレームのインデックスはCSVファイルに書き出さないことを指定しています。これにより、出力ファイルはコンペティションの提出要件を満たす形式になります。

つまり、このスクリプト機械学習モデルの予測結果を収集し、それらを平均化してから、提出フォーマットに合わせてファイルに書き出すためのものです。