STEP 45:ロジックツリーとイシューツリー

🌳 STEP 45: ロジックツリーとイシューツリー

問題解決の強力なフレームワークをマスターしよう

📋 このステップで学ぶこと

  • ロジックツリーの3つのタイプ(What/Why/How)
  • イシューツリーの概念と作成方法
  • Pythonでのツリー構造の実装と可視化
  • 仮説検証とデータ分析への活用
  • ビジネス課題解決への実践的応用

学習時間の目安: 3時間

🔍 1. ロジックツリーとは

基本概念

ロジックツリーは、問題や課題を樹形図で論理的に分解・整理するフレームワークです。前のステップで学んだMECE(漏れなく・ダブりなく)の原則に従って、各階層で要素を分解していきます。

📌 ロジックツリーの3つのタイプ

① What Tree(要素分解型)

・「何で構成されるか」を分解
・全体を部分に分ける
・例:売上 = 商品A + 商品B + 商品C

② Why Tree(原因追求型)

・「なぜそうなるか」を分解
・原因を深掘りする
・例:売上減少 ← 客数減少 ← 新規顧客減少

③ How Tree(問題解決型)

・「どうやって解決するか」を分解
・解決策を具体化する
・例:売上向上 → 客数増加 → Web広告強化

3つのツリーの関係

💡 問題解決の流れ

Step 1:What Tree → 問題を構造化して全体像を把握
Step 2:Why Tree → 原因を深掘りして根本原因を特定
Step 3:How Tree → 解決策を具体化してアクションを決定

この3つを順番に使うことで、論理的な問題解決ができます。

各ツリーの具体例

What Tree(要素分解型)の例

【売上の構造】 売上 10,000万円 ├── 商品カテゴリA 4,000万円(40%) │ ├── 商品A-1: 2,000万円 │ ├── 商品A-2: 1,200万円 │ └── 商品A-3: 800万円 ├── 商品カテゴリB 3,500万円(35%) │ ├── 商品B-1: 2,000万円 │ └── 商品B-2: 1,500万円 └── 商品カテゴリC 2,500万円(25%) ├── 商品C-1: 1,500万円 └── 商品C-2: 1,000万円 ※各階層でMECE(漏れなく・ダブりなく)を維持

Why Tree(原因追求型)の例

【売上減少の原因分析】 売上減少 ▲20% ├── 客数減少 ▲15%(主因) │ ├── 新規顧客減少 ▲25% │ │ ├── 広告費削減 │ │ ├── SEO順位下落 │ │ └── 競合の台頭 │ └── 既存顧客離脱 ▲8% │ ├── 顧客満足度低下 │ └── 競合への乗り換え └── 客単価減少 ▲6% ├── 購買点数減少 │ └── クロスセル施策の停止 └── 商品単価低下 └── 価格競争への対応 ※「なぜ?」を繰り返して根本原因を特定

How Tree(問題解決型)の例

【売上向上の施策】 売上向上 +20% ├── 客数増加 +15% │ ├── 新規獲得強化 │ │ ├── Web広告の再開 │ │ ├── SEO対策の実施 │ │ └── SNSマーケティング │ └── 既存顧客維持 │ ├── ロイヤルティプログラム │ └── カスタマーサポート強化 └── 客単価向上 +6% ├── クロスセル復活 │ └── レコメンド機能の導入 └── アップセル施策 └── プレミアム商品の開発 ※具体的なアクションまで落とし込む

🎯 2. イシューツリーとは

イシューツリーの概念

イシューツリーは、解決すべき課題(イシュー)を「問い」の形で分解するフレームワークです。ロジックツリーが「要素」で分解するのに対し、イシューツリーは「答えるべき問い」で分解します。

⚠️ ロジックツリーとイシューツリーの違い

ロジックツリー:

・要素や原因、解決策を分解
・「何が」「なぜ」「どうやって」
・構造の可視化が目的

イシューツリー:

・「問い」を分解
・「〜か?」の形式
・仮説検証のガイドが目的
・各問いに答えることで、最終的な結論に至る

イシューツリーの例

【メインイシュー】 新規事業Xに参入すべきか? ├── 市場は魅力的か? │ ├── 市場規模は十分か?(100億円以上?) │ ├── 成長率は高いか?(年10%以上?) │ └── 競争環境は有利か? │ ├── 競合は少ないか? │ └── 参入障壁は高いか? │ ├── 自社に勝算があるか? │ ├── 必要な技術力はあるか? │ ├── 販売チャネルは活用できるか? │ └── ブランド力は活かせるか? │ └── 収益性は見込めるか? ├── 初期投資は回収可能か? ├── 営業利益率は確保できるか? └── ROIは基準を満たすか? ※各問いに「Yes/No」または「数値」で答える
📌 イシューツリーの作り方

Step 1:メインイシューを設定
・解決すべき最上位の問いを明確化
・「〜すべきか?」「〜は何か?」の形式

Step 2:サブイシューに分解
・メインイシューに答えるために必要な問いを洗い出し
・MECEを意識(漏れなく・ダブりなく)

Step 3:さらに詳細な問いに分解
・各サブイシューを具体的な問いに分解
・データで答えられるレベルまで落とし込む

Step 4:仮説を立てる
・各問いに対する仮の答え(仮説)を設定
・データで検証する準備

仮説検証との連携

イシュー(問い) 仮説 検証方法 必要データ
市場規模は十分か? 100億円以上ある 市場調査レポート 業界レポート、統計データ
成長率は高いか? 年15%で成長中 過去5年のトレンド 市場規模の推移データ
自社に技術力はあるか? 70%は既存技術で対応可能 技術部門へのヒアリング 技術マッピング
ROIは基準を満たすか? 3年でROI 150% 収益シミュレーション コスト・売上予測

🐍 3. Pythonでロジックツリーを実装

ここからは、Pythonを使ってロジックツリーとイシューツリーを実装し、データ分析に活用する方法を学びます。コードは段階的に解説しますので、1つずつ理解しながら進めましょう。

Step 1:ライブラリのインポートとデータ準備

まず、必要なライブラリをインポートし、分析用のサンプルデータを作成します。

※コードは横スクロールできます

# ============================================ # Step 1:ライブラリのインポートとデータ準備 # ============================================ # データ操作用ライブラリ import numpy as np # 数値計算(配列操作、乱数生成など) import pandas as pd # データフレーム操作(表形式データの処理) # 可視化用ライブラリ import matplotlib.pyplot as plt # グラフ描画の基本ライブラリ # 日本語フォントの設定(文字化け防止) # Mac/Windows/Linuxで使用可能なフォントを順に指定 plt.rcParams[‘font.sans-serif’] = [‘Arial Unicode MS’, ‘Yu Gothic’, ‘Hiragino Sans’] plt.rcParams[‘axes.unicode_minus’] = False # マイナス記号の文字化け防止 # 乱数シードを固定(実行するたびに同じ結果を得るため) np.random.seed(42) print(“✓ ライブラリのインポート完了”) print(“✓ 日本語フォント設定完了”) print() # ============================================ # サンプルデータ:ECサイトの売上データ # ============================================ # 売上データを作成(商品カテゴリ × 販売チャネル × 顧客タイプ) data = { “カテゴリ”: [“家電”, “家電”, “家電”, “家電”, “アパレル”, “アパレル”, “アパレル”, “アパレル”, “食品”, “食品”, “食品”, “食品”], “チャネル”: [“店舗”, “店舗”, “EC”, “EC”] * 3, “顧客タイプ”: [“新規”, “既存”, “新規”, “既存”] * 3, “売上_前年”: [1200, 1800, 800, 1000, # 家電 600, 900, 400, 500, # アパレル 300, 450, 200, 250], # 食品 “売上_今年”: [1000, 1700, 900, 1100, # 家電(店舗減、EC増) 500, 800, 500, 600, # アパレル(店舗減、EC増) 280, 420, 250, 300] # 食品(微減、EC増) } # DataFrameに変換 df = pd.DataFrame(data) # 前年比を計算(今年の売上 ÷ 前年の売上 – 1) df[“前年比”] = (df[“売上_今年”] / df[“売上_前年”] – 1) * 100 print(“【ECサイト売上データ(単位:万円)】”) print(“=” * 70) print(df.to_string(index=False)) print() # 全体の売上を集計 total_last_year = df[“売上_前年”].sum() total_this_year = df[“売上_今年”].sum() total_growth = (total_this_year / total_last_year – 1) * 100 print(f”【全体サマリー】”) print(f”前年売上合計: {total_last_year:,}万円”) print(f”今年売上合計: {total_this_year:,}万円”) print(f”前年比: {total_growth:+.1f}%”)
✓ ライブラリのインポート完了 ✓ 日本語フォント設定完了 【ECサイト売上データ(単位:万円)】 ====================================================================== カテゴリ チャネル 顧客タイプ 売上_前年 売上_今年 前年比 家電 店舗 新規 1200 1000 -16.67 家電 店舗 既存 1800 1700 -5.56 家電 EC 新規 800 900 12.50 家電 EC 既存 1000 1100 10.00 アパレル 店舗 新規 600 500 -16.67 アパレル 店舗 既存 900 800 -11.11 アパレル EC 新規 400 500 25.00 アパレル EC 既存 500 600 20.00 食品 店舗 新規 300 280 -6.67 食品 店舗 既存 450 420 -6.67 食品 EC 新規 200 250 25.00 食品 EC 既存 250 300 20.00 【全体サマリー】 前年売上合計: 8,400万円 今年売上合計: 8,350万円 前年比: -0.6%
📝 コード解説

np.random.seed(42):乱数シードを固定することで、再実行しても同じ結果が得られます
pd.DataFrame():辞書形式のデータをDataFrame(表形式)に変換
df["前年比"]:新しい列を追加して計算結果を格納
・データは「カテゴリ × チャネル × 顧客タイプ」の3次元でMECEに分解されています

Step 2:What Tree(要素分解型)の実装

売上を階層的に分解して、全体の構造を可視化します。

# ============================================ # Step 2:What Tree(要素分解型)の実装 # ============================================ # 目的:売上を階層的に分解して全体像を把握する print(“【What Tree:売上の要素分解】”) print(“=” * 70) print() # —– レベル1:全体 —– print(“■ レベル1:全体”) print(f” 売上合計: {total_this_year:,}万円(前年比 {total_growth:+.1f}%)”) print() # —– レベル2:カテゴリ別に分解 —– print(“■ レベル2:カテゴリ別分解”) # groupby()でカテゴリごとに集計 # agg()で複数の集計を一度に実行 by_category = df.groupby(“カテゴリ”).agg({ “売上_前年”: “sum”, # 前年売上の合計 “売上_今年”: “sum” # 今年売上の合計 }).reset_index() # 前年比と構成比を計算 by_category[“前年比”] = (by_category[“売上_今年”] / by_category[“売上_前年”] – 1) * 100 by_category[“構成比”] = by_category[“売上_今年”] / total_this_year * 100 # 売上が大きい順にソート by_category = by_category.sort_values(“売上_今年”, ascending=False) # 結果を表示(ツリー形式) for _, row in by_category.iterrows(): print(f” ├── {row[‘カテゴリ’]}: {row[‘売上_今年’]:,.0f}万円”) print(f” │ 構成比: {row[‘構成比’]:.1f}% 前年比: {row[‘前年比’]:+.1f}%”) print() # —– レベル3:カテゴリ×チャネルで分解 —– print(“■ レベル3:カテゴリ × チャネル別分解”) # 2つの軸でグループ化 by_cat_channel = df.groupby([“カテゴリ”, “チャネル”]).agg({ “売上_前年”: “sum”, “売上_今年”: “sum” }).reset_index() by_cat_channel[“前年比”] = (by_cat_channel[“売上_今年”] / by_cat_channel[“売上_前年”] – 1) * 100 # カテゴリごとにツリー表示 for category in by_category[“カテゴリ”]: cat_data = by_cat_channel[by_cat_channel[“カテゴリ”] == category] cat_total = cat_data[“売上_今年”].sum() print(f” {category} ({cat_total:,.0f}万円)”) for _, row in cat_data.iterrows(): share = row[“売上_今年”] / cat_total * 100 print(f” ├── {row[‘チャネル’]}: {row[‘売上_今年’]:,.0f}万円”) print(f” │ カテゴリ内構成比: {share:.1f}% 前年比: {row[‘前年比’]:+.1f}%”) print() # MECEチェック level2_total = by_category[“売上_今年”].sum() level3_total = by_cat_channel[“売上_今年”].sum() print(“【MECEチェック】”) print(f” 全体: {total_this_year:,}万円”) print(f” レベル2合計: {level2_total:,.0f}万円”) print(f” レベル3合計: {level3_total:,.0f}万円”) if abs(total_this_year – level2_total) < 1 and abs(total_this_year - level3_total) < 1: print(" ✓ MECE検証OK:すべてのレベルで合計が一致") else: print(" ✗ MECE違反:合計が一致しません")
【What Tree:売上の要素分解】 ====================================================================== ■ レベル1:全体 売上合計: 8,350万円(前年比 -0.6%) ■ レベル2:カテゴリ別分解 ├── 家電: 4,700万円 │ 構成比: 56.3% 前年比: -2.1% ├── アパレル: 2,400万円 │ 構成比: 28.7% 前年比: +0.0% ├── 食品: 1,250万円 │ 構成比: 15.0% 前年比: +4.2% ■ レベル3:カテゴリ × チャネル別分解 家電 (4,700万円) ├── 店舗: 2,700万円 │ カテゴリ内構成比: 57.4% 前年比: -10.0% ├── EC: 2,000万円 │ カテゴリ内構成比: 42.6% 前年比: +11.1% アパレル (2,400万円) ├── 店舗: 1,300万円 │ カテゴリ内構成比: 54.2% 前年比: -13.3% ├── EC: 1,100万円 │ カテゴリ内構成比: 45.8% 前年比: +22.2% 食品 (1,250万円) ├── 店舗: 700万円 │ カテゴリ内構成比: 56.0% 前年比: -6.7% ├── EC: 550万円 │ カテゴリ内構成比: 44.0% 前年比: +22.2% 【MECEチェック】 全体: 8,350万円 レベル2合計: 4,700万円 → 8,350万円 レベル3合計: 8,350万円 ✓ MECE検証OK:すべてのレベルで合計が一致
💡 What Treeから得られる洞察

店舗チャネルが全カテゴリで減少(家電▲10%、アパレル▲13.3%、食品▲6.7%)
ECチャネルが全カテゴリで増加(家電+11.1%、アパレル+22.2%、食品+22.2%)
店舗からECへのシフトが進行中
→ 次はWhy Treeで「なぜ店舗が減少しているか」を分析

Step 3:Why Tree(原因追求型)の実装

店舗売上減少の原因を、データに基づいて深掘りします。

# ============================================ # Step 3:Why Tree(原因追求型)の実装 # ============================================ # 目的:店舗売上減少の原因を特定する print(“【Why Tree:店舗売上減少の原因分析】”) print(“=” * 70) print() # —– 店舗データを抽出 —– store_data = df[df[“チャネル”] == “店舗”].copy() # 店舗全体の売上変化 store_last = store_data[“売上_前年”].sum() store_this = store_data[“売上_今年”].sum() store_change = store_this – store_last store_growth = (store_this / store_last – 1) * 100 print(“■ メインイシュー:店舗売上が減少している”) print(f” 店舗売上: {store_last:,}万円 → {store_this:,}万円”) print(f” 変化額: {store_change:+,}万円(前年比 {store_growth:+.1f}%)”) print() # —– レベル1:顧客タイプ別の分解 —– print(“■ 原因レベル1:どの顧客タイプが減少?”) by_customer = store_data.groupby(“顧客タイプ”).agg({ “売上_前年”: “sum”, “売上_今年”: “sum” }).reset_index() by_customer[“変化額”] = by_customer[“売上_今年”] – by_customer[“売上_前年”] by_customer[“前年比”] = (by_customer[“売上_今年”] / by_customer[“売上_前年”] – 1) * 100 by_customer[“寄与度”] = by_customer[“変化額”] / store_last * 100 for _, row in by_customer.iterrows(): print(f” ├── {row[‘顧客タイプ’]}顧客: {row[‘変化額’]:+,.0f}万円”) print(f” │ 前年比: {row[‘前年比’]:+.1f}% 寄与度: {row[‘寄与度’]:+.1f}%”) print() # —– レベル2:カテゴリ×顧客タイプの詳細分解 —– print(“■ 原因レベル2:カテゴリ別の詳細”) by_cat_cust = store_data.groupby([“カテゴリ”, “顧客タイプ”]).agg({ “売上_前年”: “sum”, “売上_今年”: “sum” }).reset_index() by_cat_cust[“変化額”] = by_cat_cust[“売上_今年”] – by_cat_cust[“売上_前年”] by_cat_cust[“前年比”] = (by_cat_cust[“売上_今年”] / by_cat_cust[“売上_前年”] – 1) * 100 # 変化額が大きい順にソート(減少が大きい順) by_cat_cust_sorted = by_cat_cust.sort_values(“変化額”) print(” 【減少が大きい順】”) for _, row in by_cat_cust_sorted.iterrows(): impact = “★” if row[“変化額”] < -100 else "" print(f" ├── {row['カテゴリ']}×{row['顧客タイプ']}: {row['変化額']:+,.0f}万円 ({row['前年比']:+.1f}%) {impact}") print() # ----- 原因の要約 ----- print("■ Why Treeの結論") print("=" * 70) # 最大の減少要因を特定 worst = by_cat_cust_sorted.iloc[0] print(f" 【根本原因の特定】") print(f" 最大の減少: {worst['カテゴリ']}×{worst['顧客タイプ']} ({worst['変化額']:+,.0f}万円)") print() print(" 【原因の構造】") print(f" 店舗売上減少 {store_change:+,}万円") print(f" └── 新規顧客の減少が主因(寄与度大)") print(f" ├── 家電×新規: ▲200万円 ★最大") print(f" ├── アパレル×新規: ▲100万円") print(f" └── 食品×新規: ▲20万円") print() print(" → 「なぜ新規顧客が店舗に来なくなったか」をさらに深掘りする必要あり")
【Why Tree:店舗売上減少の原因分析】 ====================================================================== ■ メインイシュー:店舗売上が減少している 店舗売上: 5,250万円 → 4,700万円 変化額: -550万円(前年比 -10.5%) ■ 原因レベル1:どの顧客タイプが減少? ├── 既存顧客: -230万円 │ 前年比: -7.3% 寄与度: -4.4% ├── 新規顧客: -320万円 │ 前年比: -15.2% 寄与度: -6.1% ■ 原因レベル2:カテゴリ別の詳細 【減少が大きい順】 ├── 家電×新規: -200万円 (-16.7%) ★ ├── アパレル×新規: -100万円 (-16.7%) ├── 家電×既存: -100万円 (-5.6%) ├── アパレル×既存: -100万円 (-11.1%) ├── 食品×既存: -30万円 (-6.7%) ├── 食品×新規: -20万円 (-6.7%) ■ Why Treeの結論 ====================================================================== 【根本原因の特定】 最大の減少: 家電×新規 (-200万円) 【原因の構造】 店舗売上減少 -550万円 └── 新規顧客の減少が主因(寄与度大) ├── 家電×新規: ▲200万円 ★最大 ├── アパレル×新規: ▲100万円 └── 食品×新規: ▲20万円 → 「なぜ新規顧客が店舗に来なくなったか」をさらに深掘りする必要あり
📝 寄与度の計算方法

寄与度 = 各要素の変化額 ÷ 全体の前年売上 × 100

例:新規顧客の寄与度
= ▲320万円 ÷ 5,250万円 × 100 = ▲6.1%

寄与度を使うことで、「全体の減少のうち、どの要素がどれだけ影響しているか」が分かります。

Step 4:How Tree(問題解決型)の実装

Why Treeで特定した原因に対する解決策を、データに基づいて立案します。

# ============================================ # Step 4:How Tree(問題解決型)の実装 # ============================================ # 目的:店舗売上回復のための施策を立案する print(“【How Tree:店舗売上回復の施策立案】”) print(“=” * 70) print() # —– 目標設定 —– # 前年水準への回復を目標 target_increase = abs(store_change) # 550万円の回復が必要 print(“■ 目標:店舗売上を前年水準に回復”) print(f” 必要な売上増: +{target_increase:,}万円”) print() # —– 施策案の定義 —– # 各施策の効果を試算(仮説ベース) strategies = [ { “施策”: “店舗限定セールの実施”, “対象”: “全カテゴリ×新規”, “投資”: 50, # 万円 “期待効果”: 150, # 万円 “実現性”: “高”, “期間”: “1ヶ月” }, { “施策”: “店舗スタッフの接客強化”, “対象”: “家電×新規”, “投資”: 100, “期待効果”: 200, “実現性”: “中”, “期間”: “3ヶ月” }, { “施策”: “店舗とECのポイント共通化”, “対象”: “全カテゴリ×既存”, “投資”: 80, “期待効果”: 120, “実現性”: “高”, “期間”: “2ヶ月” }, { “施策”: “店舗限定商品の開発”, “対象”: “アパレル×新規”, “投資”: 200, “期待効果”: 180, “実現性”: “低”, “期間”: “6ヶ月” } ] # DataFrameに変換して分析 df_strategies = pd.DataFrame(strategies) # ROI(投資対効果)を計算 df_strategies[“ROI”] = (df_strategies[“期待効果”] – df_strategies[“投資”]) / df_strategies[“投資”] * 100 # ROIが高い順にソート df_strategies = df_strategies.sort_values(“ROI”, ascending=False) print(“■ 施策案(ROI順)”) print(“-” * 70) total_effect = 0 total_invest = 0 selected = [] for i, (_, row) in enumerate(df_strategies.iterrows(), 1): roi_star = “★” if row[“ROI”] >= 100 else “” print(f” {i}. {row[‘施策’]}”) print(f” 対象: {row[‘対象’]}”) print(f” 投資: {row[‘投資’]:,}万円 → 期待効果: {row[‘期待効果’]:,}万円”) print(f” ROI: {row[‘ROI’]:+.0f}% 実現性: {row[‘実現性’]} 期間: {row[‘期間’]} {roi_star}”) print() # ROI 100%以上かつ実現性が中以上を選択 if row[“ROI”] >= 100 and row[“実現性”] in [“高”, “中”]: total_effect += row[“期待効果”] total_invest += row[“投資”] selected.append(row[“施策”]) # —– 施策の組み合わせ評価 —– print(“■ 推奨施策の組み合わせ”) print(“=” * 70) print(” 【選定基準】”) print(” ・ROI 100%以上”) print(” ・実現性が「高」または「中」”) print() print(” 【選定された施策】”) for s in selected: print(f” ✓ {s}”) print() print(” 【期待される効果】”) print(f” 投資合計: {total_invest:,}万円”) print(f” 期待効果合計: {total_effect:,}万円”) print(f” 目標達成率: {total_effect / target_increase * 100:.1f}%”) print() # 目標達成判定 if total_effect >= target_increase: print(f” ✓ 目標(+{target_increase:,}万円)を達成見込み!”) else: gap = target_increase – total_effect print(f” △ 目標まであと {gap:,}万円の施策が必要”)
【How Tree:店舗売上回復の施策立案】 ====================================================================== ■ 目標:店舗売上を前年水準に回復 必要な売上増: +550万円 ■ 施策案(ROI順) ———————————————————————- 1. 店舗限定セールの実施 対象: 全カテゴリ×新規 投資: 50万円 → 期待効果: 150万円 ROI: +200% 実現性: 高 期間: 1ヶ月 ★ 2. 店舗スタッフの接客強化 対象: 家電×新規 投資: 100万円 → 期待効果: 200万円 ROI: +100% 実現性: 中 期間: 3ヶ月 ★ 3. 店舗とECのポイント共通化 対象: 全カテゴリ×既存 投資: 80万円 → 期待効果: 120万円 ROI: +50% 実現性: 高 期間: 2ヶ月 4. 店舗限定商品の開発 対象: アパレル×新規 投資: 200万円 → 期待効果: 180万円 ROI: -10% 実現性: 低 期間: 6ヶ月 ■ 推奨施策の組み合わせ ====================================================================== 【選定基準】 ・ROI 100%以上 ・実現性が「高」または「中」 【選定された施策】 ✓ 店舗限定セールの実施 ✓ 店舗スタッフの接客強化 【期待される効果】 投資合計: 150万円 期待効果合計: 350万円 目標達成率: 63.6% △ 目標まであと 200万円の施策が必要

Step 5:イシューツリーの実装

「問い」の形式で課題を分解し、仮説検証の計画を立てます。

# ============================================ # Step 5:イシューツリーの実装 # ============================================ # 目的:問いを分解して仮説検証計画を立てる print(“【イシューツリー:新規顧客減少の仮説検証】”) print(“=” * 70) print() # イシューツリーを辞書で定義 # 各イシューには「問い」「仮説」「検証方法」「判定基準」を設定 issue_tree = { “メインイシュー”: “なぜ店舗の新規顧客が減少しているか?”, “サブイシュー”: [ { “問い”: “集客が減っているか?”, “仮説”: “来店客数が前年比▲20%減少”, “検証方法”: “店舗の入店カウンターデータ”, “判定基準”: “前年比▲10%以上で問題あり”, “検証結果”: “▲18%(仮説支持)”, “詳細イシュー”: [ { “問い”: “認知が低下しているか?”, “仮説”: “広告露出が前年比▲30%”, “検証方法”: “広告出稿データ”, “判定基準”: “前年比▲15%以上で問題あり”, “検証結果”: “▲25%(仮説支持)” }, { “問い”: “競合に流出しているか?”, “仮説”: “近隣競合の売上が+15%”, “検証方法”: “競合調査データ”, “判定基準”: “競合+10%以上で影響大”, “検証結果”: “+12%(仮説支持)” } ] }, { “問い”: “購買率が下がっているか?”, “仮説”: “来店からの購買率が前年比▲5%”, “検証方法”: “POS×入店データ”, “判定基準”: “前年比▲3%以上で問題あり”, “検証結果”: “▲2%(仮説棄却)”, “詳細イシュー”: [] }, { “問い”: “客単価が下がっているか?”, “仮説”: “新規顧客の客単価が▲10%”, “検証方法”: “POSデータ(新規顧客)”, “判定基準”: “前年比▲5%以上で問題あり”, “検証結果”: “▲3%(仮説棄却)”, “詳細イシュー”: [] } ] } # イシューツリーを表示 print(f”■ {issue_tree[‘メインイシュー’]}”) print() for i, sub in enumerate(issue_tree[“サブイシュー”], 1): # 検証結果から支持/棄却を判定 is_supported = “支持” in sub[“検証結果”] status = “★要対策” if is_supported else “→問題なし” print(f” {i}. {sub[‘問い’]}”) print(f” 仮説: {sub[‘仮説’]}”) print(f” 検証: {sub[‘検証方法’]}”) print(f” 結果: {sub[‘検証結果’]} {status}”) # 詳細イシューがある場合 if sub[“詳細イシュー”]: for j, detail in enumerate(sub[“詳細イシュー”], 1): detail_supported = “支持” in detail[“検証結果”] detail_status = “★★根本原因” if detail_supported else “” print(f” {i}-{j}. {detail[‘問い’]}”) print(f” 仮説: {detail[‘仮説’]}”) print(f” 結果: {detail[‘検証結果’]} {detail_status}”) print() # —– 検証結果のサマリー —– print(“■ イシューツリーの結論”) print(“=” * 70) print() print(” 【根本原因として特定】”) print(” 1. 広告露出の減少(▲25%)→ 認知低下”) print(” 2. 競合への流出(競合+12%)→ 相対的魅力度低下”) print() print(” 【問題なしと判定】”) print(” ・購買率: ▲2%(基準の▲3%以内)”) print(” ・客単価: ▲3%(基準の▲5%以内)”) print() print(” 【次のアクション】”) print(” → 広告投資の回復と、競合差別化施策の検討”)
【イシューツリー:新規顧客減少の仮説検証】 ====================================================================== ■ なぜ店舗の新規顧客が減少しているか? 1. 集客が減っているか? 仮説: 来店客数が前年比▲20%減少 検証: 店舗の入店カウンターデータ 結果: ▲18%(仮説支持) ★要対策 1-1. 認知が低下しているか? 仮説: 広告露出が前年比▲30% 結果: ▲25%(仮説支持) ★★根本原因 1-2. 競合に流出しているか? 仮説: 近隣競合の売上が+15% 結果: +12%(仮説支持) ★★根本原因 2. 購買率が下がっているか? 仮説: 来店からの購買率が前年比▲5% 検証: POS×入店データ 結果: ▲2%(仮説棄却) →問題なし 3. 客単価が下がっているか? 仮説: 新規顧客の客単価が▲10% 検証: POSデータ(新規顧客) 結果: ▲3%(仮説棄却) →問題なし ■ イシューツリーの結論 ====================================================================== 【根本原因として特定】 1. 広告露出の減少(▲25%)→ 認知低下 2. 競合への流出(競合+12%)→ 相対的魅力度低下 【問題なしと判定】 ・購買率: ▲2%(基準の▲3%以内) ・客単価: ▲3%(基準の▲5%以内) 【次のアクション】 → 広告投資の回復と、競合差別化施策の検討
📌 イシューツリーのポイント

・各「問い」に対して仮説判定基準を事前に設定
・データで検証し、仮説が支持されるか棄却されるかを判定
・棄却された仮説は「問題なし」として除外し、支持された仮説を深掘り
・これにより、効率的に根本原因にたどり着ける

Step 6:分析結果の可視化

ここまでの分析結果を、グラフで分かりやすく可視化します。

# ============================================ # Step 6:分析結果の可視化 # ============================================ # 目的:分析結果を4つのグラフで可視化する fig, axes = plt.subplots(2, 2, figsize=(14, 10)) # ============================================ # グラフ1:チャネル別売上の前年比較(What Tree) # ============================================ ax1 = axes[0, 0] # チャネル別にデータを集計 channel_data = df.groupby(“チャネル”).agg({ “売上_前年”: “sum”, “売上_今年”: “sum” }).reset_index() x = np.arange(len(channel_data)) # X軸の位置 width = 0.35 # 棒の幅 # 前年と今年の棒グラフを並べて表示 bars1 = ax1.bar(x – width/2, channel_data[“売上_前年”], width, label=”前年”, color=”#90caf9″, alpha=0.8) bars2 = ax1.bar(x + width/2, channel_data[“売上_今年”], width, label=”今年”, color=”#1976d2″, alpha=0.8) ax1.set_xlabel(“チャネル”, fontsize=11) ax1.set_ylabel(“売上(万円)”, fontsize=11) ax1.set_title(“【What Tree】チャネル別売上の前年比較”, fontsize=13, fontweight=”bold”) ax1.set_xticks(x) ax1.set_xticklabels(channel_data[“チャネル”]) ax1.legend() ax1.grid(axis=”y”, alpha=0.3) # 前年比を棒の上に表示 for i, (last, this) in enumerate(zip(channel_data[“売上_前年”], channel_data[“売上_今年”])): growth = (this / last – 1) * 100 color = “#d32f2f” if growth < 0 else "#388e3c" ax1.annotate(f"{growth:+.1f}%", xy=(i + width/2, this), ha="center", va="bottom", fontsize=10, color=color, fontweight="bold") # ============================================ # グラフ2:顧客タイプ別の変化(Why Tree) # ============================================ ax2 = axes[0, 1] # 顧客タイプ別にデータを集計 customer_data = df.groupby("顧客タイプ").agg({ "売上_前年": "sum", "売上_今年": "sum" }).reset_index() customer_data["変化額"] = customer_data["売上_今年"] - customer_data["売上_前年"] # 変化額を水平棒グラフで表示 colors = ["#d32f2f" if x < 0 else "#388e3c" for x in customer_data["変化額"]] bars = ax2.barh(customer_data["顧客タイプ"], customer_data["変化額"], color=colors, alpha=0.8) ax2.set_xlabel("売上変化(万円)", fontsize=11) ax2.set_title("【Why Tree】顧客タイプ別の売上変化", fontsize=13, fontweight="bold") ax2.axvline(x=0, color="black", linewidth=0.5) # ゼロ線 ax2.grid(axis="x", alpha=0.3) # 値を表示 for bar, val in zip(bars, customer_data["変化額"]): x_pos = val + 10 if val >= 0 else val – 10 ha = “left” if val >= 0 else “right” ax2.text(x_pos, bar.get_y() + bar.get_height()/2, f”{val:+,.0f}万円”, ha=ha, va=”center”, fontsize=10, fontweight=”bold”) # ============================================ # グラフ3:カテゴリ×チャネル別の前年比(ヒートマップ風) # ============================================ ax3 = axes[1, 0] # ピボットテーブルを作成 pivot = df.pivot_table(index=”カテゴリ”, columns=”チャネル”, values=”前年比”, aggfunc=”mean”) # カラーマップで可視化(赤:減少、緑:増加) im = ax3.imshow(pivot.values, cmap=”RdYlGn”, aspect=”auto”, vmin=-20, vmax=25) # ラベル設定 ax3.set_xticks(np.arange(len(pivot.columns))) ax3.set_yticks(np.arange(len(pivot.index))) ax3.set_xticklabels(pivot.columns) ax3.set_yticklabels(pivot.index) ax3.set_title(“【分析】カテゴリ×チャネル別 前年比(%)”, fontsize=13, fontweight=”bold”) # 各セルに値を表示 for i in range(len(pivot.index)): for j in range(len(pivot.columns)): val = pivot.values[i, j] color = “white” if abs(val) > 10 else “black” ax3.text(j, i, f”{val:+.1f}%”, ha=”center”, va=”center”, color=color, fontsize=12, fontweight=”bold”) # カラーバー plt.colorbar(im, ax=ax3, label=”前年比(%)”) # ============================================ # グラフ4:施策のROI比較(How Tree) # ============================================ ax4 = axes[1, 1] # 施策データ strategy_names = [“店舗限定セール”, “接客強化”, “ポイント共通化”, “限定商品開発”] strategy_roi = [200, 100, 50, -10] strategy_effect = [150, 200, 120, 180] # ROIを棒グラフで表示 colors = [“#388e3c” if x >= 100 else “#ff9800” if x >= 0 else “#d32f2f” for x in strategy_roi] bars = ax4.bar(strategy_names, strategy_roi, color=colors, alpha=0.8) ax4.set_ylabel(“ROI(%)”, fontsize=11) ax4.set_title(“【How Tree】施策別ROI比較”, fontsize=13, fontweight=”bold”) ax4.axhline(y=100, color=”green”, linestyle=”–“, linewidth=2, label=”ROI 100%ライン”) ax4.axhline(y=0, color=”black”, linewidth=0.5) ax4.legend() ax4.grid(axis=”y”, alpha=0.3) # ROIの値を表示 for bar, roi, effect in zip(bars, strategy_roi, strategy_effect): height = bar.get_height() y_pos = height + 5 if height >= 0 else height – 15 ax4.text(bar.get_x() + bar.get_width()/2., y_pos, f”{roi:+}%\n({effect}万円)”, ha=”center”, va=”bottom” if height >= 0 else “top”, fontsize=9, fontweight=”bold”) # X軸ラベルを斜めに ax4.set_xticklabels(strategy_names, rotation=15, ha=”right”) plt.tight_layout() plt.savefig(“logic_tree_analysis.png”, dpi=150, bbox_inches=”tight”) plt.show() print(“✓ グラフを保存しました: logic_tree_analysis.png”)
💡 可視化のポイント

グラフ1(What Tree):構造を把握(どこが減っているか)
グラフ2(Why Tree):原因を特定(新規/既存どちらが問題か)
グラフ3(詳細分析):カテゴリ×チャネルのクロス分析
グラフ4(How Tree):施策の優先順位付け(ROI比較)

📝 STEP 45 のまとめ

✅ このステップで学んだこと
  • ロジックツリー:What(要素分解)、Why(原因追求)、How(問題解決)の3タイプ
  • イシューツリー:「問い」の形で分解し、仮説検証をガイド
  • MECE:各階層で漏れなく・ダブりなく分解することの重要性
  • Pythonでの実装:データに基づくツリー分析と可視化
  • 実務応用:問題発見→原因分析→解決策立案の一連の流れ
💡 ロジックツリーとイシューツリーの使い分け

ロジックツリーを使う場面:

・売上や利益の構造を把握したい
・問題の原因を洗い出したい
・解決策のオプションを整理したい
・プレゼンで論理構造を見せたい

イシューツリーを使う場面:

・仮説検証の計画を立てたい
・限られた時間で効率的に分析したい
・チームで分担して検証したい
・意思決定の根拠を明確にしたい

組み合わせのベストプラクティス:

1. What Tree で全体像を把握
2. イシューツリー で検証すべき問いを設定
3. Why Tree で原因を深掘り
4. How Tree で解決策を具体化

📋 実務で使えるチェックリスト

□ 各階層でMECE(漏れなく・ダブりなく)になっているか?
□ 分解の粒度は適切か?(細かすぎず、粗すぎず)
□ データで検証可能なレベルまで分解できているか?
□ 仮説と判定基準を事前に設定しているか?
□ アクションにつながる分解になっているか?
□ ステークホルダーが理解できる構造か?

📝 練習問題

問題 1 基礎

以下の状況に対して、適切なロジックツリーのタイプ(What/Why/How)を選び、第2階層まで作成してください。

状況:あなたはレストランチェーンのマネージャーです。今月の利益が目標を20%下回りました。

【解答】3つのツリーを順番に使用

① What Tree(まず構造を把握)

利益 = 売上 – コスト ├── 売上(▲15%) │ ├── 客数(▲10%) │ └── 客単価(▲5%) └── コスト(+5%) ├── 食材費(+8%) └── 人件費(+2%)

② Why Tree(原因を深掘り)

利益減少 ▲20% ├── 売上減少 ▲15%(主因) │ ├── 客数減少 ▲10% │ │ ├── 競合出店の影響 │ │ └── SNS評価の低下 │ └── 客単価減少 ▲5% │ └── 高単価メニューの販売不振 └── コスト増加 +5% └── 食材費高騰 +8% └── 原材料価格の上昇

③ How Tree(解決策を立案)

利益回復 +20% ├── 売上向上 │ ├── 客数増加 │ │ ├── SNSキャンペーン実施 │ │ └── ランチ時間帯の割引 │ └── 客単価向上 │ └── セットメニューの開発 └── コスト削減 └── 食材費削減 ├── 仕入先の見直し └── メニューの絞り込み
問題 2 応用

以下のデータを使って、Pythonでロジックツリー分析を行い、最も効果的な改善ポイントを特定してください。

ECサイトの月次データ:
・訪問者数:100,000人 → 80,000人(▲20%)
・カート追加率:5% → 4%(▲20%)
・購入完了率:60% → 65%(+8%)
・客単価:8,000円 → 7,500円(▲6%)

【解答】売上の構造分解と原因特定

売上の計算式:

売上 = 訪問者数 × カート追加率 × 購入完了率 × 客単価

前月:
100,000 × 5% × 60% × 8,000円 = 2,400万円

今月:
80,000 × 4% × 65% × 7,500円 = 1,560万円

変化: ▲840万円(▲35%)

寄与度分析:

各要素の影響度を計算:

・訪問者数:▲20% → ★最大の要因
・カート追加率:▲20% → ★2番目の要因
・購入完了率:+8% → プラス要因(改善済み)
・客単価:▲6% → 軽微な影響

Why Tree(原因分析):

売上減少 ▲35% ├── 訪問者数減少 ▲20%(★最重要) │ ├── 広告出稿の減少? │ ├── SEO順位の低下? │ └── 季節要因? └── カート追加率低下 ▲20%(★要改善) ├── 商品ページの問題? ├── 価格競争力の低下? └── 在庫切れの増加?

改善の優先順位:

1位:訪問者数の回復
・インパクト最大(売上の20%に直結)
・広告投資の見直し、SEO対策

2位:カート追加率の改善
・商品ページのUI改善
・レコメンド機能の強化

3位:客単価の維持
・クロスセル施策
・セット販売の強化

❓ よくある質問

Q1: ロジックツリーは何階層まで作るべきですか?
通常は3〜4階層が適切です。

階層数の目安:

2階層:概要把握、経営層への報告向け
3階層:標準的な分析、実務での最頻
4階層:詳細分析、根本原因の特定
5階層以上:複雑になりすぎるため通常は不要

分解を止める判断基準:
・アクションが明確になった
・これ以上データが取れない
・分解しても新しい洞察が得られない
Q2: イシューツリーとロジックツリーはどちらを先に作るべきですか?
状況によりますが、一般的な順序があります。

推奨の順序:

Step 1:What Tree(ロジックツリー)
まず全体の構造を把握し、どこに問題があるかを特定

Step 2:イシューツリー
問題が特定できたら、「なぜそうなっているか」を問いの形で分解

Step 3:Why Tree(ロジックツリー)
イシューツリーに基づいてデータ分析を行い、原因を深掘り

Step 4:How Tree(ロジックツリー)
原因が特定できたら、解決策を具体化

ただし、すでに問題が明確な場合は、イシューツリーから始めることもあります。
Q3: チームで分担してツリー分析を行うコツはありますか?
イシューツリーが特に分担に向いています。

分担のステップ:

1. 全員でイシューツリーを作成
・メインイシューとサブイシューを合意
・各イシューの仮説と判定基準を設定

2. サブイシューごとに担当を割り当て
・各担当が自分のイシューを検証
・期限を設定(例:3日後に中間報告)

3. 検証結果を持ち寄り統合
・各イシューの支持/棄却を報告
・根本原因を特定

4. How Treeで解決策を議論
・全員で施策案を出し合い
・優先順位を決定
📝

学習メモ

ビジネスデータ分析・意思決定 - Step 45

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE