📚 背景知識(読んでから問題へ)
データ分析において「見える化(可視化)」は最も強力な武器の一つです。数字だけでは気づけないパターン・分布・外れ値・相関が、グラフ1枚で一瞬で見えるようになります。Kaggleのトップランカーも、まず EDA(探索的データ分析)で大量のグラフを描くことから始めます。
⚖️ matplotlib vs seaborn
低レベルライブラリ。細かいカスタマイズが可能。全グラフの基盤になる。import matplotlib.pyplot as plt
matplotlibの高レベルラッパー。美しいデフォルトスタイル、統計グラフを少ないコードで描ける。import seaborn as sns
どちらを使っても plt.show()、plt.title()、plt.tight_layout() などのmatplotlib関数は共通して使えます。
📊 主要グラフ5種
1変数の分布を見る
外れ値・偏りを発見
plt.hist() / sns.histplot()
カテゴリ別の集計値
生存率の比較など
plt.bar() / sns.barplot()
2変数の関係(相関)
パターンの発見
plt.scatter() / sns.scatterplot()
分布の要約・外れ値
グループ比較に最適
sns.boxplot()
相関行列の可視化
全変数の関係を一覧
sns.heatmap()
🖼️ 図の構造 — Figure と Axes
fig, ax = plt.subplots(figsize=(幅インチ, 高さインチ)) — グラフ1枚ならこの形が標準パターン。複数のグラフを並べるときは plt.subplots(行数, 列数) で作成します。
🗂️ データスキーマ(今回使用)
| 列名 | 型 | 説明 | 利用するタスク |
|---|---|---|---|
PassengerId | int64 | 乗客ID | — |
Survived | int64 | 生存フラグ (0=死亡, 1=生存) | タスク2・3・4 |
Pclass | int64 | チケットクラス (1=上, 2=中, 3=下) | タスク2 |
Sex | object | 性別 (male/female) | タスク4 |
Age | float64 | 年齢 | タスク1・3・4 |
Fare | float64 | 運賃 | タスク3 |
Embarked | object | 乗船港 (S/C/Q) | — |
📝 問題
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(42)
data = {
"PassengerId": range(1, 51),
"Survived": [0,1,1,1,0,0,0,0,1,1,0,1,1,0,0,1,0,1,1,0,
0,1,1,0,0,1,0,0,1,0,0,1,1,1,0,0,0,1,0,1,
1,0,0,1,0,1,1,0,0,1],
"Pclass": [3,1,3,1,3,3,1,3,3,2,3,1,3,3,2,1,3,2,3,1,
3,2,1,3,3,1,2,3,1,3,3,2,1,3,3,2,3,1,3,2,
1,3,3,2,3,1,3,2,3,1],
"Sex": (["male","female"]*25),
"Age": [22,38,26,35,28,42,54,2,27,14,40,58,20,39,14,55,
2,31,18,35,42,26,15,29,8,60,12,33,19,44,
25,35,48,22,30,41,52,17,26,31,
22,38,26,35,28,42,54,2,27,14],
"Fare": [7.25,71.28,7.92,53.10,8.05,8.46,51.86,21.07,11.13,30.07,
16.70,26.55,8.05,31.27,16.00,86.50,7.92,24.15,7.92,512.33,
7.00,7.25,9.00,7.79,7.92,71.28,12.00,15.50,26.55,8.46,
7.25,30.07,71.28,8.05,13.00,29.70,7.25,86.50,7.92,9.50,
14.00,7.25,8.05,26.55,7.92,71.28,13.00,15.50,7.92,8.05],
"Embarked": (["S","C","S","S","Q"]*10),
}
df = pd.DataFrame(data)
タスク1 年齢のヒストグラム(matplotlib)
Age 列のヒストグラムを matplotlib で描いてください。
bins=10、色:steelblue、エッジ色:white- タイトル:
"Age Distribution"、x軸:"Age"、y軸:"Count"
タスク2 Pclassごとの生存率(seaborn barplot)
Pclass ごとの生存率(Survived の平均)を seaborn の barplot で描いてください。
- x軸:
Pclass、y軸:Survived - タイトル:
"Survival Rate by Pclass"
sns.barplot は y列の平均を自動計算してくれるので、事前に集計する必要はありません。タスク3 年齢と運賃の散布図(seaborn + hue)
Age と Fare の散布図を seaborn で描き、生存フラグ(Survived)で色分けしてください。
hue="Survived"、palette={0:"#f87171", 1:"#4ade80"}- タイトル:
"Age vs Fare (colored by Survived)"
タスク4 性別ごとの年齢分布(箱ひげ図)
性別(Sex)ごとの Age 分布を箱ひげ図で描いてください。
x="Sex",y="Age",hue="Survived",palette={0:"#f87171", 1:"#4ade80"}- タイトル:
"Age Distribution by Sex and Survived"
🔍 ヒント(段階的開示)
ヒント1 — 方向性
- タスク1:
ax.hist(df["Age"], bins=10, color="steelblue", edgecolor="white")+ax.set_title / xlabel / ylabel - タスク2:
sns.barplot(data=df, x="Pclass", y="Survived", ax=ax)— seaborn が平均を自動計算 - タスク3:
sns.scatterplot(data=df, x="Age", y="Fare", hue="Survived", palette={0:"#f87171", 1:"#4ade80"}, ax=ax) - タスク4:
sns.boxplot(data=df, x="Sex", y="Age", hue="Survived", palette={0:"#f87171", 1:"#4ade80"}, ax=ax)
ヒント2 — アプローチ
# タスク1
fig, ax = plt.subplots(figsize=(8, 5))
ax.hist(df["Age"], bins=10, color="steelblue", edgecolor="white")
ax.set_title("Age Distribution")
ax.set_xlabel("Age")
ax.set_ylabel("Count")
plt.tight_layout()
plt.show()
# タスク2
fig, ax = plt.subplots(figsize=(7, 5))
sns.barplot(data=df, x="Pclass", y="Survived", ax=ax)
ax.set_title("Survival Rate by Pclass")
plt.tight_layout()
plt.show()
# タスク3
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(data=df, x="Age", y="Fare", hue="Survived",
palette={0:"#f87171", 1:"#4ade80"}, ax=ax)
ax.set_title("Age vs Fare (colored by Survived)")
plt.tight_layout()
plt.show()
# タスク4
fig, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=df, x="Sex", y="Age", hue="Survived",
palette={0:"#f87171", 1:"#4ade80"}, ax=ax)
ax.set_title("Age Distribution by Sex and Survived")
plt.tight_layout()
plt.show()
ヒント3 — コード骨格(ほぼ答え)
# タスク1
fig, ax = plt.subplots(figsize=(8, 5))
ax.___(df["Age"], bins=___, color="___", edgecolor="___")
ax.set_title("___")
ax.set_xlabel("___")
ax.set_ylabel("___")
plt.show()
# タスク2
fig, ax = plt.subplots(figsize=(7, 5))
sns.___(data=df, x="___", y="___", ax=ax)
ax.set_title("___")
plt.show()
# タスク3
fig, ax = plt.subplots(figsize=(8, 5))
sns.___(data=df, x="Age", y="Fare", hue="Survived",
palette={0:"___", 1:"___"}, ax=ax)
ax.set_title("___")
plt.show()
# タスク4
fig, ax = plt.subplots(figsize=(8, 5))
sns.___(data=df, x="Sex", y="Age", hue="___",
palette={0:"___", 1:"___"}, ax=ax)
ax.set_title("___")
plt.show()
✅ 模範解答
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(42)
data = {
"PassengerId": range(1, 51),
"Survived": [0,1,1,1,0,0,0,0,1,1,0,1,1,0,0,1,0,1,1,0,
0,1,1,0,0,1,0,0,1,0,0,1,1,1,0,0,0,1,0,1,
1,0,0,1,0,1,1,0,0,1],
"Pclass": [3,1,3,1,3,3,1,3,3,2,3,1,3,3,2,1,3,2,3,1,
3,2,1,3,3,1,2,3,1,3,3,2,1,3,3,2,3,1,3,2,
1,3,3,2,3,1,3,2,3,1],
"Sex": (["male","female"]*25),
"Age": [22,38,26,35,28,42,54,2,27,14,40,58,20,39,14,55,
2,31,18,35,42,26,15,29,8,60,12,33,19,44,
25,35,48,22,30,41,52,17,26,31,
22,38,26,35,28,42,54,2,27,14],
"Fare": [7.25,71.28,7.92,53.10,8.05,8.46,51.86,21.07,11.13,30.07,
16.70,26.55,8.05,31.27,16.00,86.50,7.92,24.15,7.92,512.33,
7.00,7.25,9.00,7.79,7.92,71.28,12.00,15.50,26.55,8.46,
7.25,30.07,71.28,8.05,13.00,29.70,7.25,86.50,7.92,9.50,
14.00,7.25,8.05,26.55,7.92,71.28,13.00,15.50,7.92,8.05],
"Embarked": (["S","C","S","S","Q"]*10),
}
df = pd.DataFrame(data)
# ── タスク1: 年齢のヒストグラム ──
fig, ax = plt.subplots(figsize=(8, 5))
ax.hist(df["Age"], bins=10, color="steelblue", edgecolor="white")
ax.set_title("Age Distribution", fontsize=14)
ax.set_xlabel("Age")
ax.set_ylabel("Count")
plt.tight_layout()
plt.show()
# ── タスク2: Pclassごとの生存率 棒グラフ ──
fig, ax = plt.subplots(figsize=(7, 5))
sns.barplot(data=df, x="Pclass", y="Survived", ax=ax,
palette=["#60a5fa","#4ade80","#fbbf24"])
ax.set_title("Survival Rate by Pclass", fontsize=14)
ax.set_xlabel("Pclass")
ax.set_ylabel("Survival Rate")
plt.tight_layout()
plt.show()
# ── タスク3: 年齢と運賃の散布図 ──
fig, ax = plt.subplots(figsize=(8, 5))
sns.scatterplot(data=df, x="Age", y="Fare", hue="Survived",
palette={0:"#f87171", 1:"#4ade80"}, ax=ax, s=80)
ax.set_title("Age vs Fare (colored by Survived)", fontsize=14)
ax.set_xlabel("Age")
ax.set_ylabel("Fare")
plt.tight_layout()
plt.show()
# ── タスク4: 性別×生存の箱ひげ図 ──
fig, ax = plt.subplots(figsize=(8, 5))
sns.boxplot(data=df, x="Sex", y="Age", hue="Survived",
palette={0:"#f87171", 1:"#4ade80"}, ax=ax)
ax.set_title("Age Distribution by Sex and Survived", fontsize=14)
ax.set_xlabel("Sex")
ax.set_ylabel("Age")
plt.tight_layout()
plt.show()
4つのタスクで使うグラフ対応表
| タスク | グラフ種類 | ライブラリ | 主要関数 | 何が分かるか |
|---|---|---|---|---|
| タスク1 | ヒストグラム | matplotlib | ax.hist() | 年齢の分布・偏り |
| タスク2 | 棒グラフ(平均) | seaborn | sns.barplot() | クラス別生存率の差 |
| タスク3 | 散布図(色分け) | seaborn | sns.scatterplot() | 年齢・運賃・生存の関係 |
| タスク4 | 箱ひげ図(グループ比較) | seaborn | sns.boxplot() | 性別×生存別の年齢分布 |
🪜 Step-by-Step 解説
1 fig, ax = plt.subplots() — 「台紙とグラフ」を用意する
plt.subplots() は Figure(全体のキャンバス)と Axes(グラフを描く領域)を同時に作成します。figsize=(8, 5) は「幅8インチ、高さ5インチ」の意味です。複数グラフを並べるには fig, axes = plt.subplots(2, 2, figsize=(12, 8)) と書きます。
2 ax.hist() でヒストグラムを描く
ax.hist(df["Age"], bins=10, color="steelblue", edgecolor="white")
bins=10 はデータを10個の区間に分ける指定です。edgecolor="white" を設定すると棒の境界線が白くなり、隣の棒との境界が見やすくなります。
3 sns.barplot は y列の平均を自動計算する
sns.barplot(data=df, x="Pclass", y="Survived", ax=ax)
seaborn の barplot は x のカテゴリごとに y の平均値を計算して棒グラフにします。Survived は 0/1 のフラグなので、平均値 = 生存率(0〜1)となります。95%信頼区間のエラーバーも自動で表示されます。
4 hue パラメータで色分けする
sns.scatterplot(data=df, x="Age", y="Fare", hue="Survived",
palette={0:"#f87171", 1:"#4ade80"}, ax=ax)
hue="Survived" でグラフ内の点が Survived の値(0 or 1)によって色分けされます。palette で各値の色を辞書形式で指定できます。凡例も自動で追加されます。
5 plt.tight_layout() でラベルの重なりを防ぐ
plt.tight_layout()
plt.show()
tight_layout() は複数グラフや軸ラベルが重なるのを自動で調整します。show() の直前に書く習慣をつけましょう。Jupyter Notebook では show() がなくてもグラフが表示されますが、書いておくと明示的でわかりやすいです。
📦 箱ひげ図の解剖
箱の大きさ(IQR)が大きいほどデータのバラツキが大きく、小さいほど値が集中しています。外れ値(○)は特に注意が必要なデータ点です。
🔢 数学・統計の補足(文系向け)
ヒストグラムの「bins」とは何か
「bins(ビン)」は「箱」の意味です。データを一定の範囲で区切った箱に振り分けて、各箱に何件入るかを棒の高さで表します。Age 0〜60を bins=10 にすると、各棒は6歳刻みで「何人がその年齢帯にいるか」を示します。bins が多すぎると細かすぎて見にくく、少なすぎると分布の形が見えません。
散布図で「相関」を直感的に理解する
2変数をx軸とy軸にプロットして:
- 点が右上がりに並ぶ → 正の相関(一方が増えると他方も増える)
- 点が右下がりに並ぶ → 負の相関(一方が増えると他方は減る)
- 点がバラバラ → 相関なし
グラフで見ることで、相関係数を計算する前に直感を持てます。Titanic では高い運賃(Fare)の乗客が生存しやすいことが散布図から見えます。
四分位数(箱ひげ図の基礎)
データを小さい順に並べて:
- Q1(25%点): 下から25%の位置の値
- Q2(50%点): 中央値(真ん中の値)
- Q3(75%点): 下から75%の位置の値
- IQR = Q3 - Q1: 「データの真ん中50%の広がり」。外れ値の判定に使う
🏆 Kaggleでの実践的な使い方
EDA(探索的データ分析)はKaggleコンペの必須工程です。上位解法の多くが豊富なグラフを含んでいます。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
train = pd.read_csv("train.csv")
# ① 数値列の分布を一括確認
num_cols = ["Age", "Fare", "SibSp", "Parch"]
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
for i, col in enumerate(num_cols):
ax = axes[i//2][i%2]
sns.histplot(train[col].dropna(), bins=30, kde=True, ax=ax)
ax.set_title(f"{col} Distribution")
plt.tight_layout()
plt.show()
# ② カテゴリ別の生存率
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for i, col in enumerate(["Pclass", "Sex", "Embarked"]):
sns.barplot(data=train, x=col, y="Survived", ax=axes[i])
axes[i].set_title(f"Survival Rate by {col}")
plt.tight_layout()
plt.show()
# ③ 相関ヒートマップ
corr = train[["Survived","Pclass","Age","SibSp","Parch","Fare"]].corr()
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm", ax=ax)
ax.set_title("Correlation Heatmap")
plt.show()
| テクニック | 何が分かるか | Kaggle活用場面 |
|---|---|---|
histplot(kde=True) | 分布の形(正規・偏り・外れ値) | 特徴量エンジニアリングの前に分布確認 |
barplot(y="Survived") | カテゴリ別の生存率差 | 重要特徴量の発見 |
heatmap(annot=True) | 全変数間の相関を一覧表示 | 多重共線性・特徴量選択の参考 |
pairplot(hue="target") | 全ペアの散布図を一括生成 | 変数間の関係を大局的に把握 |
Kaggle EDA の標準フロー(可視化の順番)
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
plt.show() を忘れる |
Jupyter では自動表示されるため意識しにくい | スクリプト(.py)では必須。Jupyter でも書いておくと明示的でよい |
sns.barplot でy軸が 0〜1 にならず 0〜100 になる |
事前に Survived をパーセント換算してしまった |
seaborn の barplot は y列の平均を使う。0/1 フラグそのままで渡せばよい |
hue に数値型を入れて色が連続グラデーションになる |
hue="Survived" で int 型を渡した |
df["Survived"].astype(str) でカテゴリ型に変換すると 0/1 の2色に |
| ヒストグラムと棒グラフの混同 | 見た目が似ている | ヒストグラム: 1変数の連続値の分布。棒グラフ: カテゴリごとの集計値 |
tight_layout() を省いてラベルが重なる |
subplot を複数使うと自動調整されない | plt.tight_layout() を show() の前に必ず書く |
🚀 次のステップ
- 発展:
seaborn.pairplot(df, hue="Survived")で全変数ペアの散布図を一括生成。Kaggle EDA の標準ファースト・グラフ - 次回予告: 相関係数と散布図(
df.corr()で数値化しsns.heatmapで可視化)