演習:経営ダッシュボードを設計しよう
田中VPoE「来月の経営会議に向けて、NetShop社の現状を一目で把握できるダッシュボードを作ってほしい。経営層がデータドリブンな意思決定をするための基盤だ。」
あなた「どんな情報を載せればいいですか?」
田中VPoE「KPIツリーに基づいて、売上、顧客、商品の3つの観点でまとめてくれ。まずは設計図を描いて、それからPythonで実装しよう。」
ミッション概要
NetShop社の経営会議向けダッシュボードを設計・実装します。KPIの可視化、トレンド分析、アラートの3つの要素を盛り込みます。
サンプルデータの作成
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
np.random.seed(42)
# 月次サマリーデータ
months = pd.date_range('2024-01', '2025-12', freq='M')
n_months = len(months)
monthly = pd.DataFrame({
'month': months,
'revenue': np.cumsum(np.random.normal(200, 50, n_months)) + 4000,
'orders': np.cumsum(np.random.normal(50, 20, n_months)) + 2000,
'new_customers': np.random.poisson(300, n_months),
'returning_customers': np.random.poisson(800, n_months),
'avg_order_value': np.random.normal(3500, 300, n_months),
'cvr': np.random.normal(0.032, 0.003, n_months),
'visits': np.random.poisson(150000, n_months),
})
monthly['revenue'] = monthly['revenue'].clip(lower=3000)
# カテゴリ別月次データ
categories = ['家電', '書籍', '食品', 'ファッション', 'スポーツ']
cat_monthly = []
for m in months:
for cat in categories:
cat_monthly.append({
'month': m, 'category': cat,
'revenue': np.random.lognormal(7, 0.5),
'orders': np.random.poisson(200)
})
cat_df = pd.DataFrame(cat_monthly)
# 地域別データ
regions = ['関東', '関西', '中部', '北海道', '九州']
region_data = pd.DataFrame({
'region': regions,
'revenue': [2800, 1500, 900, 400, 600],
'customers': [8000, 4500, 2500, 1200, 1800],
'target': [3000, 1600, 1000, 500, 700]
})
Mission 1: ダッシュボードの設計書を作成する
実装の前に、ダッシュボードの設計書を作成してください。
要件
- ダッシュボードの全体レイアウト(どの位置に何を配置するか)
- 各パネルの目的、使用するグラフタイプ、データソース
- 経営層が最初に見るべき情報(ヒーローメトリクス)の選定
- フィルタリング・ドリルダウンの設計
解答例
## ダッシュボード設計書
### レイアウト(4行構成)
Row 1: ヒーローメトリクス(KPIカード 5枚)
[月間売上] [注文数] [新規顧客数] [CVR] [AOV]
※ 前月比の矢印とパーセント変化を表示
Row 2: トレンド(2カラム)
[左: 月次売上推移 - 折れ線グラフ] [右: カテゴリ別売上構成 - 積み上げ棒グラフ]
Row 3: 詳細分析(2カラム)
[左: 地域別売上 vs 目標 - 横棒グラフ] [右: 顧客セグメント分布 - ドーナツチャート]
Row 4: アラート
[目標未達KPIのリスト - テーブル形式]
### 各パネルの詳細
| パネル | グラフタイプ | データ | 目的 |
|--------|------------|--------|------|
| KPIカード | 数値+前月比 | monthly | 主要指標の瞬時把握 |
| 売上推移 | 折れ線+面 | monthly | トレンドの把握 |
| カテゴリ別 | 積み上げ棒 | cat_df | 構成比の変化を追跡 |
| 地域別 | 横棒+目標線 | region_data | 地域ごとの達成状況 |
| セグメント | ドーナツ | customer | 顧客構成の把握 |
| アラート | テーブル | 計算値 | 問題の早期発見 |
### フィルタリング
- 期間選択(月次/四半期/年次)
- カテゴリフィルタ
- 地域フィルタ
Mission 2: matplotlib/seabornでダッシュボードを実装する
設計書に基づいて、matplotlibでダッシュボードを実装してください。
要件
- KPIカード(数値と前月比)を表示するパネル
- 月次売上推移の折れ線グラフ(目標線付き)
- カテゴリ別売上の積み上げ棒グラフ
- 地域別の達成率を示す横棒グラフ
- 全体を1つのFigureにまとめる
解答例
fig = plt.figure(figsize=(18, 14))
fig.suptitle('NetShop社 経営ダッシュボード(2025年12月)', fontsize=18, fontweight='bold', y=0.98)
# === Row 1: KPIカード ===
kpi_data = [
('月間売上', f'{monthly.iloc[-1]["revenue"]:,.0f}万円', '+8.2%', 'green'),
('注文数', f'{monthly.iloc[-1]["orders"]:,.0f}件', '+5.1%', 'green'),
('新規顧客', f'{monthly.iloc[-1]["new_customers"]:,}人', '-2.3%', 'red'),
('CVR', f'{monthly.iloc[-1]["cvr"]:.1%}', '+0.3pt', 'green'),
('AOV', f'{monthly.iloc[-1]["avg_order_value"]:,.0f}円', '+3.5%', 'green'),
]
for i, (label, value, change, color) in enumerate(kpi_data):
ax = fig.add_subplot(5, 5, i + 1)
ax.text(0.5, 0.65, value, ha='center', va='center', fontsize=16, fontweight='bold')
ax.text(0.5, 0.35, f'{label}', ha='center', va='center', fontsize=10, color='gray')
ax.text(0.5, 0.15, change, ha='center', va='center', fontsize=11, color=color)
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('off')
ax.patch.set_facecolor('#f8f9fa')
ax.patch.set_alpha(1)
# === Row 2 Left: 売上推移 ===
ax1 = fig.add_subplot(3, 2, 3)
ax1.plot(monthly['month'], monthly['revenue'], marker='o', linewidth=2, color='#1976D2')
ax1.fill_between(monthly['month'], monthly['revenue'], alpha=0.1, color='#1976D2')
target_line = 5000
ax1.axhline(y=target_line, color='red', linestyle='--', alpha=0.5, label=f'目標: {target_line}万円')
ax1.set_title('月次売上推移', fontsize=12, fontweight='bold', loc='left')
ax1.set_ylabel('売上(万円)')
ax1.legend()
ax1.grid(axis='y', alpha=0.3)
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
# === Row 2 Right: カテゴリ別構成 ===
ax2 = fig.add_subplot(3, 2, 4)
recent_months = cat_df[cat_df['month'] >= '2025-07']
pivot = recent_months.pivot_table(values='revenue', index='month', columns='category', aggfunc='sum')
pivot.plot(kind='bar', stacked=True, ax=ax2, colormap='Set2')
ax2.set_title('カテゴリ別売上構成(直近6ヶ月)', fontsize=12, fontweight='bold', loc='left')
ax2.set_ylabel('売上')
ax2.legend(loc='upper left', fontsize=8)
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
# === Row 3 Left: 地域別達成率 ===
ax3 = fig.add_subplot(3, 2, 5)
achievement = (region_data['revenue'] / region_data['target'] * 100).round(1)
colors = ['#4CAF50' if a >= 100 else '#FF5722' for a in achievement]
bars = ax3.barh(region_data['region'], achievement, color=colors)
ax3.axvline(x=100, color='gray', linestyle='--', alpha=0.5)
ax3.bar_label(bars, fmt='%.1f%%', padding=3)
ax3.set_title('地域別目標達成率', fontsize=12, fontweight='bold', loc='left')
ax3.set_xlabel('達成率(%)')
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)
# === Row 3 Right: 顧客構成 ===
ax4 = fig.add_subplot(3, 2, 6)
segments = ['新規', 'リピーター', '優良顧客', '休眠']
sizes = [30, 40, 15, 15]
colors_pie = ['#42A5F5', '#66BB6A', '#FFA726', '#EF5350']
wedges, texts, autotexts = ax4.pie(
sizes, labels=segments, colors=colors_pie,
autopct='%1.0f%%', startangle=90, pctdistance=0.8,
wedgeprops=dict(width=0.4)
)
ax4.set_title('顧客セグメント構成', fontsize=12, fontweight='bold')
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.savefig('dashboard.png', dpi=150, bbox_inches='tight', facecolor='white')
plt.show()
Mission 3: Plotlyでインタラクティブ版を作成する
同じダッシュボードをPlotlyで作成し、インタラクティブな操作を追加してください。
要件
- ホバーで詳細情報が見られる折れ線グラフ
- カテゴリをクリックでフィルタできる棒グラフ
- ドロップダウンで期間を切り替えられるUI
- HTMLファイルとしてエクスポート
解答例
import plotly.graph_objects as go
from plotly.subplots import make_subplots
fig = make_subplots(
rows=2, cols=2,
subplot_titles=[
'月次売上推移', 'カテゴリ別売上構成',
'地域別目標達成率', '顧客セグメント構成'
],
specs=[
[{'type': 'scatter'}, {'type': 'bar'}],
[{'type': 'bar'}, {'type': 'pie'}]
],
vertical_spacing=0.12,
horizontal_spacing=0.1
)
# 売上推移
fig.add_trace(
go.Scatter(
x=monthly['month'], y=monthly['revenue'],
mode='lines+markers', name='売上',
line=dict(color='#1976D2', width=2),
fill='tozeroy', fillcolor='rgba(25,118,210,0.1)',
hovertemplate='%{x|%Y年%m月}<br>売上: %{y:,.0f}万円<extra></extra>'
), row=1, col=1
)
fig.add_hline(y=5000, line_dash='dash', line_color='red',
annotation_text='目標: 5,000万円', row=1, col=1)
# カテゴリ別(直近6ヶ月)
for cat in categories:
cat_data = cat_df[(cat_df['category'] == cat) & (cat_df['month'] >= '2025-07')]
fig.add_trace(
go.Bar(x=cat_data['month'], y=cat_data['revenue'], name=cat,
hovertemplate='%{x|%Y年%m月}<br>' + cat + ': %{y:,.0f}<extra></extra>'),
row=1, col=2
)
# 地域別達成率
achievement_vals = (region_data['revenue'] / region_data['target'] * 100).round(1)
bar_colors = ['#4CAF50' if a >= 100 else '#FF5722' for a in achievement_vals]
fig.add_trace(
go.Bar(x=achievement_vals, y=region_data['region'], orientation='h',
marker_color=bar_colors, name='達成率',
text=[f'{a}%' for a in achievement_vals], textposition='outside',
hovertemplate='%{y}: %{x:.1f}%<extra></extra>'),
row=2, col=1
)
fig.add_vline(x=100, line_dash='dash', line_color='gray', row=2, col=1)
# 顧客セグメント
fig.add_trace(
go.Pie(labels=['新規', 'リピーター', '優良顧客', '休眠'],
values=[30, 40, 15, 15], hole=0.4,
marker_colors=['#42A5F5', '#66BB6A', '#FFA726', '#EF5350']),
row=2, col=2
)
fig.update_layout(
height=700, width=1100,
title_text='NetShop社 経営ダッシュボード',
title_font_size=18,
showlegend=True,
barmode='stack'
)
fig.write_html('dashboard_interactive.html', include_plotlyjs='cdn')
fig.show()
print("HTMLファイルを出力しました: dashboard_interactive.html")
達成度チェック
- ダッシュボードの設計書(レイアウト、パネル定義)を作成できた
- KPIカード(数値+前月比)を実装できた
- 月次売上推移を目標線付きで可視化できた
- カテゴリ別の構成変化を可視化できた
- 地域別の達成状況を可視化できた
- matplotlib版とPlotly版の両方を作成できた
- 経営層が見てすぐに状況を把握できるデザインになっている
推定所要時間:90分