論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
決定木
Decision Tree
「もしXがY以上なら...」のような条件分岐で予測するモデル。可読性高いが過学習しやすい。
機械学習決定木decision tree

🔖 キーワード索引

decision tree」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「decision tree」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

decision tree統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「decision tree の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

🔖 キーワード索引

決定木 ジニ不純度 情報利得 CART ID3 / C4.5 剪定 (pruning) ccp_alpha sklearn DecisionTree dtreeviz XGBoost 単木 過学習 高分散 Random Forest 勾配ブースティング

💡 30秒で分かる結論

🍰 まずはやさしく

はいかいいえで分ける樹のような仕組みです。

データを分けて答えを予測するために使います。

スマホのプラン選びのような条件分けです。

この章では決定木の基本について読みます。

📖 包括的解説 — この概念を完全マスター

📍 学習の3ステップ

  1. 定義を理解する:この概念は何か? 数式や条件を確認
  2. 具体例を見る:実データ(SSDSE 等)で計算してみる
  3. 応用する:自分のデータに適用、 結果を解釈

🔧 Python実装パターン

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A4101(出生数) A4103(合計特殊出生率) L3221(消費支出(二人以上の世帯)) 北海道 24,430 1.06 296,888 東京都 86,348 0.99 341,320 沖縄県 12,549 1.6 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 基本パターン: SSDSE-B-2026 を読み込み、決定木で使う特徴量を確認
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 1行目=英字コード, 2行目=日本語名 → コード行を列名にするため skiprows=[1]
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d23 = df[df['SSDSE-B-2026'] == 2023]          # 直近年度(2023)に絞る

# A4101:出生数, L3221:消費支出, A4103:合計特殊出生率 の関係を可視化
sns.pairplot(d23[['A4101', 'L3221', 'A4103']])
plt.show()
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 このブロックは標準出力には何も出さない
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

📚 統計概念マップでの位置

このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。

🎯 SSDSE-B-2026 で挑戦

統計データ活用コンペティションのSSDSE-B-2026データは、 47都道府県の社会経済データ。 この概念を使って以下のような分析ができます:

💡 よく使うコマンド集

機能 Python (pandas) Python (scipy)
要約統計df.describe()stats.describe()
平均df.mean()np.mean()
標準偏差df.std()np.std()
相関df.corr()stats.pearsonr()
t検定stats.ttest_ind()
回帰stats.linregress()
分布フィッティングstats.norm.fit()

🚧 一般的な落とし穴と対策

📊 結果報告の標準フォーマット

🌐 関連分野での応用

🎓 さらに学ぶための文献

🔗 統計用語ネットワーク

この概念は、 他の多くの統計概念と密接に関連しています。 ジャストインタイム型学習では、 必要に応じて関連用語へジャンプしながら全体像を構築します。

主要な関連概念のグループ

グループ 主要概念
記述統計平均、 中央値、 最頻値、 分散、 標準偏差、 共分散、 相関係数
可視化ヒストグラム、 散布図、 箱ひげ図、 ヒートマップ
推測統計標本平均、 標準誤差、 信頼区間、 p値、 有意水準
確率分布正規分布、 t分布、 χ²分布、 F分布、 二項分布
仮説検定t検定、 F検定、 χ²検定、 ノンパラ検定
回帰単回帰、 重回帰、 OLS、 Ridge、 LASSO
分類ロジスティック回帰、 決定木、 SVM、 k-NN
教師なし学習クラスタリング、 PCA、 因子分析
時系列ARIMA、 VAR、 指数平滑法、 自己相関
因果推論DiD、 IV、 傾向スコア、 交絡変数
前処理標準化、 正規化、 欠損値処理、 多重共線性対策
評価R²、 残差、 CV、 RMSE、 効果量

学習順序の推奨

  1. 記述統計(平均、 分散、 標準偏差)
  2. 可視化(ヒストグラム、 散布図)
  3. 確率分布(正規分布)
  4. 推測統計(標準誤差、 信頼区間、 p値)
  5. 仮説検定(t検定、 χ²検定)
  6. 相関と回帰(単回帰、 重回帰)
  7. 多変量解析(PCA、 クラスタリング)
  8. 機械学習(決定木、 RF、 NN)
  9. 時系列・因果推論(応用)

📝 実践練習 — SSDSE-B-2026 で挑戦

初級課題

  1. 東北6県の家計食料費の基本統計量を計算
  2. 食料費のヒストグラムを描く
  3. 食料費と教育費の散布図を描く
  4. 都道府県を「東日本/西日本」に分け、 平均を比較

中級課題

  1. 家計支出 5項目で相関行列を作成、 ヒートマップ可視化
  2. 食料費 → 教育費の単回帰を実行、 残差分析
  3. 家計5項目で PCA を実施、 バイプロット表示
  4. k-means (k=3) で都道府県をクラスタリング、 解釈

上級課題

  1. 地域別の家計パターンに有意差があるか ANOVA で検定
  2. 重回帰で教育費を予測、 多重共線性を VIF で確認
  3. Ridge/LASSO で正則化、 CV で α を最適化
  4. 階層クラスタリングと Ward 法で都道府県を分類、 デンドログラム作成

📍 あなたが今見ているもの

🍰 まずはやさしく

条件を繰り返して答えを出すモデルです。

どのデータが重要かを見つけるために使います。

地域の人口でグループを分けるような例です。

ここでは具体的なデータの分け方を読みます。

論文中に 「決定木」として登場する用語。

決定木 とは:「もしXがY以上なら...」のような条件分岐で予測するモデル。可読性高いが過学習しやすい。

本ページでは SSDSE-B-2026 の総人口 (A1101) が 200 万人以上か否かを目的変数に、 年平均気温 (B4101)・消費支出 (L3221)・合計特殊出生率 (A4103) を特徴量として深さ 3 の決定木を訓練し、 分岐条件と葉ノード値・特徴重要度・テキスト/グラフでの可視化を実演する。

「decision tree」は 特徴量の閾値による再帰的分割で予測する非線形モデルで、 各内部ノードは「X < t」の二分質問、 葉ノードは予測値 (回帰なら平均、 分類ならクラス) を保持する。 分割基準は不純度の減少 (Gini / エントロピー / MSE)、 過学習対策に剪定 (pruning) と深さ制限がある。 本ページでは ID3 / CART / RandomForest / GBDT への発展を扱う。

🎨 直感で掴む — 決定木 の本質

🍰 まずはやさしく

質問を繰り返して絞り込むゲームのようなものです。

ルールを分かりやすく見える化するために使います。

部活のメンバー選びのような条件分けです。

ここでは仕組みを直感的に理解して読みます。

決定木は「はい/いいえの質問を繰り返してデータを分けていく」モデル。 SSDSE-B-2026 で合計特殊出生率(A4103)を予測するとき、 「総人口 > 500 万?」「いいえ → 65歳以上人口比率 > 30%?」のように分岐し、 最終的に各葉ノードで「出生率の平均」を予測する。 ルールが可視化できるのが最大の利点。

💡 ポイント:決定木 を初めて学ぶときは「正確な定義」より「どんな問題を解くための道具か」を先に押さえてください。 数式は次の「📐 数式」セクションで丁寧に展開します。
📌 比喩がうまく刺さらないときは、 自分の身近な例(家計簿・スポーツの記録・成績表)に置き換えてみると理解が定着します。 SSDSE-B-2026 を電卓代わりに触りながら、 上の説明を再読すると効果的です。

🎨 概念図で押さえる

決定木は 「特徴空間を軸平行な矩形へ再帰分割し、 各葉に多数決クラスまたは平均値を割り当てる」。 以下 3 つの図で「分割の幾何」「Gini と情報量」「深さと過学習」を視覚化する。

図 1: 軸平行分割が作る矩形領域

葉 A クラス 0 葉 B クラス 1 葉 C: クラス 2 x1 = 3.5 で分割 x2 = 2.0 x2 x1

→ 決定木の分割は 常に座標軸に平行。 斜め境界が必要な問題は深い木になりがちで、 そこが SVM やロジ回との大きな違い。

図 2: Gini 不純度の分割評価

親ノード Gini = 0.50 (50:50) 左子: 90:10 Gini = 0.18 右子: 30:70 Gini = 0.42 情報利得 ΔGini = 0.50 − 0.30 = 0.20 最大の特徴・閾値を選ぶ

→ 分割は 「子の重み付き Gini を最小化」。 これが情報利得最大化と同義。 全特徴・全閾値を貪欲探索する。

図 3: 深さと過学習

深さ 誤差 訓練誤差↓ 汎化誤差 ∪ 最適深さ 深すぎ → 過学習 葉が個別データを暗記

深さ 1 増えるごとに葉が倍。 訓練誤差は単調減少だが、 汎化誤差は最適深さ後に再び上昇。 max_depthccp_alpha で正則化する。

🎨 概念図で押さえる(決定木の全体像)

決定木の構造図(ノード分岐とリーフ予測)
図 R240-1: 決定木の構造。 ルートから条件分岐を辿り、 葉ノードで予測値(クラスまたは数値)が決定される。
非線形決定境界の例
図 R240-2: 決定木は座標軸に平行な分割で非線形な決定境界を構築できる。 ロジスティック回帰など線形モデルとの差異を視覚的に把握できる。
正則化と過学習
図 R240-3: 正則化と過学習の概念図。 決定木では深さ・葉数を制御する正則化(max_depth, ccp_alpha)で過学習を防ぐ。

✅ 理解度チェック — 決定木の核心を自問する 8 問

SSDSE-B-2026 (47 都道府県データ) を題材に、 決定木の本質を自問する 8 問。 各問は 分岐基準・剪定・過学習・解釈性・アンサンブル という 5 つの核心概念から構成されている。 答えを隠して 60 秒ほど考えてから読み進めてほしい。

Q1. SSDSE-B-2026 の「消費支出 (L3221)」を目的変数に決定木回帰を構築するとき、 分岐基準は何を使うべきか?
A1. 分散減少 (MSE 削減) を使う。 各分割候補に対し $\Delta = \mathrm{Var}(\text{親}) - \frac{n_L}{n}\mathrm{Var}(\text{左}) - \frac{n_R}{n}\mathrm{Var}(\text{右})$ を最大化する分割を採用する。 分類問題のジニ・エントロピーは連続値目的変数では使えない。
Q2. 葉ノード数が 47 (=都道府県数) になるまで分岐させた決定木の問題点は?
A2. 訓練データ上は完全に再現できるが、 各葉が 1 サンプルのみで 純粋な過学習。 新しい都道府県データ (もし沖縄が分裂したら?など) には全く対応できない。 max_depth・min_samples_leaf・ccp_alpha による剪定が必須。
Q3. 「年平均気温 (B4101) が高いと出生率 (A4103) 高」というルールが上位に来た。 これは因果関係か?
A3. 相関であって因果ではない。 決定木は予測パターンを学習するだけで、 交絡変数 (例: 地方部であることが両者を引き起こす) を考慮しない。 因果推論には DAG・操作変数・回帰不連続といった別枠組みが必要。
Q4. CART・ID3・C4.5 の違いを一行で説明せよ。
A4. ID3 = 情報利得・離散値のみ、 C4.5 = 情報利得比・連続値対応・剪定あり、 CART = ジニ不純度・二分木・分類と回帰両対応。 scikit-learn の DecisionTreeClassifier は CART を実装している。
Q5. ランダムフォレストとは何が違うか?
A5. RF は決定木のアンサンブル。 ブートストラップサンプリング + 特徴量サブセットで 分散を下げる。 単体の決定木は高分散だが、 RF は数百本の平均で安定する。 ただし解釈性は犠牲になる (1 本の木の可視化はできなくなる)。
Q6. ccp_alpha パラメータの役割は?
A6. Cost-Complexity Pruning の正則化係数。 大きくすると葉数が減り、 単純な木になる。 0 では剪定なし、 ∞ では根ノードのみ。 交差検証で最適値を探すのが標準手順。
Q7. 決定木が「外挿不可」と言われる理由は?
A7. 葉ノードの予測値は訓練データの平均値であり、 訓練データ外の領域 (例: 人口 5000 万の県) は最も近い葉の値を返すだけ。 線形回帰なら直線を伸ばして外挿できるが、 木は階段関数なので定義域外の値は予測できない
Q8. 解釈性を保ちつつ精度を上げるには?
A8. (1) 深さを制限した浅い木で SHAP 値 を併用、 (2) 勾配ブースティング + SHAP で特徴量寄与を可視化、 (3) Rule Fit で重要ルールだけ抽出、 (4) EBM (Explainable Boosting Machine) を使う ── など。 ブラックボックス化を避けつつ高精度を狙う実務的選択肢。

🎮 触って理解する — 決定木の決定境界プレイグラウンド

ここはマウス/タッチで直接触れる決定木の実験場です。 左のキャンバスをクリック(タップ)して2クラスの点を配置し、 最大深さスライダーを動かすと、 その場で決定木が学習され、 軸平行な矩形で塗り分けられた決定境界がリアルタイムに描画されます。 深さを浅くすると粗い境界(未学習・欠学習)、 深くすると点1つ1つを暗記する複雑な境界(過学習)になる様子を体感してください。 計算は本ページの数式どおりの簡易CART(貪欲な二分割)で、 ジニ不純度情報利得(エントロピー)を切り替えられます。

横軸 x₁ / 縦軸 x₂(クリック=現在のクラスの点を追加)
配置するクラス

1(粗い=欠学習)8(複雑=過学習)
分割基準

🌳 学習された木構造(各分割の不純度低下)

💡 観察のヒント:① 2つの塊を離して置き、 深さ1でもきれいに分かれることを確認 → ② 塊を混ぜ合わせ、 深さを上げないと分けられないことを確認 → ③ XOR配置(対角に同クラス)で、 決定木が斜め境界を「階段状の矩形」で近似する様子を観察 → ④ 点を1つだけポツンと敵陣に置き、 深さを最大にするとその1点のためだけに小さな矩形ができる=過学習を目撃してください。

🧩 決定木の仕組みを深掘り — 再帰分割から集団学習まで

① 再帰分割:木がデータを切り分ける手続き

決定木の学習は再帰的な二分割の繰り返しです。 (1) 現在のノードに含まれるデータの不純度を測る → (2) すべての特徴量・すべての閾値の組を試し、 分割後の子ノードの重み付き不純度が最小になる分割を貪欲に選ぶ → (3) 左右の子ノードそれぞれで同じ操作を再帰的に繰り返す → (4) 停止条件(max_depth 到達・ノードが純粋・サンプル数が下限未満)で葉ノードにする。 上のプレイグラウンドが行っているのが、 まさにこの手続きです。 各内部ノードは「x₁ < t」型の軸平行な質問1つに対応し、 特徴空間は矩形へと再帰的に分割されます。

② 不純度指標:分割の「良さ」をどう測るか

分割の良し悪しは不純度(impurity)の低下量で測ります。 分類では2つの指標が代表的です。

どちらを使っても「子の重み付き不純度を最小化する=親からの低下量を最大化する」という貪欲基準は同じで、 実データ上では選ばれる分割がほぼ一致することが多いです。 プレイグラウンドで両者を切り替えても、 決定境界が大きくは変わらないことを確認できます。

③ 過学習と枝刈り:深さは諸刃の剣

深さを増やすほど訓練データへの当てはまりは良くなりますが、 ある点を超えるとノイズや個別事例まで暗記して汎化性能が落ちます(過学習)。 対策は2系統あります。 事前剪定(pre-pruning)max_depthmin_samples_leafmin_samples_split で成長を止める。 事後剪定(post-pruning)= 一度深く育ててから ccp_alpha(コスト複雑度剪定 $R_\alpha(T)=R(T)+\alpha|T|$)で葉を刈り込む。 いずれも正則化の一種で、 最適な強さは交差検証で選ぶのが定石です。

④ アンサンブルへの発展:1本の弱さを束で補う

単体の決定木は高分散(訓練データがわずかに変わると木構造が激変する)という弱点があります。 これを克服するのがアンサンブルです。

解釈性が欲しければ浅い単体木(深さ3〜5)、 予測精度が欲しければアンサンブル、 という使い分けが実務の基本です。

⑤ 長所と短所のまとめ

✅ 長所⚠️ 短所
if-then ルールで解釈性が高い(可視化できる)高分散で不安定(1本では過学習しやすい)
標準化・正規化などの前処理が不要斜めの境界が苦手(軸平行の階段近似)
非線形・交互作用を自動で捉える外挿不可(訓練範囲外は最寄り葉の定数)
数値・カテゴリ・欠損に柔軟(実装による)滑らかな線形関係の表現が非効率

📐 数式または定義 — 決定木 の形式的表現

🍰 まずはやさしく

数式で決めたルールで分ける仕組みです。

一番きれいにデータを分ける方法を探します。

テストの点数で合格か不合格に分ける例です。

ここでは計算方法について詳しく読みます。

直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。

【不純度(分類用) — 分岐の良さを測る指標】
$$ \text{Gini}(D) = 1 - \sum_{k=1}^{K} p_k^2 \qquad \text{Entropy}(D) = -\sum_{k=1}^{K} p_k \log_2 p_k $$
この数式は「決定木 がどう計算されるか」を最短で示したもの。 記号の意味は次の「🔬 数式を言葉で読み解く」で 1 つずつ解説します。
📚 数式が苦手な方へ:1 つの長い式を一度に理解しようとせず、 記号ごとに「言葉に翻訳」するのが王道。 紙に書き写してから、 自分の言葉で音読してみてください。

🔬 数式を言葉で読み解く — 決定木 の記号辞書

上の数式に出てくる各記号が何を表すかを、 言葉で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。

記号意味(言葉での説明)
$p_k$ノードでクラス $k$ が占める割合
Gini$0$ が完全純粋、 大きいほど混在
Entropy情報理論的な「乱雑さ」
MSE回帰木で使う指標(葉ノードの分散)
深さ木の階層数(過学習との戦い)
📌 読み下しのコツ:左から右に「主語 → 述語 → 目的語」と見立てて、 「これは何を、 どうしている式か?」と一文で要約してみてください。 慣れれば 5 秒で読めます。

🧮 SSDSE-B-2026 実値計算 — 「総人口 200 万人以上」分類木

2023 年度・47 都道府県を「総人口 (A1101) が 200 万人以上 or 未満」の 2 クラスに分け、 年平均気温・消費支出・合計特殊出生率を特徴量に最大深さ 3 の決定木で分岐ルールを抽出します。

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A4103(合計特殊出生率) B4101(年平均気温) L3221(消費支出(二人以上の世帯)) 北海道 5,092,000 1.06 11.0 296,888 東京都 14,086,000 0.99 17.6 341,320 沖縄県 1,468,000 1.6 23.8 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree
import matplotlib.pyplot as plt

# 1行目=コード, 2行目=日本語名 → コード行を使うため skiprows=[1]
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d23 = df[df['SSDSE-B-2026'] == 2023]              # 2023年度・47都道府県

# 目的変数: 総人口(A1101)が200万人以上か
y = (d23['A1101'] >= 2_000_000).astype(int)
# 説明変数: 年平均気温(B4101)・消費支出(L3221)・合計特殊出生率(A4103)
X = d23[['B4101', 'L3221', 'A4103']]

tree = DecisionTreeClassifier(max_depth=3, random_state=42).fit(X, y)
print(export_text(tree, feature_names=list(X.columns)))
print('accuracy =', round(tree.score(X, y), 3))
plot_tree(tree, feature_names=X.columns,
          class_names=['200万未満', '200万以上'], filled=True)
plt.show()
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 実行例(実測) |--- A4103 <= 1.29 | |--- B4101 <= 17.05 | | |--- A4103 <= 1.09 | | | |--- class: 1 | | |--- A4103 > 1.09 | | | |--- class: 0 | |--- B4101 > 17.05 | | |--- A4103 <= 1.27 | | | |--- class: 1 | | |--- A4103 > 1.27 | | | |--- class: 1 |--- A4103 > 1.29 | |--- B4101 <= 14.85 | | |--- class: 1 | |--- B4101 > 14.85 | | |--- L3221 <= 305002.00
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

得られる分岐ルール(例)

|--- A4103 <= 1.29
|   |--- B4101 <= 17.05
|   |   |--- A4103 <= 1.09
|   |   |   |--- class: 1
|   |   |--- A4103 >  1.09
|   |   |   |--- class: 0
|   |--- B4101 >  17.05
|   |   |--- A4103 <= 1.27
|   |   |   |--- class: 1
|   |   |--- A4103 >  1.27
|   |   |   |--- class: 1
|--- A4103 >  1.29
|   |--- B4101 <= 14.85
|   |   |--- class: 1
|   |--- B4101 >  14.85
|   |   |--- L3221 <= 305002.00
|   |   |   |--- class: 0
|   |   |--- L3221 >  305002.00
|   |   |   |--- class: 0

「合計特殊出生率 (A4103) ≦ 1.29」が第 1 分岐 — 出生率の低さが人口 200 万人以上の大都市圏を最もよく切り分ける、と木が自動発見しています。 訓練精度 0.915、 5-fold CV 0.691、 葉ノード 7 個。

🧮 数式に値を入れて手で計算する

SSDSE-B-2026 (2023 年度) の全 47 都道府県を「総人口 (A1101) が 200 万人以上 (クラス高) と未満 (クラス低)」に分け、 その件数 (高 16 件, 低 31 件、 合計 47 県) を Gini 不純度・Entropy の数式に代入し、 Step 1〜3 で手計算する。 これは前節の分類木のルートノードの不純度に一致する。 同じ計算を Python (numpy / sklearn) で再現し、 結果が一致することを確認する。

📐 Gini 不純度・Entropy (再掲)

$$ \mathrm{Gini}(D) = 1 - \sum_{k=1}^{K} p_k^2 \qquad \mathrm{Entropy}(D) = -\sum_{k=1}^{K} p_k \log_2 p_k $$

Step 1: データ準備 (SSDSE-B-2026・2023 年度 47 都道府県の総人口 二値クラス分布)

クラス k件数 $n_k$比率 $p_k = n_k / n$$p_k^2$$-p_k \log_2 p_k$
高 (総人口≥200万)1616/47 = 0.34040.1159-0.3404 × log₂(0.3404) = 0.5292
低 (総人口<200万)3131/47 = 0.65960.4350-0.6596 × log₂(0.6596) = 0.3960
合計471.00000.55090.9252

Step 2: Gini と Entropy の組み立て

項目計算結果
$\sum p_k^2$$0.1159 + 0.4350$0.5509
Gini = $1 - \sum p_k^2$$1 - 0.5509$0.4491
$-\sum p_k \log_2 p_k$$0.5292 + 0.3960$0.9252

Step 3: 最終結果と参考値

項目結果解釈
Gini0.4491最大値 0.5 (50:50) に近く、 やや混在
Entropy0.9252 bits最大値 1.0 bits に近い (二値時)
(参考) 50:50 のときGini=0.5, Entropy=1.0最も不純な状態
(参考) 純粋 (1 クラスのみ)Gini=0, Entropy=0完全に分かれた葉

🐍 同じ計算を Python で再現

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) 北海道 5,092,000 東京都 14,086,000 沖縄県 1,468,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import numpy as np
from sklearn.tree import DecisionTreeClassifier

# 2023年度・全47都道府県を「総人口(A1101) 200万人以上 or 未満」で2クラス化
# df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
# d23 = df[df['SSDSE-B-2026'] == 2023]
# counts = np.array([(d23['A1101'] >= 2_000_000).sum(),
#                    (d23['A1101'] <  2_000_000).sum()])   # => [16, 31]
counts = np.array([16, 31])          # 高(>=200万) 16, 低(<200万) 31
n = counts.sum()
p = counts / n                       # 比率 p_k

gini = 1.0 - np.sum(p ** 2)
entropy = -np.sum(p * np.log2(p))

print(f"件数      = {counts.tolist()} (合計 {n})")
print(f"比率 p_k  = {np.round(p, 4).tolist()}")
print(f"Gini      = {gini:.4f}")
print(f"Entropy   = {entropy:.4f} bits")

# 参考: sklearn の DecisionTreeClassifier も同じ不純度を内部で使う
y = np.array([0] * 16 + [1] * 31)
X = np.arange(n).reshape(-1, 1)
clf_g = DecisionTreeClassifier(criterion='gini', max_depth=1).fit(X, y)
clf_e = DecisionTreeClassifier(criterion='entropy', max_depth=1).fit(X, y)
print(f"sklearn root impurity (gini)    = {clf_g.tree_.impurity[0]:.4f}")
print(f"sklearn root impurity (entropy) = {clf_e.tree_.impurity[0]:.4f}")

📤 実行結果

件数 = [16, 31] (合計 47) 比率 p_k = [0.3404, 0.6596] Gini = 0.4491 Entropy = 0.9252 bits sklearn root impurity (gini) = 0.4491 sklearn root impurity (entropy) = 0.9252

💬 手計算 (Step 3 の Gini=0.4491, Entropy=0.9252) と Python (numpy 手計算式・sklearn の tree_.impurity) がすべて完全一致。 二値クラスの最大不純度 (Gini=0.5, Entropy=1.0 bits) に近いことから、 このノードはまだ「分岐すべき余地」が大きい状態だと読める。

🧮 実値で計算してみる — SSDSE-B-2026 で 決定木 を体感

数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2018-2023 年度)の実値を当てはめて、 決定木 の挙動を電卓的に追体験します。

👉 計算例:SSDSE-B-2026(2023 年度)で目的変数を消費支出(L3221)、 説明変数を「総人口(A1101)・65歳以上人口(A1303)・出生数(A4101)・年平均気温(B4101)」に。 深さ 3 の回帰木を構築すると訓練 R² ≒ 0.693 と高く見えるが、 5-fold CV の R² は負値まで落ちる(単木は高分散で過学習しやすい典型)。 精度が要るなら次章の Random Forest 化が定石。

SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。

🐍 Python 実装バリエーション

A. sklearn.tree.DecisionTreeClassifier(基本)

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
1
2
3
4
from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier(criterion='gini', max_depth=5, min_samples_leaf=3,
                              ccp_alpha=0.0, random_state=42).fit(X, y)
print(tree.feature_importances_)
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 実行例(実測) [1.]
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

B. sklearn.tree.DecisionTreeRegressor(回帰)

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
1
2
3
4
5
from sklearn.tree import DecisionTreeRegressor
# 消費支出(L3221)を 総人口・65歳以上人口・出生数・年平均気温 から回帰
Xr = d23[['A1101', 'A1303', 'A4101', 'B4101']]
reg = DecisionTreeRegressor(max_depth=3, random_state=42).fit(Xr, d23['L3221'])
print('train R^2 =', round(reg.score(Xr, d23['L3221']), 3))   # => 0.693
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 実行例(実測) train R^2 = 0.693
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

C. コスト複雑度剪定(ccp_alpha 探索)

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
1
2
3
4
path = tree.cost_complexity_pruning_path(X, y)
for a in path.ccp_alphas[::3]:
    t = DecisionTreeClassifier(ccp_alpha=a, random_state=42).fit(X, y)
    print(f'alpha={a:.4f}, depth={t.get_depth()}, leaves={t.get_n_leaves()}')
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 実行例(実測) alpha=0.0000, depth=1, leaves=2
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

D. dtreeviz(リッチな可視化)

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
1
2
3
4
5
from dtreeviz import model
viz = model(tree, X_train=X, y_train=y,
            target_name='総人口200万以上', feature_names=list(X.columns),
            class_names=['200万未満', '200万以上'])
viz.view()
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 このブロックは標準出力には何も出さない
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

E. XGBoost で 1 本だけ作る(GBM の単木)

🎯 解説: 決定木(Decision Tree)は if-then ルールで分岐する解釈性の高い分類・回帰モデル。 ジニ不純度/エントロピーで最適分岐を選ぶ。 SSDSE-B-2026 の都道府県データで「どの変数が重要か」を可視化できる。
1
2
3
4
import xgboost as xgb
model = xgb.XGBClassifier(n_estimators=1, max_depth=3, learning_rate=1.0, random_state=0)
model.fit(X, y)
xgb.plot_tree(model, num_trees=0)
📥 入力例: data/raw/SSDSE-B-2026.csv X: 複数変数 y: ターゲット
📤 このブロックは標準出力には何も出さない
💬 読み方: 読み方: max_depth が小さいと欠学習、 大きいと過学習。 min_samples_split で分岐の最小サンプル数を制御。 木を可視化(plot_tree)すると「どの変数で分岐したか」が一目瞭然。

🐍 Python 実装 — 決定木 を SSDSE-B-2026 で動かす

まず環境をそろえます。 必要なライブラリを入れ、 matplotlib の日本語フォント(Hiragino Sans)を設定し、 SSDSE を encoding='cp932' で読み込んで shapehead()describe() を確認します。 この後、 決定木で 47 都道府県を分類・回帰していきます。 決定木は標準化が要らない数少ない手法なので StandardScaler は実際には使いませんが、 他手法と比較する節で必要になります。 エンコーディングを指定し忘れると UnicodeDecodeError で止まるのが最初の関門なので、 ここだけは丸暗記して構いません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 決定木 を SSDSE-B-2026 で確かめる最小コード
import pandas as pd
import numpy as np

# 1) SSDSE-B-2026 を読み込み(1行目=コード, 2行目=日本語名 → skiprows=[1])
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
print('shape:', df.shape)        # (564, 112) — 47 都道府県 × 12 年度
print('cols head:', list(df.columns[:8]))

# 2) 直近年度(2023 年度)に絞る(年度列の名前は 'SSDSE-B-2026')
df23 = df[df['SSDSE-B-2026'] == 2023].copy()
print('rows in 2023:', len(df23))

# 3) 決定木 を動かすために必要な列だけ取り出す(A4103:合計特殊出生率, A1101:総人口)
y = df23['A4103'].astype(float)
x = df23['A1101'].astype(float)
print('y stats:', y.describe().round(3).to_dict())
print('x stats:', x.describe().round(0).to_dict())

# 4) 決定木 の本処理(このページの主題)
#    — 具体実装は同カテゴリの個別ページにも掲載
print('---- 決定木 結果 ----')
print('mean y:', y.mean().round(3), '/ std y:', round(y.std(), 3))
print('mean x:', x.mean().round(0), '/ std x:', round(x.std(), 0))
print('corr(x, y):', y.corr(x).round(3))
📤 実行例(実測) shape: (564, 112) cols head: ['SSDSE-B-2026', 'Code', 'Prefecture', 'A1101', 'A110101', 'A110102', 'A1102', 'A110201'] rows in 2023: 47 y stats: {'count': 47.0, 'mean': 1.293, 'std': 0.133, 'min': 0.99, '25%': 1.21, '50%': 1.3, '75%': 1.385, 'max': 1.6} x stats: {'count': 47.0, 'mean': 2645809.0, 'std': 2797551.0, 'min': 537000.0, '25%': 1034000.0, '50%': 1549000.0, '75%': 2636500.0, 'max': 14086000.0} ---- 決定木 結果 ---- mean y: 1.293 / std y: 0.133 mean x: 2645809.0 / std x: 2797551.0 corr(x, y): -0.564

うまく動かないときは ①data/raw/SSDSE-B-2026.csv のパス、 ②encoding='cp932'(SSDSE-B は Shift_JIS 系)、 ③1 行目に英字コード・2 行目に日本語列名が並ぶ構造で、 skiprows=[1](2 行目だけ捨てて 1 行目のコードを列名にする)が必要、 の 3 点を確認してください。

⚠️ 決定木の落とし穴 7 連発

1. 制限なし(max_depth=None)で訓練して過学習。デフォルトの sklearn は葉が純粋になるまで分割し続けるため、 訓練精度 100%・テスト精度 60% のような典型的過学習が起きます。 max_depthmin_samples_leafccp_alpha のいずれかで剪定しないと使い物になりません。

2. 1 本の木の解釈を「真のルール」だと信じる。訓練データが少し変わると、 ルート分岐の特徴量自体が入れ替わるほど不安定です。 Random Forest 化したうえで Permutation Importance を取り、 安定して上位にくる変数を解釈の主役に据えましょう。

3. カテゴリ変数を「ラベルエンコード」して入れる。名義尺度(県名・血液型)に整数 0..n を割り当てると、 決定木は「県コード < 24」のような疑似的順序関係を学習してしまいます。 One-hot か、 ターゲットエンコーディングのほうが適切です(CatBoost なら自動)。

4. 外挿(範囲外予測)を行う。決定木は区分定数関数なので、 訓練データの最大値より大きい x を入れても、 「一番右の葉」と同じ値を返すだけ。 時系列の右端予測や、 集計値の極端領域では線形モデルとアンサンブルする方が安全です。

5. ノイズ変数を全部投入する。決定木は最も分散減少を稼げる特徴を貪欲に選ぶため、 ID 列・ハッシュ・ノイズ的ダミーがあると、 偶然それで分割して訓練データに過適合します。 事前に相関スクリーニングや MI(mutual_info)で篩にかけましょう。

6. クラス不均衡で多数派ばかり予測する。陽性 5% のデータでは、 デフォルト設定だと木が「全件陰性」の浅い構造に潰れます。 class_weight='balanced'、 SMOTE、 閾値調整のいずれかで対応してください。

7. random_state 未固定で結果がぶれる。同点ブレークの分岐で乱数が使われるため、 再実行で異なる木になります。 比較・論文用の数値は必ず random_state=42 等を固定し、 加えて乱数を変えた 5 回の平均を併記しましょう。

⚠️ よくある落とし穴 — 決定木 で初学者がやりがちなミス

この用語を実務で使うときにつまずきやすい点を、 失敗パターン別に整理しました。 1 度経験すれば回避できるものばかりですが、 先に知っておくと事故が大幅に減ります。

❌ 深さ制限なし
無制限だと訓練データに完全フィットして過学習。 max_depth=3〜5 が安全。
❌ 不安定性
入力をわずかに変えるだけで木の構造が大きく変わる。 Random Forest で安定化。
❌ 軸並行分割
斜めの境界は表現できない。 SVM や NN で補完。
❌ 線形関係が苦手
滑らかな単調関係は階段近似になる。 線形モデルと併用。
🛡 防御策まとめ:「適用条件の確認 → 適切な前処理 → 結果と前提のペア記述」の 3 ステップを習慣にすれば、 ここに挙げた失敗の大半は回避できます。

🗺️ 統計手法選択フローチャート

Q1: 何を知りたい?

Q2: データの種類は?

Q3: サンプルサイズは?

Q4: 仮定は?

📏 効果量の参照表

p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:

統計量 効果量
2群平均差Cohen's d0.20.50.8
相関r0.10.30.5
線形回帰0.020.130.26
ANOVAη² (eta²)0.010.060.14
χ²Cramér's V0.10.30.5
ロジスティックOdds Ratio1.52.54.0

🚀 実務応用の深掘り

典型的なプロジェクトの流れ

  1. 問題理解:ステークホルダーとの対話、 KGI/KPI 設定
  2. データ収集:内部DB、 公的データ(SSDSE等)、 API
  3. EDA:データの全体像把握、 異常検出
  4. 仮説立案:ドメイン知識からの仮説
  5. モデリング:シンプルから複雑へ段階的に
  6. 検証:CV、 ホールドアウト、 A/Bテスト
  7. 解釈:可視化、 SHAP、 部分依存プロット
  8. 展開:本番デプロイ、 監視

ベストプラクティス

論文・コンペでよく使う言い回し

日本語 英語
統計的に有意statistically significant
効果量effect size
95%信頼区間95% confidence interval (CI)
標本サイズsample size
検出力statistical power
第1種の誤りType I error / false positive
第2種の誤りType II error / false negative
多重比較問題multiple comparisons problem
過学習overfitting
汎化性能generalization
交差検証cross-validation (CV)

統計データ活用コンペでのコツ

🗺️ 概念マップ — 3つの視点で体系を理解する

決定木 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

📍 体系階層のパス

🌐 統計・データサイエンス › 機械学習 › 教師あり学習 › 決定木

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心に 決定木 を置き、 そこから 分類・ランダムフォレスト・XGBoost 計 3 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語あとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「決定木」は緑色でハイライト

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「決定木」は緑色でハイライト

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは 決定木隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス教師あり学習 → 決定木 という入れ子の位置を示します。 「教師あり学習には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。

🔗 隣接手法への橋渡し

「決定木」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。 具体的には次の 3 方向と密接につながる:

決定木は単純で解釈性が高く、 アンサンブル手法の基底学習器として発展する。

🌳 手法選択フロー

「decision tree」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。

典型シナリオ別の手法選択

シナリオ重視する観点候補手法
データが大規模 (n が多い、 高次元)計算コスト / メモリ / 並列化が必要Random Forest
外れ値が多い / ノイズあり頑健性 / 外れ値除去 / 中央値ベースXGBoost
解釈性を重視する線形 / 木構造 / ルールベースCART
予測精度を最優先するアンサンブル / ハイパラ調整 / 交差検証C4.5
データが少ない正則化 / ベイズ / 転移学習 / 簡素なモデルID3
リアルタイム/オンライン処理ストリーミング / 軽量モデル / 逐次更新CHAID

選んだ後の検証ステップ

  1. 前処理確認: 標準化 / 欠損処理 / カテゴリ変数のエンコード が適切か
  2. ハイパラ調整: 交差検証で安定する値を選ぶ
  3. 性能評価: タスクに応じた指標 (RMSE / Accuracy / F1 / AUC / シルエット等) を複数併用
  4. 頑健性チェック: 別手法 / 別シードで結果が大きく違わないか確認
  5. 解釈: 結果を分野知識と照らし合わせ、 意味のある発見になっているか検討

🎨 直感をもう一段深める — 「20の質問」ゲームとしての決定木

決定木は「はい/いいえで答える20の質問ゲーム」そのものです。 相手が思い浮かべた都道府県を当てるとき、 私たちは「人口は多い?」「海に面している?」と最も候補を半分に絞れる質問から順に投げます。 決定木の学習アルゴリズムがやっているのは、 この「一番よく候補を絞れる質問(=不純度を最も下げる分割)」を各段で貪欲に選ぶことに他なりません。 良い質問ほど答えを聞いた後の迷い(不純度)が小さくなる、 という感覚がそのまま ジニ不純度情報利得 の最小化に対応します。

🔑 3つのキーイメージ

上の 🎮 プレイグラウンド で点を配置し深さを動かすと、 この「切る→区画に札を貼る」過程が目に見えます。 if-then ルールの列として書き下せる(=人間が読める)のが、 他の非線形モデル(SVM・ニューラルネット)に対する決定木の決定的な強みです。 一方で「切り口が必ず軸平行」という制約が、 次に述べる落とし穴の根っこにもなっています。

⚠️ 落とし穴を実データで見る — SSDSE-B-2026 で過学習を再現

「深い木は過学習する」は言葉で言うと当たり前ですが、 実データで数値として見ると腑に落ちます。 ここでは SSDSE-B-2026(2023年度・47都道府県)の実測値だけを使い、 深さを変えたときの訓練性能と汎化性能(Leave-One-Out 交差検証, n=47 なので LOO が自然)のギャップを示します。 数値はすべて下のコードで再現できます。

① 分類木:総人口が 200 万人以上か(葉=多数決クラス)

目的変数=総人口 (A1101) ≧ 200 万人(該当 16/47 県)。 特徴量=年平均気温 (B4101)・消費支出 (L3221)・合計特殊出生率 (A4103)。

max_depth 訓練 Accuracy LOO-CV Accuracy 葉の数 解釈
10.7660.7452やや欠学習
20.8720.7664LOO 最良(汎化のピーク)
30.9150.7237訓練↑・CV↓(乖離開始)
50.9790.59611過学習
None(無制限)1.0000.63812訓練を完全暗記=典型的過学習

訓練 Accuracy は深さとともに単調に 1.000 まで上がるのに、 LOO-CV は depth=2 の 0.766 が頂点で以後は下降。 まさに 図 3 の「訓練誤差↓・汎化誤差∪」を実データが再現しています。 深さ 3 の木の根分岐は「合計特殊出生率 A4103 ≦ 1.29」で、 特徴重要度は A4103=0.608・B4101=0.371・L3221=0.021。 このデータでは気温と出生率が効き、 消費支出はほぼ使われません。

② 回帰木:合計特殊出生率 A4103 を予測(葉=平均値)

目的変数=合計特殊出生率 A4103(実測レンジ 0.99〜1.60、 平均 1.293)。 特徴量=気温 (B4101)・消費支出 (L3221)・総人口 (A1101)。 指標は決定係数 $R^2$。

max_depth 訓練 $R^2$ LOO-CV $R^2$ 葉の数
10.3520.2082
20.6120.3624
30.7570.3417
50.9140.16017
None(無制限)1.0000.06043

→ 回帰でも同じ形。 訓練 $R^2$ は 1.000(47点を43葉でほぼ 1 点 1 葉に暗記)まで上がる一方、 LOO-CV $R^2$ は depth=2 の 0.362 が頂点で、 無制限では 0.060 まで崩落します。 「葉が増える=暗記が進む」が数字で見えます。 なお回帰木は区分定数関数なので、 訓練データの外側(外挿)では常に端の葉の定数を返す点にも注意(落とし穴 4)。

③ ジニ vs エントロピー:基準を変えると木も少し変わる

同じ分類問題(深さ 3)で分割基準を切り替えた実測比較です。

基準 根の分岐 訓練 Accuracy 葉の数
ジニ不純度(sklearn 既定)A4103 ≦ 1.290.9157
エントロピー(情報利得)A4103 ≦ 1.350.7874

どちらも根で選ぶ特徴は同じ(A4103)で、 一般に両者の差は小さいと言われます。 ただし小標本(n=47)では閾値・葉数・同点処理の違いから木の形が変わることもあり、 「基準の選択そのものより深さ・剪定の方が影響が大きい」という経験則を裏づけます。

④ 特徴量重要度の落とし穴:高カーディナリティ有利バイアス

不純度ベースの特徴量重要度(sklearn の feature_importances_)は、 取りうる値が多い変数(連続値・高カーディナリティ)ほど分割の機会が多く、 実際には無関係でも重要度を稼いでしまうという既知のバイアスがあります。 実データ 3 変数に、 予測に一切関係しない 架空のほぼ一意な一様乱数列を 1 本足して無制限深さで学習すると:

A4103 = 0.535 / B4101 = 0.301 / L3221 = 0.121 / 架空ノイズ = 0.043(真の寄与はゼロのはず)

→ 無意味なノイズ列が 重要度 0.043 を誤って獲得しました。 対策は、 (1) Permutation ImportanceSHAP 値など木構造に依存しない重要度を併用、 (2) 高カーディナリティのカテゴリは安易なラベルエンコードを避ける(落とし穴 3)、 (3) ID 列やハッシュを特徴に混ぜない(落とし穴 5)。

🔁 再現コード(この節の数値はすべてここから)

# SSDSE-B-2026 実測: 深さ vs 過学習(分類・回帰) import pandas as pd, numpy as np from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor from sklearn.model_selection import cross_val_score, cross_val_predict, LeaveOneOut from sklearn.metrics import r2_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) d = df[df['SSDSE-B-2026'] == 2023] feats = ['B4101', 'L3221', 'A4103'] # 気温・消費支出・出生率 X = d[feats].values y = (d['A1101'] >= 2_000_000).astype(int).values # 総人口200万以上か for dep in [1, 2, 3, 5, None]: clf = DecisionTreeClassifier(max_depth=dep, random_state=42).fit(X, y) train = clf.score(X, y) loo = cross_val_score(clf, X, y, cv=LeaveOneOut()).mean() print(f'depth={dep}: train={train:.3f} LOO={loo:.3f} leaves={clf.get_n_leaves()}')

🚀 発展 — 枝刈り・アンサンブル・重要度の計算

① コスト複雑度剪定(Cost-Complexity Pruning, CCP)

事後剪定の代表格。 木 $T$ の「当てはまりの悪さ $R(T)$」に「木の大きさ $|T|$(葉の数)」への罰則を足した目的関数

$$ R_\alpha(T) = R(T) + \alpha\,|T| $$

を最小化します。 $\alpha=0$ なら剪定なし(フルサイズ)、 $\alpha$ を上げるほど葉が減り単純化します。 sklearn では cost_complexity_pruning_path() で有効な $\alpha$ 候補列を取得し、 交差検証で最良の ccp_alpha を選ぶのが定石です(上の 🐍 Python 実装節にコード例あり)。 事前剪定(max_depth / min_samples_leaf)が「育てる前に止める」のに対し、 CCP は「深く育ててから刈る」ため、 重要な深い分割を保ちつつ無駄枝だけ落とせる利点があります。 いずれも本質は 正則化 です。

② アンサンブル化:高分散を「束ねて」抑える

上の実測で見たとおり単体木は不安定(高分散)です。 これを克服する 2 系統が実務の主役です。

系統 代表 仕組み 主に下げる誤差
バギング(並列)ランダムフォレストブートストラップ標本+特徴量ランダム選択で多数の木を育て平均/多数決分散
ブースティング(直列)XGBoost / LightGBM前の木の残差を次の木が順に補正(勾配降下的に損失を減らす)バイアス(+分散)

両者の位置づけは バイアス・バリアンス分解 の観点で整理でき、 木のアンサンブル全体像は 木のアンサンブル ページにまとまっています。 「単体木は解釈用、 アンサンブルは精度用」が使い分けの一言まとめです。

③ アルゴリズム系譜:CART / ID3 / C4.5

④ 回帰木と特徴量重要度の計算

回帰木は葉に「そのノードの目的変数の平均値」を割り当て、 分割基準を不純度から分散(MSE)減少に置き換えたものです(上の実測②がまさに回帰木)。 不純度ベースの特徴量重要度は、 その特徴で分割したノードでの不純度減少量をサンプル数で重み付けして合計・正規化したもの。 計算は軽い反面、 落とし穴④の高カーディナリティ・バイアスを持ちます。 より頑健な代替が Permutation Importance(特徴をシャッフルして性能低下を測る)と SHAP 値(各予測への寄与を公平に分配)です。