一覧へ

KDEとヒストグラム — 分布の可視化

ヒストグラムとKDE(カーネル密度推定)の違いを理解し、seabornを使用してデータの分布を可視化する方法を学びます。

中級
|
10
|
検証済み (2026-07)
KDEヒストグラム分布の可視化カーネル密度推定データの分布
進捗0/17 (0%)

KDE とヒストグラム — 分布の可視化

このトピックを終えると

ヒストグラムと KDE プロットの違いを説明できるようになり、seaborn を使用してデータの分布を可視化し、データの形状を理解できるようになります。


分布を見る理由

データを分析する際に、平均と標準偏差だけでは不十分です。

python
import numpy as np
data_a = np.array([50, 50, 50, 50, 50])
data_b = np.array([10, 30, 50, 70, 90])
print(f"A の平均: {data_a.mean()}, B の平均: {data_b.mean()}") # どちらも 50

平均は同じですが、データの 形状 は完全に異なります。A は一箇所に集中しており、B は広く分布しています。分布を可視化すると、このような違いがわかります。


ヒストグラム — 棒で頻度を見る

ヒストグラムは、データを ビン に分割し、各ビンに含まれるデータの個数を棒の高さで表現します。

python
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(42)
data = np.random.normal(170, 10, 1000) # 平均 170、標準偏差 10、1000 人の身長
plt.figure(figsize=(8, 4))
plt.hist(data, bins=30, color='steelblue', edgecolor='white', alpha=0.7)
plt.xlabel('身長 (cm)')
plt.ylabel('頻度')
plt.title('身長の分布 (ヒストグラム)')
plt.show()

bins=30 は、全体の範囲を 30 個のビンに分割することを意味します。ビンの数によって形状が異なります。

python
fig, axes = plt.subplots(1, 3, figsize=(12, 3))
for ax, b in zip(axes, [5, 30, 100]):
ax.hist(data, bins=b, color='steelblue', edgecolor='white')
ax.set_title(f'bins={b}')
plt.tight_layout()
plt.show()
  • ビンが少なすぎると: 詳細な構造が失われる
  • ビンが多すぎると: ノイズが見える
  • 適切なビンの数を見つけることが、ヒストグラムの課題です。

KDE — 滑らかな曲線で密度を見る

KDE (Kernel Density Estimation、カーネル密度推定) は、ヒストグラムのスムーズなバージョンです。各データポイントに小さな鐘型の曲線(カーネル)を置いて、すべてを合計します。

python
import seaborn as sns
plt.figure(figsize=(8, 4))
sns.kdeplot(data, fill=True, color='steelblue', alpha=0.5)
plt.xlabel('身長 (cm)')
plt.title('身長の分布 (KDE)')
plt.show()

KDE の利点:

  • ビンの数を選択する必要がない (連続的な曲線であるため)
  • 視覚的に滑らか — 分布の形状を直感的に把握
  • 2 つの分布の比較が容易 — 重ねて描画するときに明確

ヒストグラム + KDE を一緒に見る

python
plt.figure(figsize=(8, 4))
sns.histplot(data, bins=30, kde=True, color='steelblue',
edgecolor='white', alpha=0.5, stat='density')
plt.xlabel('身長 (cm)')
plt.title('ヒストグラム + KDE')
plt.show()

stat='density' を設定すると、ヒストグラムの y 軸が頻度ではなく密度に変わり、KDE 曲線とスケールが一致します。


2 つのグループを比較する

python
np.random.seed(42)
male = np.random.normal(175, 8, 500)
female = np.random.normal(162, 7, 500)
plt.figure(figsize=(8, 4))
sns.kdeplot(male, fill=True, label='男性', alpha=0.4)
sns.kdeplot(female, fill=True, label='女性', alpha=0.4)
plt.xlabel('身長 (cm)')
plt.legend()
plt.title('性別による身長の分布の比較')
plt.show()

KDE は、重なる部分が透明に表示されるため、2 つのグループの違いと重なりを直感的に把握できます。


さまざまな分布の形状

python
np.random.seed(42)
fig, axes = plt.subplots(1, 4, figsize=(16, 3))
# 正規分布 — 左右対称の鐘型
normal = np.random.normal(0, 1, 1000)
sns.kdeplot(normal, ax=axes[0], fill=True)
axes[0].set_title('正規分布')
# 右側の裾 — ほとんどは小さく、少数は大きい (所得分布)
skewed = np.random.exponential(2, 1000)
sns.kdeplot(skewed, ax=axes[1], fill=True)
axes[1].set_title('右に偏った分布')
# 二峰性分布 — 2 つのグループが混ざっている
bimodal = np.concatenate([np.random.normal(-2, 0.5, 500),
np.random.normal(2, 0.5, 500)])
sns.kdeplot(bimodal, ax=axes[2], fill=True)
axes[2].set_title('二峰性分布')
# 一様分布 — すべての値がほぼ同じ頻度
uniform = np.random.uniform(0, 10, 1000)
sns.kdeplot(uniform, ax=axes[3], fill=True)
axes[3].set_title('一様分布')
plt.tight_layout()
plt.show()

分布の形状を見ると、データの特性をすぐに知ることができます。二峰性分布が現れると、「データの中に 2 つのグループが混ざっている」という洞察を得ることができます。


ヒストグラム vs KDE の選択基準

ヒストグラムKDE
正確な頻度✅ 各ビンの個数を確認可能❌ 密度推定値
分布の形状ビンの数によって異なる✅ 一貫性のある滑らかな曲線
グループの比較重なると読み取りにくい✅ 透明なオーバーレイが明確
離散データ✅ 適切❌ 連続データに適している
少量データ✅ 実際のデータを反映⚠️ 過度の平滑化のリスク

両方を一緒に使うのが最も安全です — ヒストグラムで実際の分布を確認し、KDE で全体的な傾向を把握します。



KDE の bandwidth パラメータ

KDE で最も重要な設定は bandwidth (帯域幅) です。各データポイントに配置するカーネルの幅を決定します。

python
fig, axes = plt.subplots(1, 3, figsize=(12, 3))
bandwidths = [0.1, 0.5, 2.0]
for ax, bw in zip(axes, bandwidths):
sns.kdeplot(data, bw_adjust=bw, ax=ax, fill=True)
ax.set_title(f'bw_adjust={bw}')
plt.tight_layout()
plt.show()
  • bandwidth が小さい (0.1): ノイズまで反映、ギザギザ
  • bandwidth が適切 (0.5〜1.0): データの傾向をうまく捉える
  • bandwidth が大きい (2.0): 過度に平滑化、詳細な構造が失われる

seaborn の bw_adjust は、自動的に計算された bandwidth に乗算する係数です。1.0 がデフォルト値で、ほとんどの場合、うまく機能します。


実践 — 外れ値の検出

分布の可視化は、外れ値 (outlier) を検出するのに効果的です。

python
np.random.seed(42)
normal_data = np.random.normal(100, 15, 1000)
outliers = np.array([200, 210, 220, -50])
data_with_outliers = np.concatenate([normal_data, outliers])
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
# ヒストグラムで外れ値を確認
axes[0].hist(data_with_outliers, bins=50, color='steelblue', edgecolor='white')
axes[0].set_title('ヒストグラム — 裾に外れ値が表示')
# 箱ひげ図と組み合わせるとより明確
axes[1].boxplot(data_with_outliers, vert=False)
axes[1].set_title('箱ひげ図 — 外れ値が点で表示')
plt.tight_layout()
plt.show()

KDE やヒストグラムで見た分布の裾が予想よりも長い場合、外れ値を疑います。箱ひげ図と組み合わせて使用すると、より正確な診断が可能です。



seaborn の displot — 統合分布可視化

python
# displot は、ヒストグラム、KDE、ECDF を 1 つの API で提供
sns.displot(data, kind="hist", kde=True, bins=30, height=4, aspect=2)
plt.show()
# ECDF — 累積分布関数
sns.displot(data, kind="ecdf", height=4, aspect=2)
plt.show()

displot は、seaborn 0.11+ で導入された統合インターフェースです。kind パラメータで "hist""kde""ecdf" のいずれかを選択し、hue パラメータでグループごとの比較を簡単に行うことができます。


分布を可視化することは、データ分析の最初のステップです。平均と標準偏差という数字だけでは見落としてしまうパターンが、グラフ 1 枚でわかります。

💬 質問・コメント

0件のコメント

ログインせずに投稿できます。ゲスト投稿は投稿者自身で編集・削除できません。

0/2000

読み込み中...