SIGNATEのBeginner限定コンペをやってみた（【第30回_Beginner限定コンペ】PCゲームの勝敗予測）

# 記事の概要
* この記事は、データ分析コンペ未経験者向けの記事です。
* 特にSIGNATEのコンペに参加してみたい人は、分析手法から投稿方法も載せてありますので、ぜひご覧ください
* データそのものについては参加規約上掲載できないので、詳細に関しては[こちら](https://signate.jp/competitions/746)をよろしくお願いします。

# コンペの概要
* 今回取り組んだコンペは「【第30回_Beginner限定コンペ】PCゲームの勝敗予測」で、2023年1月1日～31日まで開催していました。
* モデル精度のボーダーラインが設定されており、そのラインを超える精度を出すと称号（ランクのようなもの）が昇格する仕組みとなっております。
* 今回の精度のボーダーラインはAccuracy=0.791で、私が取り組んだ期間は17日～24日の1週間でした。

# 分析環境
動作環境(OS)	：Windows11											
言語：Python3																	
ライブラリ：pandas, scikit-learn, matplotlib, seaborn, optuna
ツール：Jupyterlab																			

# 分析内容
## 目標
Tier5昇格Lineの"Accuracy>=0.791"

## 分析手順
### 1. EDA
* まずはデータ概要について把握します。
  * データの大きさ（行・列はそれぞれ幾つか）
  * データ型
  * 欠損値の有無
* 上記の内容は全て.infoで確認することが出来ます。
```
df.info()
```
* ちなみに今回は試合開始直後の10分間のデータから勝敗を予測します。

### 2. 前処理
* EDAによって確認した結果、欠損値やカテゴリ変数が存在していた場合は分析し易いように補間や数値変換を行う必要があります。
* 今回は欠損値が無く、全て数値データだったので特に行っていません
* IDの列に関しては分析上必要ないので、この時点で除外しておきます
```
X = df.drop(['gameId','blueWins'],axis=1)
y = df['blueWins']
```

### 3. ベースラインモデル構築
* データが用意出来たので、一旦モデルにデータを学習させてみます。
* バリデーション方法（検証方法、要はデータをどのように分割するか）については、クロスバリデーションの方が丁寧で精度のバラつきを抑えられますが、その分計算量がかなり増えてしまい、一回の分析に時間がかなりかかってしまうので、今回はホールドアウト法（いわゆるtrain_test_split）を選択しました。
```
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=0)
```
* ベースラインモデルの選択に関しては以下の観点を考慮しました。
  * 性能: 与えられたタスクに対して、最高の精度を発揮するモデルを選択する。
  * スケーラビリティ: 大規模なデータセットに対しても実行時間やメモリ使用量が許容されるモデルを選択する。
  * 理解性: 特徴量の重要度や決定木の構造を可視化できるモデルを選択する。
  * 実装のしやすさ: ライブラリやフレームワークが提供されており、実装が容易なモデルを選択する。
* 今回はLightGBMとXGBoostで精度を比較した結果、時間は多少かかるものの、より精度の高い**XGBoost**を選択しました
* そして、ハイパーパラメータはOptunaによって最適化しました。
```
# objective関数を定義する
def objective(trial):
    # ハイパーパラメータの確認
    params = {
        'objective': 'binary:logistic',
        'max_depth': trial.suggest_int('max_depth', 2, 10),
        'eta': trial.suggest_loguniform('eta', 0.01, 0.2),
        'subsample': trial.suggest_uniform('subsample', 0.5, 1.0),
        'colsample_bytree': trial.suggest_uniform('colsample_bytree', 0.5, 1.0)
    }
    # モデルの学習
    dtrain = xgb.DMatrix(X_train, y_train)
    dtest = xgb.DMatrix(X_test, y_test)
    model = xgb.train(params, dtrain, evals=[(dtest, 'test')], num_boost_round=100)
    # evaluate the model
    preds = model.predict(dtest)
    pred_labels = preds > 0.5
    accuracy = (pred_labels == y_test).mean()
    return 1 - accuracy

# study
study = optuna.create_study()

# optimize
study.optimize(objective, n_trials=100)

# 最適化されたハイパーパラメータをゲット
best_params = study.best_params

# 最適化されたハイパラでモデル作成
dtrain = xgb.DMatrix(X_train, y_train)
dtest = xgb.DMatrix(X_test, y_test)
model = xgb.train(best_params, dtrain, evals=[(dtest, 'test')], num_boost_round=100)

# 予測値からのモデル評価
preds = model.predict(dtest)
pred_labels = preds > 0.5
accuracy = (pred_labels == y_test).mean()
print("Accuracy: ", accuracy)
```

### 4. 特徴量エンジニアリング
* 精度向上のため、特徴量の取捨選択、加工を行っていきます。
* 基本的にはドメイン知識（タスクに関する背景知識）から構築される仮説や、相関係数、特徴量重要度から判断しました。
* 今回はPCゲームということもあり、対戦ゲームにおける「Kill数とDeath数」は重要だと考えました。
* そこで、Kill数とDeath数の差が大きい、もしくはマイナスになってしまっている試合は勝敗が確定し易いと考え、"Kill-Death"のカラムを追加しました。
* また、Kill数とAssist数が共に高い場合、チームの連携がとれており試合に安定して勝ち易いと考え、"Kill×Assist"のカラムも追加しました。
* そして、特徴量の出し入れを行っていく中で、精度向上に寄与せず、多重共線性も心配されるため、"Assist"と"Dragons"の列を削除しました。

### 5. モデル完成
* 実際の分析は上記のような完璧なステップを経てはおらず、少しづつ分析手法を変えて行ったため、試行回数はおよそ30回程度でした。
* 初心者の方向けに、最後の提出するためのコードはこちらです
```
# 本番用データの読み込み
test = pd.read_csv('test.csv')
test = test.drop('ID',axis=1)

# 本番用データでの学習
test = xgb.DMatrix(test)
preds = model.predict(test)
pred_labels = (preds > 0.5).astype(int)

# 提出データへの書き込み
answer = pd.read_csv('submit.csv', names=['id', 'ans'])
answer['ans'] = pred_labels
sub.to_csv("first_submit.csv", header=False, index=False)
```

## 結果
・最終精度はAccuracy=0.7925で、順位は170人中48位でした。
・無事に目標を達成し、Intermediate(Tier5)に昇格することが出来ました。
![PCcompe_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991881/2904873f-9048-4c7a-b56c-d5b3cb382bb3.png)


## 反省点
* 今回の分析の反省点として、特徴量エンジニアリングの際、ドメイン知識を上手く活用できませんでした。
* というのも、今回はデータについての説明からある程度ＰＣゲームの元ネタを特定し、そのゲームのルールはもちろんのこと、「最初の10分間の最善の動き」についても調べました。
* しかし、その知識を基に特徴量エンジニアリングを行っても中々精度は向上しませんでした。
* 結局、元々ＦＰＳ系のゲームをやっていたので、その程度のドメイン知識しか生かせませんでした。
* また、バリデーションを交差検証ではなくホールドアウトで行ったため、精度にバラつきがあり提出回数を余計に増やしてしまいました。
* 精度にバラつきがあることで、自分の特徴量エンジニアリングによって精度が向上したのかどうか分かりにくくなっていたことも、かなりのタイムロスだったと思います。

# 感想とまとめ
* 最後に私の感想ですが、このコンペは**初心者には必ずオススメ**です。
* 理由は、データ前処理などの面倒な作業は省略されていて、モデル選択や特徴量エンジニアリングなど、**精度向上に向けた最も面白い部分を楽しめるから**です。
* 一部の方はデータ前処理がないという点や二値分類のためにデータ分析の力が十分に身に付かないと考えるかもしれませんが、**初心者の方はまずコンペの楽しさを知ることが重要**だと思います。
* 現在はこのPCゲームの勝敗予測のコンペは開催されいませんが、別のBeginner限定コンペは開催されているので、ぜひ挑戦してみてください