Kaggle Titanic データで学ぶ、基本的な可視化手法

# はじめに

[【随時更新】Kaggle テーブルデータコンペで使う EDA・特徴量エンジニアリングのスニペット集](https://qiita.com/TaigoKuriyama/items/8f9286b5c882819adebb)におけるスニペットを主に利用して、 [Kaggle の Titanic データ ](https://www.kaggle.com/c/titanic/data)を利用して基本的なデータの可視化を行います。

## 前提

```py
import numpy as np 
import pandas as pd
import pandas_profiling as pdp
import matplotlib.pyplot as plt
import seaborn as sns
import warnings

warnings.filterwarnings('ignore')
cmap = plt.get_cmap("tab10")
plt.style.use('fivethirtyeight')
%matplotlib inline

pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option("display.max_colwidth", 10000)
```

```py
target_col = "Survived"
data_dir = "/kaggle/input/titanic/"
```

## フォルダの確認

```sh
!ls -GFlash /kaggle/input/titanic/
```

```sh
total 100K
4.0K drwxr-xr-x 2 nobody 4.0K Jan  7  2020 ./
4.0K drwxr-xr-x 5 root   4.0K Jul 12 00:15 ../
4.0K -rw-r--r-- 1 nobody 3.2K Jan  7  2020 gender_submission.csv
 28K -rw-r--r-- 1 nobody  28K Jan  7  2020 test.csv
 60K -rw-r--r-- 1 nobody  60K Jan  7  2020 train.csv
```

## データを読みこむ

```py
train = pd.read_csv(data_dir + "train.csv")
test = pd.read_csv(data_dir + "test.csv")
submit = pd.read_csv(data_dir + "gender_submission.csv")
```

## データを確認

```py
train.head()
```
<img width="994" alt="スクリーンショット 2020-07-12 9.17.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/3d019ab8-ba4b-28eb-240f-ca1a1923123f.png">

## レコード数、カラム数の確認

```py
print("{} rows and {} features in train set".format(train.shape[0], train.shape[1]))
print("{} rows and {} features in test set".format(test.shape[0], test.shape[1]))
print("{} rows and {} features in submit set".format(submit.shape[0], submit.shape[1]))
```
```sh
891 rows and 12 features in train set
418 rows and 11 features in test set
418 rows and 2 features in submit set
```

## カラムごとの欠損数を確認

カラムごとにどのくらい欠損があるか確認する。

```py
train.isnull().sum()
```

```sh
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64
```

## 欠損値の可視化

欠損に規則性があるか確認する。

```py
plt.figure(figsize=(18,9))
sns.heatmap(train.isnull(), cbar=False)
```
<img width="1044" alt="スクリーンショット 2020-07-12 10.52.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/4044db3e-d5e7-ffb6-f46d-24d8508cccea.png">



## 各カラムの要約統計量の確認

各カラムごとに平均や標準偏差、最大値、最小値、最頻値などの要約統計量を確認してデータをざっと理解する。


```py
train.describe()
```
<img width="597" alt="スクリーンショット 2020-07-12 11.58.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/b990fcbe-869b-22e2-60a4-d499f232684a.png">



## データの件数 (頻度) を集計

### ターゲットの割合を確認

```py
sns.countplot(x=target_col, data=train)
```
<img width="425" alt="スクリーンショット 2020-07-12 11.44.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/c3182137-7b21-4019-ba28-e0f2014fbce6.png">

### カテゴリ値の割合を確認

```sh
col = "Pclass"
sns.countplot(x=col, data=train)
```
<img width="436" alt="スクリーンショット 2020-07-12 12.41.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/583eb970-146d-c518-5fca-6ca7058873ba.png">

### ターゲットの値ごとのあるカラムの割合を確認

```py
col = "Pclass"
sns.countplot(x=col, hue=target_col, data=train)
```
<img width="426" alt="スクリーンショット 2020-07-12 10.32.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/f3b93570-77ed-41ac-173f-f1b4090c47ae.png">

```py
col = "Sex"
sns.countplot(x=col, hue=target_col, data=train)
```
<img width="429" alt="スクリーンショット 2020-07-12 10.35.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/bcf61dc2-deae-861d-13e4-29c8eef2fde4.png">

## ヒストグラム 

縦軸は度数、横軸は階級で、データの分布状況を可視化する。
ビンの大きさが異なれば異なったデータの特徴を示すためいくつか試す。

```py
col = "Age"
train[col].plot(kind="hist", bins=10, title='Distribution of {}'.format(col))
```
<img width="433" alt="スクリーンショット 2020-07-12 10.15.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/1e64d43c-d683-c237-099d-3fdb678a78b6.png">

```py
col = "Fare"
train[col].plot(kind="hist", bins=50, title='Distribution of {}'.format(col))
```
<img width="444" alt="スクリーンショット 2020-07-12 11.01.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/758b9d4c-2132-210f-ab2d-884761fce860.png">

### カテゴリごとのヒストグラム 

```py
f, ax = plt.subplots(1, 3, figsize=(15, 4))
sns.distplot(train[train['Pclass']==1]["Fare"], ax=ax[0])
ax[0].set_title('Fares in Pclass 1')
sns.distplot(train[train['Pclass']==2]["Fare"], ax=ax[1])
ax[1].set_title('Fares in Pclass 2')
sns.distplot(train[train['Pclass']==3]["Fare"], ax=ax[2])
ax[2].set_title('Fares in Pclass 3')
plt.show()
```
<img width="998" alt="スクリーンショット 2020-07-12 11.15.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/d23fdb08-81a6-e65a-09eb-cef72193aa0e.png">

### ターゲットのカテゴリごとのカラムのヒストグラム 

```py
col = "Age"
fig, ax = plt.subplots(1, 2, figsize=(15, 6))
train[train[target_col]==1][col].plot(kind="hist", bins=50, title='{} - {} 1'.format(col, target_col), color=cmap(0), ax=ax[0])
train[train[target_col]==0][col].plot(kind="hist", bins=50, title='{} - {} 0'.format(col, target_col), color=cmap(1), ax=ax[1])
plt.show()
```
<img width="1013" alt="スクリーンショット 2020-07-12 9.51.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/1bbe5579-7790-3d85-ecbb-a692d91fa171.png">

### ターゲットの値ごとのあるカラムのヒストグラム(重ねる場合)

```py
col = "Age"
train[train[target_col]==1][col].plot(kind="hist", bins=50, alpha=0.3, color=cmap(0))
train[train[target_col]==0][col].plot(kind="hist", bins=50, alpha=0.3, color=cmap(1))
plt.title("histgram for {}".format(col))
plt.xlabel(col)
plt.show()
```
<img width="424" alt="スクリーンショット 2020-07-12 12.19.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/0ded359b-06ae-6377-54e9-38381dff1a8b.png">

## カーネル密度推定

ざっくりいうとヒストグラムを曲線化したもの。Xに対するYを取得できる。

```py
sns.kdeplot(label="Age", data=train["Age"], shade=True)
```
<img width="431" alt="スクリーンショット 2020-07-12 13.06.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/24297207-cd12-39bf-0dce-60135d34cf65.png">

## クロス集計

カテゴリデータのカテゴリごとの出現回数を算出する。

```py
pd.crosstab(train["Sex"], train["Pclass"])
```
<img width="164" alt="スクリーンショット 2020-07-12 12.06.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/7e7d5ad4-fee9-abc0-07ae-c90300a2d8b9.png">

```py
pd.crosstab([train["Sex"], train["Survived"]], train["Pclass"])
```
<img width="213" alt="スクリーンショット 2020-07-12 12.10.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/fcd4821a-2f21-da9e-a681-e1798f40ab94.png">

## ピボットテーブル

### カテゴリごとの量的データの平均

```py
pd.pivot_table(index="Pclass", columns="Sex", data=train[["Age", "Fare", "Survived", "Pclass", "Sex"]])
```
<img width="472" alt="スクリーンショット 2020-07-12 15.37.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/771cbc72-5f1b-4bfd-ced6-a5e94b311ed3.png">

### カテゴリごとの量的データの最小値

```py
pd.pivot_table(index="Pclass", columns="Sex", data=train[["Age", "Fare", "Pclass", "Sex"]], aggfunc=np.min)
```
<img width="246" alt="スクリーンショット 2020-07-12 15.41.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/e0d90129-cfb5-2f7d-249e-92d97696b5b9.png">

## 散布図

２つのカラムの関係性を確認する。

### 散布図

```py
sns.scatterplot(x="Age", y="Fare", data=train)
```
<img width="445" alt="スクリーンショット 2020-07-12 12.29.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/916ea6f1-7205-4304-867c-bbbcae3b2a54.png">

### 散布図（カテゴリごとに色分け）

```py
sns.scatterplot(x="Age", y="Fare", hue=target_col, data=train)
```
<img width="440" alt="スクリーンショット 2020-07-12 12.30.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/b134a73a-2d03-e651-e811-20ad89e7224a.png">

### 散布図行列

```py
sns.pairplot(data=train[["Fare", "Survived", "Age", "Pclass"]], hue="Survived", dropna=True)
```
<img width="606" alt="スクリーンショット 2020-07-12 16.11.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/ac450087-79c6-dd14-c244-9f08ce69487c.png">

## 箱ひげ図

データのばらつきを視覚化する。

### カテゴリごとの箱ひげ図

カテゴリごとにデータのばらつきを確認する。

```py
sns.boxplot(x='Pclass', y='Age', data=train)
```
<img width="423" alt="スクリーンショット 2020-07-12 12.57.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/17bbdff3-007a-3289-ffcd-89d9e19d9f0b.png">

## ストリップチャート

データをドットで表した図。２つのデータに一方がカテゴリカルな場合に利用する。

```py
sns.stripplot(x="Survived", y="Fare", data=train)
```
<img width="426" alt="スクリーンショット 2020-07-12 10.58.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/e411bce5-3d80-cb90-2598-7db6371d32f1.png">

```py
sns.stripplot(x='Pclass', y='Age', data=train)
```
<img width="427" alt="スクリーンショット 2020-07-12 13.15.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/09b351be-424b-62aa-0e73-db8d1cca9c32.png">

## ヒートマップ

### カラムごとの相関係数のヒートマップ

```py
sns.heatmap(train.corr(), annot=True)
```
<img width="429" alt="スクリーンショット 2020-07-12 11.09.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184983/0cebc1c4-8293-3791-b4b0-6b6f95ebd580.png">

## 参考

- [EDA To Prediction(DieTanic)](https://www.kaggle.com/ash316/eda-to-prediction-dietanic)
- [A Simple Tutorial To Data Visualization](https://www.kaggle.com/vanshjatana/a-simple-tutorial-to-data-visualization)
- [Python: seaborn を使った可視化を試してみる](https://blog.amedama.jp/entry/seaborn-plot#scatter-plot-%E6%95%A3%E5%B8%83%E5%9B%B3)
- [pandasのピボットテーブルでカテゴリ毎の統計量などを算出](https://note.nkmk.me/python-pandas-pivot-table/)