【FDUA】第一回 金融データ活用チャレンジをやってみている #1

ひょんなことから[【FDUA】第一回 金融データ活用チャレンジ](https://signate.jp/competitions/841)に参加しているので、個人の活動記録を兼ねてやってることを書いてみます。
正直、あまり分析の助けにはならないと思いますが、学習回してる間の読み物にでもなれば。。。

https://signate.jp/competitions/841

## 自身の背景知識

- コンペ初参加。Kaggle覗いたことがある程度。
- 機械学習はちょっと触ってる程度。
- コンペの分析基盤であるDatabricksは業務で利用中。プラットフォーム自体の知識はそこそこある・・・かな？
- 金融のドメイン知識は全く無い。

普段はデータエンジニア・アナリティクスエンジニア的な仕事を事業会社でやっていて、  
コンペ参加は勉強のためという理由です。

## 参加にあたってのコンセプト（自分への縛り）

- せっかくなので、「**Databricksらしい(?)**」やり方でやってみて、どこまでいけるか試す。
- モデル訓練は頑張らない。頑張らない方法でやる。
- 前処理や特徴量エンジニアリングは超頑張る。
- 困っている人がいたら（特にDatabricks機能周りで）なるべく助ける。

## 今の状況

- 暫定評価0.95以上。当初目標が0.8以上だったので、割と頑張れているのではないか。。。

## どんな風にやってるの？

大まかに以下のステップでやっています。
Notebookもだいたいこの単位で作成。

### 1. 基本的な前処理と可視化

- Train/TestデータをUNION結合して、まとめてデータタイプ(日付型等)の変換等を実施
- 欠損状況などの確認
- 加工後の保管

Databricksらしく、というコンセプトに則って、データ処理はpandasではなくpysparkを使用します。
Spark(pyspark)はビッグデータ処理に適した分散処理環境です。
今回のコンペ環境では、シングルノードのクラスタしか利用できないので恩恵は少なめなのですが、今回ぐらいのデータ規模だとマルチノードのクラスタが欲しくなりました。
余談ですが、個人的にはPandasよりもSparkのAPIの方が(SQLに近くて)好きです。
(自分は経験がないのですが、[Polars](https://qiita.com/nkay/items/9cfb2776156dc7e054c8)も良さげですよね）

欠損状況の確認は、display関数を使ってデータ可視化やデータプロファイルを利用して確認しています。

また、Databricksでは[dbutils](https://docs.databricks.com/dev-tools/databricks-utils.html#data-utility-dbutilsdata)というユーティリティ機能も提供していて、データプロファイルを最初から使いたい場合は便利です。

https://docs.databricks.com/dev-tools/databricks-utils.html#data-utility-dbutilsdata


```python
# データフレームdf変数について統計情報を表示
# display関数を使ってデータプロファイルを使うのと、機能的には同一
dbutils.data.summarize(df)
```
基本的な加工後はデータベース(Deltalake & Unity Catalog)に保管します。
```python
# こんな感じで、データベース的にテーブルを保管できる。
# テーブル情報などは「データ」メニューから確認できる。
df.write.mode("overwrite").saveAsTable("テーブル名")
```
以後、各工程ごとに同様にテーブルへデータを保管しています。

### 2. 特徴量エンジニアリング

- 予測対象に関係しそうな仮説を考えて、必要な特徴量を追加していく。
    - 延滞しそうな人ってどういう人だろう、って考えて特徴量をとりあえず足していく。
    - 身近にそういう人がいるなら、その人の傾向を考えるといいかも・・・？
- 公式サイトにあがっている[チュートリアル](https://signate.jp/competitions/841/data)も参考になる。
- 最初のうちは、効く・効かないをあまり考えず、仮説に基づいてどんどん足す。
- 欠損値埋めもこのタイミング。

多くの方はPandasだったりSklearnだったり[xfeat](https://blog.amedama.jp/entry/xfeat)だったり使っていると思いますが、
私はほぼPysparkでやっています。
もし同じようにpysparkで頑張っている方がいらっしゃったら、ラグ値を計算したりするためにWindow関数は必ず理解されるのをお勧めします。以下の記事などが参考になると思います。

https://qiita.com/Tsubasa-Koyama/items/d332e385287c33beccb6

また、Databricksには特徴量ストアという機能があります。
私は今回のコンペでは使ってないのですが、特徴量管理をするにあたって使ってみるのもいいかも・・・？


https://qiita.com/taka_yayoi/items/88ddec323537febf7784


### 3. 特徴量の選定と不均衡データの調整

- 学習に利用する特徴量を選定（使う列だけに絞る）
    - 最初のうちは、とりあえず全部の特徴量を使ってもいいと思います。
    - 実際にはこのあたり何度もループを回すので、ループを回している中できちんと効果的な特徴量に絞っていく方がいい（たぶん）
- 不均衡データの調整
    - チュートリアルでも触れられていますが、今回のデータセットは不均衡データ（target_flag=1の割合が非常に少ない）です。
    - これのバランスを調整しないとまともなモデルにならないので、このタイミングで調整しています。
- 調整後データの可視化
    - バランス調整後に特徴量間の関係性を見たり、それを基に特徴量を選定しなおしたり。
- Train/Testを切り分けて保管

調整後データの可視化には、Databricksらしくということで```bamboolib```を使いました。
bamboolibはDatabricksがサポートしているノーコード・ローコードのデータ処理モジュールで、
pandasやpysparkをあまり習熟してない方でもデータを加工しやすいかなと思います。
詳しくは↓がサイコーにわかりやすいです。

https://qiita.com/taka_yayoi/items/7bf7813a84e169644876

私の用途は、このbamboolibによるPredictive Power Score([PPS](https://github.com/8080labs/ppscore))の計算です。
詳細は割愛しますが、これで予測に使えそうな特徴量かを大まかに判断していました。

### 4. 学習

- **コンセプト通り、ここは頑張らない**
- 私が書くコードよりもAutoMLの方が優秀だと思ったので、基本AutoMLでモデルを作ります。

DatabricksはAutoMLの機能を備えており、またモデル生成のNotebookを作ってくれるという機能を備えています。
つまりは、AutoMLで生成したNotebookをカスタマイズしてモデル改善ができるわけです。

https://qiita.com/taka_yayoi/items/0ed860131a02aeade14f

AutoMLの実行はGUI上からもできますが、
何度も実行することになるので、Notebook上で実行するようにしています。

```python

# 例。これを実行するとAutoMLの処理が実行され、エクスペリメントに記録される。

from databricks import automl

automl_result = automl.classify(
    train,
    target_col="target_flag",
    exclude_cols=["gid"],
    primary_metric="roc_auc",
    pos_label=1,
    # time_col="時系列データとして扱いたい場合、ここに時間のカラム名を指定",
    timeout_minutes=180,
)

```

最初のうちは短い実行時間で回してmetricsを見つつ、
特徴量選定が安定してるなと判断できたら長時間回して精度の良いモデルを作る、というようなやり方をしています。


### 5. モデルの解釈

- metricsの良かったモデルに対して、特徴量重要度を計算
- 特徴量の見直しを考える

上に書いたように、DatabricksのAutoMLは、そのモデルを作るためのNotebookを作ってくれます。
また、そのNotebook内には、SHAPで特徴量重要度を計算する処理まで含んでいます。
ただ、デフォルトだと計算しないように設定されているので、以下の部分を探して有効化＆Notebookを再実行する必要があります。

```python
# Set this flag to True and re-run the notebook to see the SHAP plots
shap_enabled = False # <- ここをTrueに変えることで、SHAPによる特徴量重要度計算が有効化される
```

※　ちなみにSHAPによる特徴量重要度計算は結構時間がかかるので注意。

SHAPの結果を基に、選定した特徴量が想定通り効いているのか・そうでないのかを判断します。
あまり有効ではない特徴量は3.の工程まで戻ってバッサリ切ったりなど、特徴量見直しの材料にします。

SHAP値確認の対象は、AutoMLで生成されたスコア上位の2・3個ぐらいまでを対象に確認しています。
感覚ですが、Bestモデルだけを見るより何個か見た方がいいような気がしています。
（特にアルゴリズムが異なるモデルの場合）


### 6. 予測

- 成績の良かったモデルを使ってTestデータに対する予測値を算出
- 予測結果の分布確認

mlflowを使って生成したモデルをロードし、probaを予測値として出します。
予測結果は分布を可視化して、過学習モデルによる変な分布になってたりしないかを確認しています。

このときも、１回のAutoMLで作ったBestモデルだけではなく、スコア上位2,3個のモデルで予測値を出して見ています。

### 7. SIGNATEへの提出

- SIGNATEへアップロードして、スコアを確認。
- アップの仕方はチュートリアルが参考になります。

この瞬間がやはりドキドキワクワクしますね。

結果のスコアを見て、5.の工程で確認したSHAPの情報や、他の仮説を基に2や3から再度やり直します。
基本的にはこのループを回すことでスコアを徐々に上げれていっています。
私の場合、始まりが0.7ぐらいで、ループを回すたびに徐々にスコアが上がっていく感じで進められました。

~~あと、最初は0 or 1の分類で提出すると勘違いしていて全然スコアあがらんかった。ルールをちゃんと把握するの大事です。~~

途中、AutoMLで生成したNotebookを基にカスタムモデルを作っていくことも試しました。
ただ、特徴量の試行錯誤に集中＆上記のループを早く回そうと思ったら、コンペ終盤まではAutoMLに任せた方が早くて精度出そうなので、AutoMLをぶん回す日々が続いています。
（なお、最終的にはモデルのチューニングや後処理を頑張る必要があると考えています）


## まとめ

- コンペ楽しいよコンペ
- Databricksの機能を活用すると素人でもそれなりに楽しんでやれるよ

ネタができたら#2も書いてみたいと思います。


追記：#2書きました。

https://qiita.com/isanakamishiro2/items/d8125606cc0d625f63d0