カーネル密度推定グラフを使用して、特徴量の分布を可視化する。

カーネル密度推定グラフを使用して、特徴量の分布を可視化し、
トレーニングデータセットとテストデータセットで利用可能な各特徴量の分布の確認をしているコードを見つけたためメモ。（[TPS September 2021 EDA(Kaggle)](https://www.kaggle.com/code/dwin183287/tps-september-2021-eda#4.2.1-Features-f1---f25)）

トレーニングデータセットとテストデータの分布が一致しない状況は、ドメインシフトと言われていて、
機械学習の性能低下に繋がることがあるとのこと。
参考：[ドメインシフトと機械学習の性能低下](https://www.mamezou.com/techinfo/ai_machinelearning_rpa/ai_tech_team/3)

# カーネル密度推定とは
有限の標本点から全体の分布を推定する手法の一つ。
分布をパラメトリックモデルで記述できない場合は、ノンパラメトリック推定という手法が使われる。
カーネル密度推定はノンパラメトリック推定の代表例。

参考：[パラメトリック手法とノンパラメトリック手法の違い](https://ai-trend.jp/basic-study/basic/parametric-method/)
参考：[カーネル密度推定とは](https://club.informatix.co.jp/?p=1176)


# 使用コード
データセットは[Tabular Playground Series - Sep 2021](https://www.kaggle.com/competitions/tabular-playground-series-sep-2021)のものを使用している。
（トレーニングデータセットをtrain_df, テストデータセットをtest_dfに格納。）
```
features = [feature for feature in train_df.columns if feature not in ['id', claim']]

plt.rcParams['figure.dpi'] = 600
fig = plt.figure(figsize=(10, 10), facecolor='#f6f5f5')
gs = fig.add_gridspec(5, 5)
gs.update(wspace=0.3, hspace=0.3)

run_no = 0
for row in range(0, 5):
    for col in range(0, 5):
        locals()["ax"+str(run_no)] = fig.add_subplot(gs[row, col])
        locals()["ax"+str(run_no)].set_facecolor(background_color)
        for s in ["top","right"]:
            locals()["ax"+str(run_no)].spines[s].set_visible(False)
        run_no += 1  

features = list(train_df.columns[1:26])
# features = ['f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f20', 'f21', 'f22', 'f23', 'f24', 'f25', 'f26']

background_color = "#f6f5f5"

run_no = 0
for col in features:
    sns.kdeplot(ax=locals()["ax"+str(run_no)], x=train_df[col], zorder=2, alpha=1, linewidth=1, color='#ffd514')
    locals()["ax"+str(run_no)].grid(which='major', axis='x', zorder=0, color='#EEEEEE', linewidth=0.4)
    locals()["ax"+str(run_no)].grid(which='major', axis='y', zorder=0, color='#EEEEEE', linewidth=0.4)
    locals()["ax"+str(run_no)].set_ylabel('')
    locals()["ax"+str(run_no)].set_xlabel(col, fontsize=4, fontweight='bold')
    locals()["ax"+str(run_no)].tick_params(labelsize=4, width=0.5)
    locals()["ax"+str(run_no)].xaxis.offsetText.set_fontsize(4)
    locals()["ax"+str(run_no)].yaxis.offsetText.set_fontsize(4)
    run_no += 1

run_no = 0
for col in features:
    sns.kdeplot(ax=locals()["ax"+str(run_no)], x=test_df[col], zorder=2, alpha=1, linewidth=1, color='#ff355d')
    locals()["ax"+str(run_no)].grid(which='major', axis='x', zorder=0, color='#EEEEEE', linewidth=0.4)
    locals()["ax"+str(run_no)].grid(which='major', axis='y', zorder=0, color='#EEEEEE', linewidth=0.4)
    locals()["ax"+str(run_no)].set_ylabel('')
    locals()["ax"+str(run_no)].set_xlabel(col, fontsize=4, fontweight='bold')
    locals()["ax"+str(run_no)].tick_params(labelsize=4, width=0.5)
    locals()["ax"+str(run_no)].xaxis.offsetText.set_fontsize(4)
    locals()["ax"+str(run_no)].yaxis.offsetText.set_fontsize(4)
    run_no += 1

plt.show()
```
参考：[TPS September 2021 EDA(Kaggle)](https://www.kaggle.com/code/dwin183287/tps-september-2021-eda#4.2.1-Features-f1---f25)

### 出力結果
トレーニングデータセットとテストデータセットの特徴量の分布がほぼ同じであると分かった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/883573/cd0390c7-6cc2-6100-f127-8778556dccd7.png)

## 使用コード内の知らなかった関数など
### add_gridspec
`Figure.add_gridspec(nrows, ncols)`を実行すると、nrows（縦）、ncols(横）で分割するGridSpecが返される。
上記の使用コードでは、
```
gs = fig.add_gridspec(5,5)
```
としているので、出力結果のように5×5の図表が出力されている。
また、下記の部分は、図表同士の間隔を設定している。
```
gs.update(wspace=0.3, hspace=0.3)
```

### spines["top", "right"].set_visible(False)
軸の目盛りを結ぶ線で、データ領域の境界を示すもの。任意の位置に配置することができる。
使用コードでは、図表の枠を`spines["Top"]`, `spines["right"]`で指定し、`set_visible(False)`で指定した枠線を消しているイメージ。
参考：[matplotlibで枠線を消したグラフを作る](https://qiita.com/irs/items/fe909442be057f0efb48)
```
for s in ["top","right"]:
    locals()["ax"+str(run_no)].spines[s].set_visible(False)
    run_no += 1  
```