【Leapコンペ】GBT系モデル解説②

前回記事に引き続きLeapコンペGBT系の解説をします。

# データのインポート
```python
train_files = sorted(glob("/kaggle/input/leap-dataset-giba/train_batch/*.parquet"))
test_files = glob("/kaggle/input/leap-dataset-giba/test_batch/*.parquet")
len(train_files), len(test_files)
```
train_filesの中身は
- '/kaggle/input/leap-dataset-giba/train_batch/0.parquet',
- '/kaggle/input/leap-dataset-giba/train_batch/1.parquet',
- '/kaggle/input/leap-dataset-giba/train_batch/10.parquet',

が複数ファイル。


```python
train = pd.read_parquet(train_files[:1]).astype('float32')
# '/kaggle/input/leap-dataset-giba/train_batch/0.parquet'ファイルを読み込み
train = cudf.from_pandas(train)  # pandasデータフレームをGPUで扱えるデータフレーム型に変換。
gc.collect() #メモリを解放:CPUとストレージ間でプログラムを一時的に保存する記憶装置
```
trainデータファイルで実行したことをvalidデータ、testデータでも同様のことを実行する

```python
# 特に解説なし。train_files[-1]は無作為に選択。
valid = pd.read_parquet(train_files[-1]).astype('float32')
valid = cudf.from_pandas(valid)
gc.collect()

test  = pd.read_parquet(test_files[0]).astype('float32')
test = cudf.from_pandas(test) 
gc.collect()
```

# モデルの学習

ポイント
- 今回のコンペでは目的変数が複数個あるため、複数の説明変数を用いて一つの説明変数を導くことをループ処理する
- 目的変数が近似値であれば0を入れる
- モデルの精度が良くなければ無視する
```python
xgb_params = {
    'n_estimators': 200, 
    'learning_rate': 0.10,
    'max_depth': 8,
    'device': 'cuda',
    'subsample': 0.40,
    'colsample_bytree': 0.95,
}

# xgb_parameterの設定
# よく使うパラメーター：https://medium.com/@rithpansanga/the-main-parameters-in-xgboost-and-their-effects-on-model-performance-4f9833cac7c


partial_target = []
for tnum, target in enumerate(targets): 
#targetsリストの各要素に対してループを実施し、tnumはターゲットのインデックス、targetsは前回記事で設定。
    feat = target + '_pred' 
    M = train[target].mean() 
    # M変数にtargetの平均→何も使われていない？記述ミス？

    if (train[target].nunique() != 1) and (train[target].abs().mean() > 1e-3):
        # target変数の値が1つでない、かつ、ターゲット変数の値が一意でなく、絶対値の平均が閾値（1e-3）
        # つまり値が離れている。
        es = xgb.callback.EarlyStopping( rounds=30, min_delta=1e-3, save_best=False, maximize=False)        
        #Early Stoppingの定義。->訓練データに対しての過学習を防ぐ
        # https://towardsdatascience.com/gradient-boosting-to-early-stop-or-not-to-early-stop-5ea67ac09d83
        model = xgb.XGBRegressor(**xgb_params, objective='reg:squarederror', callbacks=[es])
        
        model.fit(
            train[features], 
            train[target],
            eval_set=[(valid[features], valid[target])],
            verbose=False,
        )
        
        
        valid[feat] = model.predict(valid[features])
        # trainで学習したモデルをvalidデータに適用。
        score_model = r2_score(valid[target].values_host, valid[feat].values_host, force_finite=True)
        # r2_score(実測値, 予測値, force_finite=True(初期値はTrue))

        # If r2 is negative, just use mean(target)
        if score_model <= 0:
            #　r2_scoreがマイナスになればそのモデルはあまり当てにならない証拠になる。その場合はめんどくさいし0でいいか的なノリ
            valid[feat] = 0. # ループ処理された目的関数の値を0にしとく
            test[target] = 0.  # testデータの目的変数は予測云々よりも0で統一。
        else:
            test[target] = model.predict(test[features])
            # r2が正の場合は、学習モデルを活用してそれをtest[target]の値に入れる。
            
        bi = model.best_iteration
        # model.best_iterationは、XGBoostモデルの早期停止（Early Stopping）機能に関連するパラメータ。早期停止は、モデルの過剰適合（オーバーフィッティング）を防ぐために使用される手法。
        del model; gc.collect()
    else:
    #値が同じになってしまう場合。
        valid[feat] = 0. 
        test[target] = 0.
        bi = 0

    partial_target.append(target)
    score0 = r2_score(valid[target].values_host, valid[feat].values_host, force_finite=True)
    # 実測値 /　予測値
    # 予測値valid[feat(ここで定義feat = target + '_pred')]
    score1 = r2_score(valid[partial_target].values_host, valid[[f + '_pred' for f in partial_target]].values_host)
    # 今までの累積r2スコアを計測
    print(f"{tnum} r2(accum): {score1:.4f} / r2({target}): 
{score0:.4f},  best iter: {bi}")
```

# 最終的なスコアを計算
```python
score = r2_score(valid[targets].values_host, valid[[f + '_pred' for f in targets]].values_host)
print(score)
```

```python
valid.to_pandas().to_parquet(f'validation_{score:.4f}.parquet')
test = test.to_pandas()

del train, valid; gc.collect()
```

## サブミッションファイルの提出
```python
submission = pd.read_csv("/kaggle/input/leap-atmospheric-physics-ai-climsim/sample_submission.csv")

for col in tqdm(targets):
    if weights[col] > 0:
        submission[col] = test[col].values
    else:
        submission[col] = 0.
        
submission.to_csv('submission.csv', index=False)        
submission.head()

```

説明不足、間違っている箇所がありましたらご連絡ください。