Machine Learning: Matplotlib & Seabornによる可視化
最終更新:2026-08-26
優れたグラフは千行のデータに匹敵する — 可視化はパターン発見の第一歩です。
1. 学習内容
- Matplotlibの基礎:Figure/Axes/サブプロットシステム、折れ線グラフ、棒グラフ、散布図
- Seabornの高度なグラフ:分布プロット(histplot)、箱ひげ図、ヒートマップ
- 複数サブプロットのレイアウトとスタイルカスタマイズ:sns.set_theme、カラーパレット、CJKフォント設定
- ECデータの可視化実践:月次売上トレンド、カテゴリシェア、ユーザーRFM分布
- グラフ選択の判断:データに最適なグラフタイプの選び方
2. プロダクトマネージャーの実体験
(1) 課題:表データではトレンドと異常が見えない
BobはSalesPredictの月次売上レポートをチームに共有しました。50行のExcelデータを見ても、どのカテゴリが下落しているのか、どの月に異常な変動があったのかを素早く把握できる人はいませんでした。Aliceの米国データのトレンドは中国データとまったく異なりますが、生の数字を眺めているだけではその違いに気づくことはほぼ不可能です。データはスプレッドシートに埋もれ、重要なインサイトはかき消されていました。
(2) 可視化による解決策
たった1つの折れ線グラフで、第3四半期のElectronicsカテゴリの明確な下降トレンドが即座に判明しました。ヒートマップでは、広告費と売上の相関が予想を大きく上回っていることがわかりました。
PYTHON
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
# Quick visualization reveals hidden patterns
df = pd.read_csv("monthly_sales.csv")
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
df.plot(x="month", y="revenue", ax=axes[0], title="Revenue Trend")
sns.heatmap(df.corr(numeric_only=True), annot=True, ax=axes[1])
plt.tight_layout()
plt.savefig("sales_overview.png", dpi=150)
(3) 成果:5分で重要なビジネスインサイトを発見
生のテーブルを可視化に置き換えた結果、Bobは5分以内に第3四半期のElectronicsカテゴリの15%減少を発見しました。タイムリーに広告戦略を調整し、約20万ドルの損失を回避できました。
3. Matplotlibの基礎
(1) Figure/Axesシステム
Matplotlibは2層アーキテクチャを採用しています。Figure(キャンバス)が1つ以上のAxes(描画領域)を含みます。
graph TB
FIG[Figure - Canvas] --> AX1[Axes 1<br/>Subplot 1]
FIG --> AX2[Axes 2<br/>Subplot 2]
AX1 --> LINE[Line Chart]
AX2 --> BAR[Bar Chart]
▶ サンプル:基本的な折れ線グラフの作成
PYTHON
import matplotlib.pyplot as plt
# Monthly revenue data (thousand USD)
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
revenue = [120, 135, 150, 142, 160, 175, 180, 190, 195, 200, 220, 250]
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(months, revenue, marker="o", linewidth=2, color="#2196F3")
ax.set_title("Monthly Revenue Trend", fontsize=14)
ax.set_xlabel("Month")
ax.set_ylabel("Revenue (thousand USD)")
ax.grid(True, alpha=0.3)
ax.fill_between(months, revenue, alpha=0.1, color="#2196F3")
# Annotate peak
peak_idx = revenue.index(max(revenue))
ax.annotate(f"Peak: {max(revenue)}k", xy=(peak_idx, max(revenue)),
xytext=(peak_idx-2, max(revenue)+15),
arrowprops=dict(arrowstyle="->", color="red"))
plt.tight_layout()
plt.savefig("revenue_trend.png", dpi=150)
出力:
TEXT
📖 参照専用
# Executed successfully
(2) よく使われるグラフの種類
▶ サンプル:棒グラフと散布図
PYTHON
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Bar chart: category revenue
categories = ["Electronics", "Clothing", "Food", "Books", "Home"]
revenue = [2500, 1450, 900, 700, 4000]
colors = ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0", "#9966FF"]
axes[0].barh(categories, revenue, color=colors)
axes[0].set_title("Revenue by Category")
axes[0].set_xlabel("Revenue (thousand USD)")
# Scatter plot: ad spend vs revenue
np.random.seed(42)
ad_spend = np.random.uniform(10, 100, 50)
sales = 50 + 0.8 * ad_spend + np.random.normal(0, 10, 50)
axes[1].scatter(ad_spend, sales, alpha=0.6, color="#2196F3", edgecolors="white")
axes[1].set_title("Ad Spend vs Revenue")
axes[1].set_xlabel("Ad Spend (thousand USD)")
axes[1].set_ylabel("Revenue (thousand USD)")
# Add trend line
z = np.polyfit(ad_spend, sales, 1)
p = np.poly1d(z)
axes[1].plot(ad_spend, p(ad_spend), "r--", alpha=0.8, linewidth=2)
plt.tight_layout()
plt.savefig("bar_scatter.png", dpi=150)
出力:
TEXT
📖 参照専用
# Executed successfully
| グラフの種類 | 最適な用途 | Matplotlibの関数 |
|---|---|---|
| 折れ線グラフ | 時系列トレンド | ax.plot() |
| 棒グラフ | カテゴリ比較 | ax.bar() / ax.barh() |
| 散布図 | 2変数の関係性 | ax.scatter() |
| 円グラフ | 構成比の分布 | ax.pie() |
| ヒストグラム | 1変数の分布 | ax.hist() |
4. Seabornの高度なグラフ
SeabornはMatplotlibの上に構築されており、より高レベルな統計グラフと洗練されたデフォルトスタイルを提供します。
(1) 分布プロット
▶ サンプル:注文金額の分布分析
PYTHON
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
# Generate order amount data
rng = np.random.default_rng(42)
orders_normal = rng.normal(150, 50, 1000)
orders_normal = orders_normal[orders_normal > 0] # Remove negatives
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Histogram with KDE
sns.histplot(orders_normal, bins=30, kde=True, ax=axes[0], color="#2196F3")
axes[0].set_title("Order Amount Distribution")
axes[0].set_xlabel("Amount (USD)")
# Box plot by category
categories = rng.choice(["Electronics", "Clothing", "Food"], 500)
amounts = np.where(categories == "Electronics",
rng.normal(300, 80, 500),
np.where(categories == "Clothing",
rng.normal(120, 40, 500),
rng.normal(50, 20, 500)))
amounts = np.clip(amounts, 1, None)
data = {"category": categories, "amount": amounts}
sns.boxplot(data=data, x="category", y="amount", ax=axes[1], palette="Set2")
axes[1].set_title("Order Amount by Category")
plt.tight_layout()
plt.savefig("distribution.png", dpi=150)
出力:
TEXT
📖 参照専用
# Executed successfully
(2) ヒートマップ
▶ サンプル:特徴量の相関ヒートマップ
PYTHON
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Simulate SalesPredict feature correlations
np.random.seed(42)
n = 200
ad_spend = np.random.uniform(10, 100, n)
traffic = ad_spend * 1.2 + np.random.normal(0, 15, n)
conversion = traffic * 0.03 + np.random.normal(0, 0.5, n)
revenue = conversion * 150 + np.random.normal(0, 500, n)
customer_age = np.random.uniform(18, 65, n)
df = pd.DataFrame({
"ad_spend": ad_spend,
"traffic": traffic,
"conversion_rate": conversion,
"revenue": revenue,
"customer_age": customer_age,
})
corr = df.corr()
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr, annot=True, fmt=".2f", cmap="RdBu_r",
center=0, vmin=-1, vmax=1, ax=ax,
square=True, linewidths=0.5)
ax.set_title("Feature Correlation Heatmap")
plt.tight_layout()
plt.savefig("correlation_heatmap.png", dpi=150)
出力:
TEXT
📖 参照専用
# Executed successfully
(3) 複数サブプロットのレイアウト
▶ サンプル:SalesPredictの4次元分析パネル
PYTHON
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
rng = np.random.default_rng(42)
df = pd.DataFrame({
"date": pd.date_range("2024-01-01", periods=90),
"revenue": rng.normal(5000, 1000, 90).cumsum(),
"category": rng.choice(["Elec", "Cloth", "Food"], 90),
"orders": rng.integers(50, 200, 90),
})
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# (1) Revenue trend
axes[0, 0].plot(df["date"], df["revenue"], color="#2196F3")
axes[0, 0].set_title("Daily Revenue Trend")
# (2) Category distribution
cat_rev = df.groupby("category")["revenue"].sum()
axes[0, 1].pie(cat_rev, labels=cat_rev.index, autopct="%1.1f%%")
# (3) Orders distribution
sns.histplot(df["orders"], bins=20, kde=True, ax=axes[1, 0], color="#4CAF50")
axes[1, 0].set_title("Orders Distribution")
# (4) Revenue vs Orders
axes[1, 1].scatter(df["orders"], df["revenue"], alpha=0.5, c="#FF5722")
axes[1, 1].set_title("Revenue vs Orders")
plt.tight_layout()
plt.savefig("dashboard.png", dpi=150)
出力:
TEXT
📖 参照専用
# Executed successfully
5. スタイルカスタマイズとグラフの選択
(1) Seabornのテーマとカラーパレット
PYTHON
import seaborn as sns
# Set global theme
sns.set_theme(style="whitegrid", palette="muted", font_scale=1.2)
# Available themes: darkgrid, whitegrid, dark, white, ticks
# Available palettes: deep, muted, pastel, bright, dark, colorblind
| テーマ | 背景 | グリッド | 最適な用途 |
|---|---|---|---|
| darkgrid | ダーク | あり | データの密集した表示 |
| whitegrid | ホワイト | あり | 学術レポート |
| dark | ダーク | なし | プレゼンテーション |
| white | ホワイト | なし | 論文 |
| ticks | ホワイト | なし | ミニマルスタイル |
(2) グラフ選択の判断ガイド
graph TB
DATA[Data Type] --> CAT[Categorical]
DATA --> NUM[Numerical]
DATA --> TIME[Time Series]
CAT --> COMP[Comparison<br/>Bar Chart]
CAT --> PART[Part of Whole<br/>Pie / Stacked Bar]
NUM --> DIST[Distribution<br/>Histogram / KDE / Box]
NUM --> REL[Relationship<br/>Scatter / Heatmap]
TIME --> TREND[Trend<br/>Line Chart]
TIME --> SEA[Seasonality<br/>Seasonal Plot]
▶ サンプル:CJKフォントの設定
PYTHON
import matplotlib.pyplot as plt
# Method 1: Use SimHei font (Windows)
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False
# Method 2: Use English labels (recommended for i18n)
# Keep all labels in English to avoid font issues across platforms
fig, ax = plt.subplots()
ax.set_title("Monthly Sales Report") # English for compatibility
ax.set_xlabel("Month")
ax.set_ylabel("Revenue (thousand USD)")
出力:
TEXT
📖 参照専用
# Executed successfully
❓ よくある質問
Q MatplotlibとSeabornのどちらを使うべきですか?
A 日常的な分析にはSeaborn(よりクリーンで洗練されている)、細かな制御が必要な場合はMatplotlibを使ってください。SeabornはMatplotlibの上に構築されているため、自由に組み合わせて使えます。
Q グラフ内のCJK文字が文字化けする場合はどうすればいいですか?
A
plt.rcParams["font.sans-serif"] にCJKフォントを設定してください。ただし、クロスプラットフォームのフォント問題を避けるため、英語ラベルの使用を推奨します。Q 保存した画像がぼやけます。どうすればいいですか?
A dpiパラメータを設定してください:
plt.savefig("fig.png", dpi=150)。論文には300以上、Webには100〜150が目安です。ベクターグラフィックが必要な場合は .svg または .pdf 形式を使用してください。Q 適切なグラフの種類はどう選べばいいですか?
A データの種類と目的によります。時系列トレンドには折れ線グラフ、カテゴリ比較には棒グラフ、分布にはヒストグラム・箱ひげ図、2変数の関係性には散布図・ヒートマップを使用します。
Q Seabornの
hue パラメータは何をするものですか?A
hue は指定した列でデータをグループ化し、色分けします。例えば、sns.scatterplot(data=df, x="ad_spend", y="revenue", hue="category") はカテゴリごとに異なる色を割り当てます。Q サブプロットの間隔が狭すぎる場合はどうすればいいですか?
A
plt.tight_layout() で自動調整するか、plt.subplots_adjust(hspace=0.3, wspace=0.3) で手動で間隔を制御してください。📖 まとめ
- MatplotlibのFigure/Axesシステムはすべてのグラフの基盤です。Figureはキャンバス、Axesは描画領域です
- Seabornはより高レベルな統計グラフを提供します:histplot(KDE分布)、boxplot(箱ひげ図)、ヒートマップ(相関ヒートマップ)
- 複数サブプロットのレイアウトは
plt.subplots(nrows, ncols)で作成し、複数のグラフを統一的に管理します - グラフの選択はデータの種類に従います:時系列→折れ線、カテゴリ→棒、分布→ヒストグラム、関係性→散布図・ヒートマップ
- CJK表示にはフォント設定が必要ですが、クロスプラットフォーム互換性のため英語ラベルを推奨します
seaborn.set_theme()でスタイルを1行で設定できます。可能な限りカラーユニバーサルデザイン対応のパレットを選んでください
📝 練習問題
- 基礎(難易度 ⭐):Matplotlibを使って12ヶ月間の売上トレンドを示す折れ線グラフを描画してください。タイトルと軸ラベルを追加しましょう。ヒント:セクション3の折れ線グラフの例を参照してください。
- 中級(難易度 ⭐⭐):Seabornを使って2x2のサブプロットパネルを作成してください。折れ線グラフ(トレンド)、棒グラフ(カテゴリ比較)、箱ひげ図(分布)、ヒートマップ(相関)を、シミュレートしたSalesPredictデータで描画します。ヒント:
plt.subplots(2,2)+sns.xxx(ax=axes[i,j])。 - チャレンジ(難易度 ⭐⭐⭐):インタラクティブダッシュボードのコンセプトを作成してください。月次売上トレンドのグラフを描き、「プロモーション月」と「通常月」を異なる色でハイライトし、プロモーション効果を説明する注釈を追加してください。ヒント:
ax.axvspan()で領域を塗りつぶし、ax.annotate()で注釈を追加します。