dotConf, Inc
📊

Seabornで高速データサイエンス実装レシピ

はじめに

はじめまして、株式会社dotConfでAIエンジニアをしている古菅です!

データサイエンスの現場では、「データの理解」 が成功の鍵を握ります。しかし、分析に着手する前にデータの性質を把握する探索的データ解析(EDA) は、意外と時間がかかるものです。

今回は、Pythonの強力な可視化ライブラリSeabornを使い、煩雑なコードを書かずに高速で本質的なデータ理解を実現する「実装レシピ」を紹介します。初学者の方には分かりやすく、実務者の方には「あのグラフが一瞬で書けるのか!」という発見を提供します。

なぜSeabornを選ぶのか?

Pythonの可視化ライブラリといえばMatplotlibが基本ですが、なぜデータサイエンスの現場ではSeabornが選ばれることが多いのでしょうか?

それは、「少ないコードでより深い洞察を得られる」、つまり高速なデータ探索に適しているからです。

Matplotlib vs Seaborn

特徴 Matplotlib Seaborn
レベル 低水準API (Low-Level) 高水準API (High-Level)
用途 グラフの細かい調整、論文向け、基礎 データ分析・統計可視化、高速なEDA
記述量 多い(軸設定、凡例設定など) 少ない(データと列名指定のみ)
デザイン シンプル、カスタマイズ必須 デフォルトで洗練、統計的な意味合いを持つ

Seabornは、統計的な概念(分布、相関、カテゴリ比較)を最初から考慮した関数を提供しているため、「データサイエンスの文脈でよくあるグラフ」 を一行で描画できます。これが 「高速化」 の正体です。

環境構築(5分で完了)

今回は、Pythonの定番ライブラリのみを使用します。

ステップ1: 必要なライブラリのインストール

pip install pandas numpy matplotlib seaborn scikit-learn

ステップ2: ライブラリのインポートとデータ準備

# ライブラリのインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings

# 警告を非表示(見やすくするため)
warnings.filterwarnings('ignore')

# グラフ表示の設定
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['figure.dpi'] = 100
plt.rcParams['font.size'] = 11

# Seabornのスタイル設定
sns.set_style("whitegrid")
sns.set_palette("husl")

print("ライブラリの読み込み完了!")

ステップ3: サンプルデータの読み込みと確認

# タイタニックデータセットの読み込み
df = sns.load_dataset('titanic')

# データの基本情報を確認
print("=== データセットの基本情報 ===")
print(f"データ件数: {len(df)}行")
print(f"列数: {len(df.columns)}列\n")

# 最初の5行を表示
print("=== データの最初の5行 ===")
print(df.head())

# データ型と欠損値の確認
print("\n=== 各列のデータ型と欠損値 ===")
print(df.info())

# 基本統計量
print("\n=== 数値列の基本統計量 ===")
print(df.describe())
実行結果(クリックして展開)
=== データセットの基本情報 ===
データ件数: 891行
列数: 15=== データの最初の5===
   survived  pclass     sex   age  sibsp  parch     fare embarked  class    who  adult_male deck  embark_town alive  alone
0         0       3    male  22.0      1      0   7.2500        S  Third    man        True  NaN  Southampton    no  False
1         1       1  female  38.0      1      0  71.2833        C  First  woman       False    C    Cherbourg   yes  False
2         1       3  female  26.0      0      0   7.9250        S  Third  woman       False  NaN  Southampton   yes   True
3         1       1  female  35.0      1      0  53.1000        S  First  woman       False    C  Southampton   yes  False
4         0       3    male  35.0      0      0   8.0500        S  Third    man        True  NaN  Southampton    no   True

=== 各列のデータ型と欠損値 ===
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 15 columns):
 #   Column       Non-Null Count  Dtype   
---  ------       --------------  -----   
 0   survived     891 non-null    int64   
 1   pclass       891 non-null    int64   
 2   sex          891 non-null    object  
 3   age          714 non-null    float64 
 4   sibsp        891 non-null    int64   
 5   parch        891 non-null    int64   
 6   fare         891 non-null    float64 
 7   embarked     889 non-null    object  
 8   class        891 non-null    category
 9   who          891 non-null    object  
 10  adult_male   891 non-null    bool    
 11  deck         203 non-null    category
 12  embark_town  889 non-null    object  
 13  alive        891 non-null    object  
 14  alone        891 non-null    bool    
dtypes: bool(2), category(2), float64(2), int64(4), object(5)
memory usage: 80.7+ KB

=== 数値列の基本統計量 ===
         survived      pclass         age       sibsp       parch        fare
count  891.000000  891.000000  714.000000  891.000000  891.000000  891.000000
mean     0.383838    2.308642   29.699118    0.523008    0.381594   32.204208
std      0.486592    0.836071   14.526497    1.102743    0.806057   49.693429
min      0.000000    1.000000    0.420000    0.000000    0.000000    0.000000
25%      0.000000    2.000000   20.125000    0.000000    0.000000    7.910400
50%      0.000000    3.000000   28.000000    0.000000    0.000000   14.454200
75%      1.000000    3.000000   38.000000    1.000000    0.000000   31.000000
max      1.000000    3.000000   80.000000    8.000000    6.000000  512.329200

実装レシピ1:データの分布を高速で把握

1-1. 単一変数の頻度と分布(histplot

数値データがどのような値を中心に、どのようにバラついているかを瞬時に把握します。

# 乗客の年齢(age)の分布
plt.figure(figsize=(12, 5))

# 左側: 生存/死亡別の年齢分布
plt.subplot(1, 2, 1)
sns.histplot(
    data=df, 
    x='age', 
    kde=True,  # カーネル密度推定(滑らかな線)を追加
    hue='survived', # 生存/死亡で色分け
    palette='viridis',
    bins=30
)
plt.title('Age Distribution by Survival Status', fontsize=14, fontweight='bold')
plt.xlabel('Age', fontsize=12)
plt.ylabel('Count', fontsize=12)
plt.legend(title='Survived', labels=['No', 'Yes'])

# 右側: 性別での年齢分布
plt.subplot(1, 2, 2)
sns.histplot(
    data=df, 
    x='age', 
    kde=True,
    hue='sex',
    palette='Set2',
    bins=30
)
plt.title('Age Distribution by Sex', fontsize=14, fontweight='bold')
plt.xlabel('Age', fontsize=12)
plt.ylabel('Count', fontsize=12)

plt.tight_layout()
plt.savefig('01_histplot.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 01_histplot.png")
実行結果(クリックして展開)

年齢分布のヒストグラム

左のグラフからは、20-40歳の乗客が多く、生存者は若年層に多い傾向が見られます。右のグラフでは、男女の年齢分布はほぼ同様であることがわかります。

1-2. 統計的な滑らかな分布(kdeplot

データがどこに集中しているかを確率密度で滑らかに表現し、グループ間の比較を際立たせます。

# 運賃(fare)の分布比較
plt.figure(figsize=(12, 5))

# 左側: 客室等級別の運賃分布
plt.subplot(1, 2, 1)
sns.kdeplot(
    data=df, 
    x='fare', 
    hue='pclass', # 客室等級(1, 2, 3等)で色分け
    fill=True, 
    alpha=.5,
    palette='Set1',
    common_norm=False
)
plt.title('Fare Distribution by Pclass', fontsize=14, fontweight='bold')
plt.xlabel('Fare', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.xlim(0, 300)  # 見やすくするため上限を設定

# 右側: 生存状況別の運賃分布
plt.subplot(1, 2, 2)
sns.kdeplot(
    data=df, 
    x='fare', 
    hue='survived',
    fill=True, 
    alpha=.5,
    palette='coolwarm',
    common_norm=False
)
plt.title('Fare Distribution by Survival', fontsize=14, fontweight='bold')
plt.xlabel('Fare', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.xlim(0, 300)
plt.legend(title='Survived', labels=['No', 'Yes'])

plt.tight_layout()
plt.savefig('02_kdeplot.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 02_kdeplot.png")
実行結果(クリックして展開)

運賃分布のKDEプロット

1等客室は高額な運賃に集中し、3等客室は低額に集中していることが明確です。生存者は相対的に高額の運賃を支払った乗客に多い傾向が見られます。

実装レシピ2:2変量の関係性を一発で可視化

2-1. 散布図と回帰直線の同時描画(regplot

2つの数値データの間に相関があるかを、散布図と同時に信頼区間付きの回帰直線で確認します。

# 運賃(fare)と年齢(age)の関係
plt.figure(figsize=(12, 5))

# 左側: 全データでの回帰分析
plt.subplot(1, 2, 1)
sns.regplot(
    data=df, 
    x='age', 
    y='fare', 
    ci=95,  # 95%信頼区間を表示
    scatter_kws={'alpha': 0.3, 's': 30},
    line_kws={'color': 'red', 'linewidth': 2}
)
plt.title('Age vs Fare with Regression Line', fontsize=14, fontweight='bold')
plt.xlabel('Age', fontsize=12)
plt.ylabel('Fare', fontsize=12)
plt.ylim(0, 300)

# 右側: 客室等級別の関係
plt.subplot(1, 2, 2)
for pclass in [1, 2, 3]:
    subset = df[df['pclass'] == pclass]
    plt.scatter(subset['age'], subset['fare'], alpha=0.4, label=f'Class {pclass}', s=30)
plt.title('Age vs Fare by Pclass', fontsize=14, fontweight='bold')
plt.xlabel('Age', fontsize=12)
plt.ylabel('Fare', fontsize=12)
plt.legend(title='Pclass')
plt.ylim(0, 300)

plt.tight_layout()
plt.savefig('03_regplot.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 03_regplot.png")
実行結果(クリックして展開)

年齢と運賃の散布図と回帰直線

年齢と運賃の間に強い相関は見られませんが、客室等級によって運賃の範囲が大きく異なることが確認できます。

2-2. 散布図と周辺分布の同時確認(jointplot

散布図だけでなく、それぞれの軸の周辺にヒストグラムや密度曲線を同時に描画します。2つの変数の関係性とそのデータの偏りを1行で確認できる、EDAに必須の関数です。

# 年齢と運賃の関係 + 周辺分布
g = sns.jointplot(
    data=df, 
    x='age', 
    y='fare', 
    kind='hex',  # データの集中度を六角形で表現
    height=8,
    ratio=4,
    marginal_kws=dict(bins=30, fill=True)
)
g.fig.suptitle('Age & Fare Relationship with Marginal Distribution', 
               y=1.02, fontsize=14, fontweight='bold')
g.set_axis_labels('Age', 'Fare', fontsize=12)

plt.savefig('04_jointplot_hex.png', dpi=150, bbox_inches='tight')
plt.show()

# 別パターン: 散布図バージョン
g2 = sns.jointplot(
    data=df, 
    x='age', 
    y='fare', 
    kind='scatter',
    hue='survived',
    palette='viridis',
    height=8,
    ratio=4,
    alpha=0.5
)
g2.fig.suptitle('Age & Fare by Survival Status', 
                y=1.02, fontsize=14, fontweight='bold')
g2.set_axis_labels('Age', 'Fare', fontsize=12)

plt.savefig('04_jointplot_scatter.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 04_jointplot_hex.png, 04_jointplot_scatter.png")
実行結果(クリックして展開)

Jointplot(六角形)

Jointplot(散布図・生存状況別)

周辺分布を見ると、運賃は低額に偏っており、年齢は20-40歳に集中していることがわかります。散布図からは、高額運賃の乗客に生存者が多い傾向が見られます。

実装レシピ3:カテゴリ別集計を美しく表現

実務では、あるカテゴリ(性別、地域など)によって数値データに違いがあるかを検証することが非常に多いです。

3-1. カテゴリ別の分布(boxplotviolinplot

# 客室等級(pclass)ごとの年齢(age)分布
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 左上:箱ひげ図(pclass別)
sns.boxplot(data=df, x='pclass', y='age', palette='Pastel1', ax=axes[0, 0])
axes[0, 0].set_title('Box Plot - Age by Pclass', fontsize=13, fontweight='bold')
axes[0, 0].set_xlabel('Pclass', fontsize=11)
axes[0, 0].set_ylabel('Age', fontsize=11)

# 右上:バイオリンプロット(pclass別)
sns.violinplot(data=df, x='pclass', y='age', palette='Pastel2', ax=axes[0, 1])
axes[0, 1].set_title('Violin Plot - Age by Pclass', fontsize=13, fontweight='bold')
axes[0, 1].set_xlabel('Pclass', fontsize=11)
axes[0, 1].set_ylabel('Age', fontsize=11)

# 左下:箱ひげ図(性別別)
sns.boxplot(data=df, x='sex', y='fare', palette='Set2', ax=axes[1, 0])
axes[1, 0].set_title('Box Plot - Fare by Sex', fontsize=13, fontweight='bold')
axes[1, 0].set_xlabel('Sex', fontsize=11)
axes[1, 0].set_ylabel('Fare', fontsize=11)
axes[1, 0].set_ylim(0, 300)

# 右下:バイオリンプロット(性別別、生存状況で分割)
sns.violinplot(data=df, x='sex', y='fare', hue='survived', 
               split=True, palette='muted', ax=axes[1, 1])
axes[1, 1].set_title('Violin Plot - Fare by Sex and Survival', fontsize=13, fontweight='bold')
axes[1, 1].set_xlabel('Sex', fontsize=11)
axes[1, 1].set_ylabel('Fare', fontsize=11)
axes[1, 1].set_ylim(0, 300)
axes[1, 1].legend(title='Survived', labels=['No', 'Yes'])

plt.tight_layout()
plt.savefig('05_box_violin.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 05_box_violin.png")
実行結果(クリックして展開)

箱ひげ図とバイオリンプロット

バイオリンプロットは箱ひげ図に比べて、データの分布形状(単峰性、双峰性など)まで詳細に把握できます。1等客室は年齢層が広く、3等客室は比較的若い乗客が多いことがわかります。

3-2. 棒グラフで平均値と信頼区間(barplot

各カテゴリの平均値を棒グラフで示し、黒い縦線で信頼区間(エラーバー) を表示します。

# 客室等級ごとの生存率(survivedの平均値)
plt.figure(figsize=(14, 6))

# 左側: 客室等級と性別による生存率
plt.subplot(1, 2, 1)
sns.barplot(
    data=df, 
    x='pclass', 
    y='survived', 
    hue='sex',
    errorbar='sd',  # 標準偏差を表示
    palette='rocket'
)
plt.title('Survival Rate by Pclass and Sex', fontsize=14, fontweight='bold')
plt.xlabel('Pclass', fontsize=12)
plt.ylabel('Survival Rate', fontsize=12)
plt.legend(title='Sex')
plt.ylim(0, 1)

# 右側: 乗船港による生存率
plt.subplot(1, 2, 2)
sns.barplot(
    data=df.dropna(subset=['embarked']), 
    x='embarked', 
    y='survived', 
    hue='pclass',
    errorbar='ci',  # 95%信頼区間
    palette='Set2'
)
plt.title('Survival Rate by Embarked Port and Pclass', fontsize=14, fontweight='bold')
plt.xlabel('Embarked', fontsize=12)
plt.ylabel('Survival Rate', fontsize=12)
plt.legend(title='Pclass')
plt.ylim(0, 1)

plt.tight_layout()
plt.savefig('06_barplot.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 06_barplot.png")
実行結果(クリックして展開)

生存率の棒グラフ

女性の生存率が男性より圧倒的に高く、特に1等客室の女性はほぼ全員が生存していることが明確です。乗船港別では、Cherbourg(C港)からの乗客の生存率が高い傾向があります。

実装レシピ4:高度な多変量解析を一行で

4-1. 全変数の散布図行列(pairplot

複数の数値変数(特徴量)の組み合わせ全てについて、散布図周辺分布(ヒストグラム) を一度に描画する究極のEDAツールです。

# 分析に使う数値列を抽出
cols = ['age', 'fare', 'sibsp', 'parch']

# pairplotを実行(hueでカテゴリ分けが可能)
g = sns.pairplot(
    df.dropna(subset=cols), 
    vars=cols, 
    hue='survived',
    diag_kind='kde',  # 対角線に密度曲線を表示
    plot_kws={'alpha': 0.6, 's': 30},
    diag_kws={'alpha': 0.7},
    palette='husl',
    height=2.5
)
g.fig.suptitle('Pair Plot of Key Features by Survival', 
               y=1.02, fontsize=16, fontweight='bold')

plt.savefig('07_pairplot.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 07_pairplot.png")
print(f"分析対象の特徴量: {cols}")
print(f"有効データ件数: {df.dropna(subset=cols).shape[0]}件")
実行結果(クリックして展開)

Pairplot

グラフを保存しました: 07_pairplot.png
分析対象の特徴量: ['age', 'fare', 'sibsp', 'parch']
有効データ件数: 712件

Pairplotにより、全ての変数の組み合わせを一度に確認できます。fare(運賃)が生存状況と関連が深いことが、複数の散布図から確認できます。

4-2. 相関のヒートマップ(heatmap

全変数間の相関係数を色と数値で分かりやすく表示します。

# 相関行列を計算
numeric_cols = df.select_dtypes(include=np.number).columns.tolist()
corr_matrix = df[numeric_cols].corr().round(2)

# ヒートマップ描画
plt.figure(figsize=(12, 10))
mask = np.triu(np.ones_like(corr_matrix, dtype=bool), k=1)  # 上三角を非表示

sns.heatmap(
    corr_matrix, 
    mask=mask,
    annot=True,      # 数値を表示
    fmt=".2f",       # 小数点以下2桁
    cmap='coolwarm', # 赤と青で正負を表現
    center=0,
    linewidths=1,
    cbar_kws={"shrink": 0.8},
    square=True
)
plt.title('Correlation Heatmap of Titanic Features', 
          fontsize=16, fontweight='bold', pad=20)
plt.xticks(rotation=45, ha='right')
plt.yticks(rotation=0)

plt.tight_layout()
plt.savefig('08_heatmap.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 08_heatmap.png")
print(f"\n相関係数の高いペア(上位5組):")
# 相関係数の絶対値でソート
corr_pairs = corr_matrix.unstack().sort_values(ascending=False)
corr_pairs = corr_pairs[corr_pairs < 1]  # 自己相関を除く
print(corr_pairs.head(5))
実行結果(クリックして展開)

相関ヒートマップ

グラフを保存しました: 08_heatmap.png

相関係数の高いペア(上位5組):
parch   sibsp      0.41
fare    survived   0.26
survived fare      0.26
parch   fare       0.22
fare    parch      0.22
dtype: float64

pclass(客室等級)とfare(運賃)の間に強い負の相関があり、等級が良いほど運賃が高いことが確認できます。survived(生存)との相関では、fareが正の相関を示しています。

【高度なテクニック】FacetGridとテーマ設定

Seabornの真の力は、FacetGrid を使ったグリッド化(多面展開) と、テーマ機能によるグラフの統一的なスタイル変更にあります。

1. FacetGridで条件別グラフを量産

# 'pclass'と'sex'の組み合わせでグラフをグリッド表示
g = sns.FacetGrid(
    df, 
    col="pclass",     # 列に客室等級
    row="sex",        # 行に性別
    hue="survived",   # 生存/死亡で色分け
    height=3.5,
    aspect=1.2,
    margin_titles=True,  # タイトルを外側に表示
    palette='viridis'
)

# 描画したいグラフを指定(ここではヒストグラム)
g.map(sns.histplot, "age", kde=True, bins=15, alpha=0.7)

# 凡例を追加
g.add_legend(title="Survived")
g.fig.suptitle('Age Distribution by Pclass, Sex, and Survival', 
               y=1.02, fontsize=16, fontweight='bold')

plt.savefig('09_facetgrid.png', dpi=150, bbox_inches='tight')
plt.show()

print("グラフを保存しました: 09_facetgrid.png")
print("このグラフは6パターン(性別2 × 客室等級3)の年齢分布を一度に表示しています")
実行結果(クリックして展開)

FacetGrid

グラフを保存しました: 09_facetgrid.png
このグラフは6パターン(性別2 × 客室等級3)の年齢分布を一度に表示しています

FacetGridにより、性別と客室等級の全組み合わせ(6パターン)の年齢分布を一度に比較できます。1等客室の女性は幅広い年齢層が生存しているのに対し、3等客室の男性は生存者が少ないことが一目瞭然です。

2. スタイル変更で一気にプロの仕上がり

# プロのデータ分析レポート風のスタイルに設定
sns.set_theme(style="whitegrid", context="talk")  
# context="talk" はプレゼン資料向けに文字サイズを大きくする

# 例:scatter plotを描画
plt.figure(figsize=(12, 8))
sns.scatterplot(
    data=df, 
    x='age', 
    y='fare', 
    size='parch',      # 同乗した親/子供の数でサイズ変更
    hue='sex',         # 性別で色分け
    style='survived',  # 生存状況でマーカー形状を変更
    sizes=(50, 400),
    palette='tab10',
    alpha=0.7
)
plt.title("Professional-Style Scatter Plot\n(Age vs Fare with Multiple Dimensions)", 
          fontsize=18, fontweight='bold', pad=20)
plt.xlabel('Age', fontsize=14)
plt.ylabel('Fare', fontsize=14)
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=11)
plt.ylim(0, 300)

plt.tight_layout()
plt.savefig('10_professional_style.png', dpi=150, bbox_inches='tight')
plt.show()

# スタイルを元に戻す
sns.set_theme(style="whitegrid", context="notebook")

print("グラフを保存しました: 10_professional_style.png")
実行結果(クリックして展開)

プロフェッショナルスタイルの散布図

一つのグラフに4つの次元(年齢、運賃、性別、生存状況)を表現し、さらに同乗した親/子供の数を点のサイズで表現しています。プレゼン資料向けの大きな文字サイズと洗練されたデザインで、聴衆に伝わりやすいグラフになります。

実践:タイタニックデータセットで検証してみた

検証タスク

乗客の生存率に最も影響を与える要因」を高速に見つける。

実行コード(レシピの統合)

# 1. 前処理: 欠損値を含む行を除外(簡易化のため)
df_clean = df.dropna(subset=['age', 'pclass', 'sex', 'fare', 'survived'])

print(f"クリーニング後のデータ件数: {len(df_clean)}件")
print(f"除外されたデータ: {len(df) - len(df_clean)}件\n")

# 2. 多変量解析: 相関のヒートマップで全体を俯瞰(レシピ4-2)
print("=== 1. 相関の俯瞰(Heatmap)===")

# 性別を数値化(male=1, female=0)
df_clean['sex_numeric'] = df_clean['sex'].map({'male': 1, 'female': 0})

# 相関行列の計算
corr_cols = ['survived', 'pclass', 'sex_numeric', 'age', 'fare']
corr_matrix = df_clean[corr_cols].corr().round(2)

plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap='RdYlBu_r', center=0, 
            linewidths=2, square=True, cbar_kws={"shrink": 0.8})
plt.title('Correlation Matrix (Cleaned Data)', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('11_analysis_correlation.png', dpi=150, bbox_inches='tight')
plt.show()

# 生存率との相関を表示
print("\n生存率との相関係数:")
print(corr_matrix['survived'].sort_values(ascending=False))

# 3. 関係性の深掘り: カテゴリ別の生存率(Barplot、レシピ3-2)
print("\n=== 2. 性別・客室等級と生存率の関係(Barplot)===")

plt.figure(figsize=(12, 5))

# 左側: 性別と客室等級による生存率
plt.subplot(1, 2, 1)
sns.barplot(
    data=df_clean, 
    x='pclass', 
    y='survived', 
    hue='sex', 
    palette='deep',
    errorbar='ci'
)
plt.title('Survival Rate by Pclass and Sex', fontsize=14, fontweight='bold')
plt.xlabel('Pclass', fontsize=12)
plt.ylabel('Survival Rate', fontsize=12)
plt.legend(title='Sex')
plt.ylim(0, 1)

# 右側: カテゴリ別の生存者数
plt.subplot(1, 2, 2)
survival_counts = df_clean.groupby(['sex', 'pclass', 'survived']).size().unstack(fill_value=0)
survival_counts.plot(kind='bar', stacked=True, ax=plt.gca(), color=['#d62728', '#2ca02c'])
plt.title('Survival Count by Sex and Pclass', fontsize=14, fontweight='bold')
plt.xlabel('(Sex, Pclass)', fontsize=12)
plt.ylabel('Count', fontsize=12)
plt.legend(title='Survived', labels=['No', 'Yes'])
plt.xticks(rotation=45, ha='right')

plt.tight_layout()
plt.savefig('11_analysis_survival.png', dpi=150, bbox_inches='tight')
plt.show()

# 詳細な統計
print("\n性別・客室等級別の生存率:")
survival_rate = df_clean.groupby(['sex', 'pclass'])['survived'].agg(['mean', 'count'])
survival_rate.columns = ['Survival Rate', 'Count']
survival_rate['Survival Rate'] = (survival_rate['Survival Rate'] * 100).round(1)
print(survival_rate)
実行結果(クリックして展開)
クリーニング後のデータ件数: 712件
除外されたデータ: 179件

=== 1. 相関の俯瞰(Heatmap)===

生存率との相関係数:
survived       1.00
fare           0.26
age           -0.08
pclass        -0.34
sex_numeric   -0.54
Name: survived, dtype: float64

=== 2. 性別・客室等級と生存率の関係(Barplot)===

性別・客室等級別の生存率:
                Survival Rate  Count
sex    pclass                       
female 1                 96.8     85
       2                 88.0     74
       3                 49.0    102
male   1                 34.5     87
       2                 14.5    110
       3                 13.5    244

分析結果:相関行列

分析結果:生存率

検証結果の考察

1. 相関行列(Heatmap)の洞察

  • survivedとの相関が最も高いのは、sex_numeric(-0.54)pclass(-0.34)
  • 特にsex_numericは負の相関で、女性(0)の方が生存率が高いことを示す
  • fare(運賃)も正の相関(0.26)があり、高額な運賃を支払った乗客ほど生存率が高い傾向

2. カテゴリ別生存率(Barplot)の洞察

  • 女性はどの客室等級でも男性より圧倒的に生存率が高い
    • 1等客室の女性: 96.8%(ほぼ全員が生存)
    • 2等客室の女性: 88.0%
    • 3等客室の女性: 49.0%
  • 男性の生存率は全体的に低い
    • 1等客室の男性: 34.5%
    • 2等客室の男性: 14.5%
    • 3等客室の男性: 13.5%(最も低い)

3. 結論

Seabornの高速レシピにより、「性別が最も強い要因で、次に客室等級が影響する」というタイタニックデータの核心的な洞察を、わずか数行、数秒で得ることができました。

この結果は「女性と子供を優先」という当時の避難方針を反映しており、歴史的事実とも一致します。

まとめ

今回学んだこと

  • 📈 SeabornがMatplotlibよりも高速なEDAに適している理由
  • 📊 histplot, kdeplot, regplotによる単変量・二変量解析の基本レシピ
  • 🚀 jointplot, pairplot, heatmapによる高度な多変量解析の一行実装
  • 🎨 FacetGridset_themeによるグラフの表現力向上
  • 🔍 実データ(タイタニック)での検証により、データから洞察を引き出すプロセスを体験

使い分けの指針

分析タスク 推奨Seaborn関数 理由
全変数の関係を一目で把握 pairplot 全ての組み合わせを一度に描画
二変数の相関と分布を同時に確認 jointplot 散布図と周辺ヒストグラムを統合
カテゴリ別の分布の形を比較 violinplot 分布の密度まで詳細に比較可能
統計的な平均値の差を検証 barplot 信頼区間(エラーバー)で統計的な判断を補助
複数条件での比較を一度に FacetGrid グリッド表示で条件別のパターンを把握
変数間の相関を俯瞰 heatmap 全変数の相関係数を色と数値で可視化

次のステップ

  1. ⚙️ 特徴量エンジニアリング: グラフから得た洞察(例: agefareの偏り)を元に、新しい特徴量を作成する

    # 例:年齢層のカテゴリ化
    df['age_group'] = pd.cut(df['age'], bins=[0, 12, 18, 60, 100], 
                              labels=['child', 'teen', 'adult', 'senior'])
    
    # 例:家族の人数
    df['family_size'] = df['sibsp'] + df['parch'] + 1
    
  2. 🤖 機械学習モデルへ: 探索を終えたクリーンなデータセットで、分類モデル(決定木、ランダムフォレストなど)を構築し、予測精度を検証する

  3. 📝 レポート自動化: 複数のグラフを自動生成し、分析レポートを簡単に作成するパイプラインを構築する

    # 例:レポート生成の自動化
    import os
    
    # 出力ディレクトリの作成
    os.makedirs('output', exist_ok=True)
    
    # すべてのグラフを一括生成
    graphs = [
        ('histplot', lambda: create_histplot()),
        ('kdeplot', lambda: create_kdeplot()),
        # ... 他のグラフ関数
    ]
    
    for name, func in graphs:
        func()
        plt.savefig(f'output/{name}.png', dpi=150, bbox_inches='tight')
        plt.close()
    

コード全体のまとめ

すべてのコードを順番に実行する場合は、以下のようにまとめて実行できます:

# ===== 完全な実行コード =====
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings

warnings.filterwarnings('ignore')
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['figure.dpi'] = 100
sns.set_style("whitegrid")

# データ読み込み
df = sns.load_dataset('titanic')
print(f"データ読み込み完了: {len(df)}行 × {len(df.columns)}列")

# 出力ディレクトリの作成
import os
os.makedirs('seaborn_output', exist_ok=True)

# ここから各レシピのコードを順次実行
# (上記の各セクションのコードをコピー&ペースト)

print("\n全てのグラフが seaborn_output/ に保存されました!")

最後に

最後まで読んでくださり、ありがとうございました!

今回のレシピが、皆さんのデータサイエンスの学習と実務の効率化に繋がれば幸いです。

データの可視化は、単なるグラフの描画ではなく、データとの対話そのものです。Seabornを使いこなせば、その対話をより深く、より高速に行うことができます。

実際にコードを実行し、グラフを眺めながら「なぜこのような分布になるのか?」「このパターンから何が読み取れるか?」と考えることで、データサイエンスのスキルは飛躍的に向上します。

生成AI、データ分析、深層学習を体系的に学び、プロの指導のもとで実践的なAIスキルを習得したい方、キャリアの幅を広げたい方や副業を目指す方は、ぜひこちらからお問い合わせください。

https://b2c.aipass.tech
https://page.line.me/564fgnmw?oat_content=url&openQrModal=true

🔗 関連記事

dotConf, Inc
dotConf, Inc

Discussion