「random forest」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「random forest」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「random forest の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
たくさんの決定木(判断の木)が集まった森のような手法です。
データの予測をより正確にするために使います。
スマホのアプリで好みの商品を当てるような仕組みです。
この章では、この手法の結論を短くまとめます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # 基本パターン import pandas as pd import numpy as np from scipy import stats 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]) # 基本統計量 df.describe() # 可視化 sns.pairplot(df[['L322101', 'L322108', 'L322102']]) # 食料/教育/住居 plt.show() |
ランダムフォレストは決定木を多数 (典型 100〜500 本) 並べたバギング系のアンサンブル学習。 上位概念はアンサンブル、 並列概念は単一決定木 / Extra Trees / Bagging (ブートストラップ集約)、 派生概念は勾配ブースティング (XGBoost, LightGBM, CatBoost)、 競合は SVM / ロジスティック回帰。 「列のサブセット (max_features) と行のサブセット (bootstrap) で木を脱相関し、 多数決 / 平均で集約」が中核アイデア。
47 都道府県の社会経済データで、 RF の標準ワークフロー (前処理 → 学習 → 重要度 → OOB) を一通り体験する。
| 機能 | Python (scikit-learn) | 補足 |
|---|---|---|
| 分類器 | RandomForestClassifier() | criterion='gini' or 'entropy' |
| 回帰器 | RandomForestRegressor() | criterion='squared_error' |
| OOB スコア | RF(oob_score=True).oob_score_ | bootstrap=True が必須 |
| Gini 重要度 | model.feature_importances_ | 高カーディナリティを過大評価 |
| Permutation 重要度 | sklearn.inspection.permutation_importance() | Gini の偏りを回避 |
| SHAP 重要度 | shap.TreeExplainer(model).shap_values(X) | 個別予測の説明にも使える |
| 木の可視化 | sklearn.tree.plot_tree(model.estimators_[0]) | 深い木は読めないので max_depth=3 推奨 |
RF は「決定木」「アンサンブル」「特徴量重要度」「ハイパーパラメータ調整」「モデル説明可能性 (XAI)」が交差する位置にある。 単独で理解しようとせず、 周辺の概念を辿りながら学ぶ。
| グループ | RF と関連の深い概念 |
|---|---|
| 基礎 (1 本の木) | 決定木 (CART)、 Gini 不純度、 エントロピー、 情報利得 |
| アンサンブル戦略 | Bagging、 Boosting、 Stacking、 Voting |
| サンプリング | ブートストラップ、 Out-of-Bag、 Subsampling |
| 列のランダム化 | max_features (√p, log2(p))、 Extra Trees の閾値ランダム化 |
| 並列・後継モデル | Gradient Boosting、 XGBoost、 LightGBM、 CatBoost |
| 汎化性能評価 | OOB スコア、 k-fold CV、 hold-out |
| 重要度の指標 | Gini 重要度、 Permutation 重要度、 SHAP 値、 LIME |
| バイアス・バリアンス | バリアンス削減、 木間相関、 偏りと分散のトレードオフ |
| 不均衡データ | class_weight、 SMOTE、 BalancedRandomForest |
| RF 派生 | Isolation Forest (異常検知)、 quantile random forest (分位点予測) |
🍰 まずはやさしく
多くの決定木を組み合わせて使う分析の手法です。
複雑なデータから正しい答えを導き出すために使います。
都道府県のデータを使って分析する時に役立ちます。
ここでは、この用語がどこで使われるかを説明します。
論文中に 「ランダムフォレスト」として登場する用語。
ランダムフォレスト とは:多数の決定木をブートストラップサンプリングで学習させ、結果を平均/多数決するアンサンブル手法。
本ページでは「random forest」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「random forest」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
みんなで相談して答えを決める多数決のようなものです。
一人の判断ミスを防いで、結果を安定させるために使います。
部活の試合で、チーム全員で作戦を考えるイメージです。
ここでは、仕組みを直感的に理解するための例を読みます。
ランダムフォレストは「たくさんの決定木を、 サンプルと特徴量をランダムに変えて作り、 平均する」アンサンブル手法。 個々の木は弱学習器でも、 集めると強い。 SSDSE-B-2026 で「都道府県の出生率」を 100 本の木で予測すると、 単一の決定木より分散が下がって安定する。
ランダムフォレストは「多数の決定木の多数決」。 ブートストラップ標本+特徴量サブセットで多様な木を作り、 平均(回帰)または多数決(分類)で予測する。
→ 各木は弱学習器でも、 多数決により汎化性能が上がる。
→ 木同士の相関を下げることで、 集約の効果が最大化される。
→ 木を増やすほどバリアンスが下がり、 合計誤差は飽和点まで減少する。
ランダムフォレスト (RF) について、 自分で説明できるか 5 問で確認しよう。 詰まった項目は該当章へ戻ること。 暗記でなく「なぜそうなるか」を 1-2 文で書けるかが目標。
Q1. ブートストラップ標本とは何か、 なぜ使うのか
ランダムフォレストの各決定木は「ブートストラップ標本」で訓練される。 これは何で、 なぜ全データを使わないのか。
答えの方向: ブートストラップ = 元データから「重複ありで」N 個をランダムサンプリング。 各木が見るデータが微妙に違うため、 木同士の相関が下がる。 多数決の効果は「木同士が無相関ほど大きい」ため、 ブートストラップは集約効果を最大化する仕組み。
Q2. なぜ各分岐で特徴量のサブセットだけを使うのか
分類なら √p、 回帰なら p/3 個の特徴量を各分岐でランダムに選ぶ。 強力な特徴量を毎回使った方がよさそうだが、 なぜわざわざ選択するのか。
答えの方向: もし全特徴量を使うと、 各木がほぼ同じ「最良の分岐」を選ぶため木同士が似通う (= 相関が高い)。 これでは集約してもバリアンスが下がらない。 ランダムに特徴を制限することで木のバリエーションを増やし、 アンサンブルの効果を高める。
Q3. 木の本数 n_estimators を増やすデメリットは
木の本数を増やしてもバイアスは増えず、 バリアンスは減るので「多ければ多いほどよい」と言われる。 ではデメリットは何か。
答えの方向: 計算コスト・メモリ使用量が線形に増える。 また、 ある本数を超えると性能向上は飽和し、 学習時間だけが伸びる。 実務では 100-500 本程度から CV で頭打ちを確認し、 そこを採用する。
Q4. OOB スコアとは何か
RF には「OOB (Out-of-Bag) スコア」という独自の指標がある。 これはなぜ "ほぼ無料の交差検証" と呼ばれるのか。
答えの方向: ブートストラップでサンプリングされる時、 各木の訓練には平均で全体の約 63% のデータしか使われず、 残り 37% は「Bag の外 (OOB)」になる。 これを当該木のテストデータとして使えるので、 別途 CV を回さなくても汎化性能を推定できる。
Q5. 特徴量重要度を因果として読んではいけない理由
RF の feature_importances_ は便利だが、 これを「この特徴量が結果を引き起こしている」と解釈してはいけない。 なぜか。
答えの方向: 重要度は「予測にどれだけ寄与するか」を示すだけで、 因果関係ではない。 例: アイスクリーム売上が水着売上を予測しても、 因果的には「気温」が両方を引き起こしている (交絡)。 因果効果を測りたいなら DiD、 IV、 RCT などの因果推論手法が必要。
→ 5 問とも自分の言葉で 2 文で説明できれば RF の理解は OK。 詰まった部分は「ブートストラップ」「特徴量ランダム選択」「OOB」セクションを再読しよう。
RF は「とりあえずベースライン」として最も使われるが、 万能ではない。 前提・限界・誤解を整理する。
集約効果の理論は「木同士のエラーが独立」を仮定する。 完全に同じ特徴量しか効かないデータ (= 真の構造が 1 つしかない) では、 ブートストラップ + 特徴量サブセットを使っても木同士が似てしまい、 集約効果が薄い。
各木がブートストラップ標本で学習するので、 元データが極端に少ない (n < 50) と、 各木の学習データの質が悪化する。 小規模データでは線形モデル + 正則化や交差検証で慎重に評価する方が安全。
RF (および決定木) は訓練データの「葉ノード代表値」で予測する。 訓練データの範囲外 (例: 訓練時に最高温度 35 度しか見ていないのに 40 度を予測しようとする) では、 葉ノードの値で頭打ちになる。 時系列の外挿、 トレンド予測などは線形回帰や GAM の方が向く。
RF は「並列」のアンサンブル。 一方 XGBoost/LightGBM は「逐次」で前回の誤差を学習する。 構造化データのコンペでは XGBoost/LightGBM が RF を上回ることが多い。 ただし RF は OOB スコアとハイパーパラメータの少なさで実装が楽。
「デフォルトで動く」は確かだが、 max_depth、 min_samples_leaf、 max_features は性能に大きく影響する。 特に max_depth を制限しないとメモリと過学習の問題が出る。 必ず CV でチューニングする。
Q5 で見たとおり、 重要度は「予測寄与」であって因果ではない (相関と因果)。 また、 RF の Gini importance (ジニ不純度の減少量ベース) はカーディナリティの高い特徴量 (連続値) を過大評価する傾向があり、 さらに相関の強い特徴量同士では重要度が分散して両方とも低く見える点にも注意。 Permutation importance や SHAP を併用して頑健に評価する。
直感に反して、 木の本数を増やしても過学習は基本的に起きない (バリアンスが減るだけ)。 過学習を起こす主因は max_depth の深さや個別木のサイズ。 「木が多いと過学習」と勘違いして本数を絞ると、 単にバリアンスが下がりきらない弱いモデルになる。
→ RF は「弱学習器の独立性 + 多数決」が成立するように設計するモデル。 集約効果が出ないなら、 特徴量設計や手法選択を見直すサイン。 XGBoost/LightGBM との比較は必ず行う。
2 次元・2 クラスの分類データに対して、 1 本の決定木(左)と ランダムフォレスト(右)の決定境界をその場で学習・描画します。 木の学習はジニ不純度による情報利得で分割点を選ぶ簡易 CART を実装しています(近似ではなく実際に木を育てています)。 スライダーで 木の本数 n を増やすと、 1 本の木のギザギザした階段状の境界が、 多数の木の平均によって滑らかな確率グラデーションへと均されていく様子(=バギングによる分散低減)を体感できます。
学習データ 120 点 / 別に用意したテストデータで精度を測定。 各木はブートストラップ標本 + 分割ごとに 1 特徴をランダム選択(max_features='sqrt')。 左の単一木は全データ・全特徴で学習した比較用です。
背景色 = 予測クラス(青=クラス0 / 赤=クラス1)。 右図は色の濃淡が「何本の木がそのクラスに投票したか(確率)」を表し、境界付近ほど中間色になります。 ● は学習データ点です。
1 本の木は訓練データのわずかな違いで境界が大きく変わる高バリアンスな弱学習器です。 だが各木の誤差がある程度独立していれば、 多数の木で多数決/平均を取ると誤差が打ち消し合い、 予測の分散が 1/n 近くまで低下します(バイアスはほぼ不変)。 スライダーの n を 1 → 60 と動かすと、 右図の確率グラデーションが滑らかに収束していくのが分散低減そのものです。 詳しくは バイアス-バリアンス分解 と ブートストラップ(バギング) を参照。
🍰 まずはやさしく
たくさんの決定木の答えを平均したり、多数決したりする仕組みです。
計算で正しく予測値を出すために使います。
テストの点数を予想して、平均を出す計算に似ています。
ここでは、数式を使った厳密な定義について読みます。
直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。
上の数式 $\hat{y}_{\text{RF}}(x) = \frac{1}{B}\sum_{b=1}^{B} T_b(x; \Theta_b)$ に出てくる各記号が何を表すかを、 言葉・読み方・SSDSE-B-2026 (47 都道府県データ) での具体例の 3 段で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。
| 記号 | 読み方 | 意味 | SSDSE-B-2026 での例 |
|---|---|---|---|
| $\hat{y}_{\text{RF}}(x)$ | わいハット アールエフ オブ エックス | ランダムフォレスト全体の予測値。 $B$ 本の木の予測の平均 (回帰) または多数決 (分類)。 | 総人口・出生数・婚姻件数を入力 → 死亡数(A4200)の予測値 |
| $B$ | ビー (number of trees) | フォレスト内の木の本数。 大きいほど分散が減って安定する。 通常 100〜1000。 | $B=300$ で 47 都道府県を予測 |
| $b$ | ビー (添字) | 何本目の木かを表すインデックス。 $b = 1, 2, \ldots, B$。 | $b=42$ なら 42 本目の木 |
| $T_b(x; \Theta_b)$ | ティービー オブ エックス | $b$ 番目の決定木 (CART)。 入力 $x$ に対して 1 つの予測値を返す。 ランダム性 $\Theta_b$ で異なる木になる。 | 「総人口 > 500 万人なら死亡数 多」のような枝分かれ判定 |
| $\Theta_b$ | シータビー | $b$ 番目の木のランダム化要素。 (1) bootstrap サンプル (元データを復元抽出) と (2) 各分割で候補となる特徴量サブセット の 2 つから成る。 | 47 件から 47 件を復元抽出 + 14 特徴量から $\lfloor\sqrt{14}\rfloor = 3$ 個ランダム選択 |
| $x$ | エックス | 予測したい入力特徴量ベクトル。 | (人口, 所得, 高齢化率, …) の 14 次元ベクトル |
| $m_{\text{try}}$ | エムトライ | 各分割で候補にする特徴量の数。 回帰は $p/3$、 分類は $\sqrt{p}$ が経験則。 | $p=14$ → 分類は $\lfloor\sqrt{14}\rfloor = 3$、 回帰は $\lfloor 14/3 \rfloor = 4$ |
| OOB | オーオービー (Out-Of-Bag) | bootstrap で「選ばれなかった」約 37% のサンプル。 各木に対する自然な検証セット。 cross-validation 不要。 | 47 件中 約 17 件が OOB として未使用 → 精度評価に使う |
| $\frac{1}{B}\sum$ | B 分の 1 でシグマ | $B$ 本の木の予測を平均する集約操作。 これにより分散が約 $1/B$ + 木間相関分に縮む (bias-variance 分解)。 | 300 本の予測値の平均が最終予測 |
「合計特殊出生率(A4103)」を予測するランダムフォレスト回帰を、 SSDSE-B-2026 の 2023 年度データで構築します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import pandas as pd from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split, cross_val_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df.rename(columns={'SSDSE-B-2026': '年度'}) d = df[df['年度'] == 2023].dropna() features = ['A1303', 'A9101', 'B4101', 'A5101', # 高齢人口/婚姻/気温/転入 'L3221', 'A1101'] # 消費支出/総人口 X, y = d[features], d['A4103'] # 合計特殊出生率 X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42) rf = RandomForestRegressor(n_estimators=500, max_depth=10, min_samples_leaf=2, oob_score=True, random_state=42, n_jobs=-1) rf.fit(X_tr, y_tr) print(f'Train R² = {rf.score(X_tr, y_tr):.3f}') print(f'Test R² = {rf.score(X_te, y_te):.3f}') print(f'OOB R² = {rf.oob_score_:.3f}') |
実測結果:Train R² = 0.887, Test R² = 0.273, OOB R² = 0.517。 Train と Test の大きな差は過学習の兆候で、 合計特殊出生率のように変動幅の小さい比率は 47 県の小標本では予測が難しい。 OOB R²(0.517)はテスト R² より高く、 少標本ゆえ評価指標がばらつくことを示す。 単一の指標に頼らず OOB・テスト・CV を併記するのが安全。
1 2 3 4 | import pandas as pd imp = pd.Series(rf.feature_importances_, index=features).sort_values(ascending=False) print(imp) # L3221消費支出: 0.35, B4101気温: 0.27, A1303高齢人口: 0.17, A1101総人口: 0.09, A5101転入: 0.07, A9101婚姻: 0.05 |
「L3221 消費支出」が最重要(35%)、 次が「B4101 年平均気温」(27%)、 「A1303 高齢人口」(17%)と続く。 相関する人口系の変数間では重要度が分散するため、 次の Permutation Importance で頑健に確認する。
1 2 3 4 5 6 | from sklearn.inspection import permutation_importance r = permutation_importance(rf, X_te, y_te, n_repeats=30, random_state=42) for i in r.importances_mean.argsort()[::-1]: print(f'{features[i]:20s}: {r.importances_mean[i]:.3f} ± {r.importances_std[i]:.3f}') # テストセットで「変数をシャッフルしたら精度がどれだけ落ちるか」で測る # 標準の feature_importances_ よりバイアスが少ない(特にカテゴリ・スケール違いに頑健) |
数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2012-2023 年度)の実値を当てはめて、 ランダムフォレスト の挙動を電卓的に追体験します。
SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。
合成データで木数 B 別の予測分散減少を計算する。
1 2 3 4 5 | import numpy as np sigma2, rho = 4, 0.3 B = np.array([1, 10, 100, 1000]) var = rho*sigma2 + (1-rho)*sigma2/B print(f"B 別分散: {var.round(3)}") |
💬 手計算 (Step 2) と Python 出力が完全一致。
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 28 29 30 31 32 33 | import pandas as pd import numpy as np from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score, mean_squared_error # SSDSE-B-2026 を読み込み、 死亡数 A4200 を 5 変数で予測 df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]).rename(columns={'SSDSE-B-2026': '年度'}) df = df[df['年度'] == 2023] features = ['A1101', 'A1301', 'A1303', 'A4101', 'A9101'] # 総人口/年少/高齢/出生数/婚姻件数 X = df[features].astype(float) y = df['A4200'].astype(float) # 訓練/テスト分割 X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42) # RandomForestRegressor: 500 本の木でアンサンブル rf = RandomForestRegressor(n_estimators=500, max_depth=None, min_samples_leaf=1, max_features='sqrt', oob_score=True, n_jobs=-1, random_state=42) rf.fit(X_tr, y_tr) # 評価 y_pred = rf.predict(X_te) r2_test = r2_score(y_te, y_pred) rmse = np.sqrt(mean_squared_error(y_te, y_pred)) print(f'OOB スコア = {rf.oob_score_:.4f}') print(f'テスト R² = {r2_test:.4f}') print(f'テスト RMSE = {rmse:,.0f} 人') print('特徴量重要度 top3:') imp = pd.Series(rf.feature_importances_, index=features).sort_values(ascending=False) print(imp.head(3).to_string()) |
1 2 3 | from sklearn.ensemble import ExtraTreesRegressor et = ExtraTreesRegressor(n_estimators=500, n_jobs=-1, random_state=42) # 分割点もランダム化 → さらに分散低減・学習高速化 |
1 2 3 4 5 6 7 8 9 10 11 | from xgboost import XGBRegressor from sklearn.metrics import r2_score # XGBoost 2.0 以降、 early_stopping_rounds は fit() ではなくコンストラクタ引数 xgb = XGBRegressor(n_estimators=500, learning_rate=0.05, max_depth=5, subsample=0.8, colsample_bytree=0.8, random_state=42, early_stopping_rounds=20) xgb.fit(X_tr, y_tr, eval_set=[(X_te, y_te)], verbose=False) print(f'早期終了した木の本数 = {xgb.best_iteration}') print(f'テスト R2 = {r2_score(y_te, xgb.predict(X_te)):.4f}') # RF より高精度になることが多い。 ハイパーパラメータ調整が肝心 |
1 2 3 4 5 | import lightgbm as lgb lgb_model = lgb.LGBMRegressor(n_estimators=500, learning_rate=0.05, num_leaves=31, random_state=42) lgb_model.fit(X_tr, y_tr, eval_set=[(X_te, y_te)], callbacks=[lgb.early_stopping(20)]) # 数百万行データでも数秒で訓練。 カテゴリ・欠損値ネイティブ対応 |
1 2 3 4 | from catboost import CatBoostRegressor cat = CatBoostRegressor(iterations=500, learning_rate=0.05, depth=6, verbose=0) cat.fit(X_tr, y_tr, cat_features=[]) # カテゴリ変数の前処理不要、 デフォルトでも高精度 |
1 2 3 4 5 6 7 | import shap explainer = shap.TreeExplainer(rf) sv = explainer(X_te) # Explanation(値・基準値・入力をまとめて持つ) shap.summary_plot(sv, X_te, show=False) # 各特徴の影響度・方向を可視化 shap.plots.waterfall(sv[0], show=False) # 個別予測の説明(Explanation を 1 件渡す) print('SHAP 値の形 =', sv.values.shape) print(f'基準値 E[f(x)] = {sv.base_values[0]:,.0f} 人') |
🎯 このコードでやること: まず環境をそろえます。 必要なライブラリを入れ、 matplotlib の日本語フォント(Hiragino Sans)を設定し、 SSDSE を encoding='cp932' で読み込んで shape・head()・describe() を確認します。 この後の節では、 47 都道府県データにランダムフォレストを当てます。 木のアンサンブルなので標準化は不要ですが、 特徴量重要度は「相関の強い変数どうしで分け合われる」ため、 重要度が低い=不要とは限らない点に注意が要ります。 SSDSE は人口系の列が互いに 0.99 近い相関を持つので、 この現象が起きやすいデータです。 エンコーディングを指定し忘れると 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 26 27 | # ランダムフォレスト を 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]) df = df.rename(columns={'SSDSE-B-2026': '年度'}) # 先頭列が年度 print('shape:', df.shape) # (564, 112) — 47 都道府県 × 12 年度(2012-2023) print('cols head:', list(df.columns[:8])) # 2) 直近年度(2023 年度)に絞る df23 = df[df['年度'] == 2023].copy() print('rows in 2023:', len(df23)) # 3) ランダムフォレスト を動かすために必要な列だけ取り出す 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)) |
うまく動かないときは ①data/raw/SSDSE-B-2026.csv のパス、 ②encoding='cp932'(SSDSE-B は Shift_JIS 系)、 ③1 行目に英数字ヘッダ、 2 行目に日本語列名が入る構造なので skiprows=[1](日本語名の行だけ除外)が必要、 の 3 点を確認してください。
feature_importances_(mean decrease in impurity)は分割回数・カーディナリティに偏る。 連続変数・高カーディナリティのカテゴリ変数が過大評価され、 二値変数が過小評価される傾向。 また学習データに対する重要度なので、 過学習を反映する場合も。 Permutation Importance(テストデータで実施)とSHAP値を併用してクロスチェックするのが現代的。n_estimators=100, max_depth=None, min_samples_leaf=1 で過学習しやすい。 (i) n_estimators は 500-1000 程度に増やす、 (ii) max_depth を 5-20 で制限、 (iii) min_samples_leaf を 2-10 に、 (iv) max_features='sqrt'(分類)/ 0.33(回帰、 p/3 相当の小数指定)に。 GridSearchCV や RandomSearchCV、 Optuna でチューニング。 適切な調整で R² が 5-15% 改善することはざら。class_weight='balanced'、 (ii) SMOTE などのオーバーサンプリング、 (iii) 評価指標を accuracy ではなく F1・AUC・recall に、 (iv) 閾値調整(デフォルト 0.5 を変える)。 「accuracy が高い」だけでは不均衡データでは無意味。この用語を実務で使うときにつまずきやすい点を、 失敗パターン別に整理しました。 1 度経験すれば回避できるものばかりですが、 先に知っておくと事故が大幅に減ります。
p値だけでなく効果量も併記するのが現代統計の標準。 主要な指標と Cohen の解釈基準:
| 統計量 | 効果量 | 小 | 中 | 大 |
|---|---|---|---|---|
| 2群平均差 | Cohen's d | 0.2 | 0.5 | 0.8 |
| 相関 | r | 0.1 | 0.3 | 0.5 |
| 線形回帰 | R² | 0.02 | 0.13 | 0.26 |
| ANOVA | η² (eta²) | 0.01 | 0.06 | 0.14 |
| χ² | Cramér's V | 0.1 | 0.3 | 0.5 |
| ロジスティック | Odds Ratio | 1.5 | 2.5 | 4.0 |
| 日本語 | 英語 |
|---|---|
| 統計的に有意 | 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つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 統計・データサイエンス › 機械学習 › 教師あり学習 › ランダムフォレスト
中心に ランダムフォレスト を置き、 そこから 決定木・XGBoost・分類・LightGBM 計 4 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語とあとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。
大きな円が小さな円を包含する Circle Packing 図。 「ランダムフォレスト」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「ランダムフォレスト」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは ランダムフォレスト の隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス → 教師あり学習 → ランダムフォレスト という入れ子の位置を示します。 「教師あり学習には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。
「ランダムフォレスト」は単独で完結する手法ではなく、 隣接領域と 接続 / 統合 / 比較 の 3 視点で連携して初めて真価を発揮する。 章 10 が派生カタログ、 章 15 が初期分岐、 本セクションは 実務で隣接技術と組み合わせる切替判断 に集中する。
ランダムフォレストを中心に、 データ準備から解釈・運用までの一気通貫パイプラインの隣接ノードを整理:
pd.get_dummies で one-hot 化するか、 sklearn 1.4+ なら OrdinalEncoder + HistGradientBoostingRegressor 経由のネイティブ対応がよい。RandomizedSearchCV や Optuna で。 SSDSE-B-2026 は 47 サンプルしかないので cv=5 でも fold あたり 9 県、 n_estimators=300 程度で十分。joblib.dump(model, 'rf.pkl') で保存し FastAPI 等で推論 API 化。 解釈面では Partial Dependence Plot (PDP) で「高齢人口を変えると死亡数がどう変わるか」を曲線で見せられる。ランダムフォレスト単独でも強いが、 以下 3 つの隣接手法と組み合わせるとさらに効く:
IterativeImputer(estimator=RandomForestRegressor()) = MissForest 法。 SSDSE-B-2026 の数値列に欠損がある場合、 他列で RF を学習 → 欠損列を予測補完を繰り返し、 一般の平均補完より MAE が 30–50% 低下する事例が多い。StackingClassifier で 10 行で実装可能。「ランダムフォレスト vs 類似手法」の選定で迷ったらこの表 (相補的 = 用途で使い分け、 競合的 = 1 つを選ぶ):
| 手法 | ランダムフォレストに切り替える条件 | 利点 | 注意点 |
|---|---|---|---|
| 単一決定木 | 精度が必要で、 単一木では過学習する場合 | バギングで分散低減、 OOB スコアで内部検証無料、 ハイパラに鈍感 | 解釈性が落ちる (300 本の木は人間が読めない、 SHAP で補完必要) |
| XGBoost / LightGBM / CatBoost | ハイパラ調整に時間が割けない、 並列学習が必要、 small/medium データで安定したい | デフォルト設定でほぼ最強、 学習が並列 (n_jobs=-1)、 OOB で過学習検出無料、 欠損 OK | ピーク精度は GBM 系の方が 2-5% 高いことが多い、 RAM 消費大 (n_estimators × max_depth) |
| Extra Trees | RF より少しだけ分散低減を強化、 訓練速度も上げたい | 分割閾値をランダム選択するため過学習しにくい、 訓練が RF より 1.5x 速い | 特徴量重要度はランダム選択の影響で不安定、 解釈用途には RF の方がよい |
| 線形回帰 / ロジスティック回帰 | 線形仮定では精度不足、 交互作用・非線形を捕捉したい | RF は前処理が楽 (スケーリング不要、 外れ値耐性、 欠損 OK)、 交互作用自動検出 | 線形回帰は係数で因果的解釈ができるが、 RF は予測専用 (相関ベース) |
| ニューラルネット (PyTorch) | 表形式中規模データ (≦ 数十万行)、 解釈性も欲しい | RF は表形式データで NN を上回ることが多い (TabNet, NODE 等の DL Tabular より単純で強い)、 ハイパラ少ない、 解釈付き | 画像・音声・テキスト・系列データでは NN が圧倒、 RF はそれらに不向き |
ランダムフォレストを選ぶべき場面の要約: (i) 表形式データで非線形・交互作用が予想される、 (ii) 前処理を最小化したい、 (iii) ハイパラチューニングに時間を割けない、 (iv) 特徴量重要度を出したい、 (v) 中規模データ (10^3–10^6 行) — のいずれかが該当するなら RF が第一候補。 SSDSE-B-2026 の死亡数予測は典型例: 47 サンプル × 数個〜数十特徴量で、 RF が線形回帰と XGBoost の中間的精度・解釈性を提供する。
「random forest」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。
| シナリオ | 重視する観点 | 候補手法 |
|---|---|---|
| 特徴量が多い (高次元) かつ非線形 | 変数間の相互作用を自動捕捉 | ランダムフォレスト or 勾配ブースティング |
| 外れ値・欠損が混在 | 頑健性と前処理省略を重視 | ランダムフォレスト (分割基準は順位に強い) |
| 解釈性を最優先したい | 1 本の木でルールを読みたい | 決定木 (深さ 4-6) を選ぶ |
| 予測精度を最優先したい | ブースティング + ハイパラ調整 | XGBoost / LightGBM / CatBoost |
| 変数重要度を出したい | permutation / impurity 重要度 | ランダムフォレストの feature_importances_ |
既存の各章に加え、 ここでは直感 → 落とし穴 → 発展を一段掘り下げる。 数値はすべて data/raw/SSDSE-B-2026.csv(cp932, skiprows=[1], 2023 年度 47 都道府県)での実測値で、 合成データを使う箇所は「架空」と明記する。 関連ページへのリンクは 決定木・アンサンブル・ジニ不純度・ブートストラップ・SHAP・XGBoost など既存の用語ページに接続している。
1 本の決定木は訓練データのわずかな入れ替えで枝分かれが大きく変わる高バリアンスな弱学習器。 ランダムフォレストは (1) ブートストラップ標本(行を復元抽出)と (2) 各分割での特徴量ランダム選択(列を max_features 個に制限)という 2 種類の撹乱で互いに脱相関した木を大量に作り、 回帰なら平均・分類なら多数決で集約する。 分散の縮小式 $\mathrm{Var}=\rho\sigma^2+\frac{1-\rho}{B}\sigma^2$ が示す通り、 木の本数 $B$ を増やすと第 2 項は消え、 残るのは木間相関 $\rho$ に比例する項だけ。 だから RF は「$\rho$ を下げる」ために列をわざとランダムに絞る(バギングとの違いはこの列サブサンプリング)。
特徴量=総人口 A1101・65歳以上人口 A1303・出生数 A4101・婚姻件数 A9101 の 4 つで死亡数 A4200 を予測。 n_estimators だけを動かした OOB R² の実測:
| n_estimators | 1 | 5 | 10 | 50 | 100 | 300 |
|---|---|---|---|---|---|---|
| OOB R² | −0.782 | 0.688 | 0.946 | 0.944 | 0.945 | 0.942 |
→ 1 本では OOB R² が負(単一木は不安定)だが、 わずか 10 本で 0.946 まで一気に立ち上がり、 以降は増やしても過学習せず頭打ちで安定する。 これが「本数は多くても害がない(計算コストが増えるだけ)」の実測的裏付け。
RF の予測は葉ノードに落ちた訓練サンプルの平均値なので、 訓練データの最大値を超えられない。 実測で確認:総人口が最大の東京都を訓練から除外し、 残り 46 県で RF(n_estimators=300)を学習して東京の死亡数を予測すると、 実測 137,241 人に対し予測は 100,156 人。 訓練データ中の死亡数の最大は 104,964 人で、 予測はほぼそこで飽和している。 時系列トレンドの外挿や、 訓練分布の外側を狙う予測には 線形回帰 や GAM を併用する。
Gini 重要度(mean decrease in impurity)は「分割に使われた回数×不純度減少」の集計なので、 取りうる値が多い連続変数・高カーディナリティ列ほど分割候補になりやすく過大評価されやすい。 検証として、 上記 4 特徴量に目的変数と無関係な架空の乱数列 NOISE_rand(標準正規, seed=1)を 1 本足すと、 Gini 重要度は NOISE_rand=0.005 とゼロではない値を受け取る。 一方テストで測る Permutation importance では 0.001 とほぼ消える。 実測 Gini(65歳以上 0.277 / 総人口 0.268 / 出生数 0.240 / 婚姻 0.215)と Permutation(65歳以上 0.246 / 総人口 0.132 / 婚姻 0.130 / 出生数 0.089)で順位も配分も変わる点に注意。 相関の強い人口系変数どうしでは重要度が分散して両方低く見えることもあるため、 Gini 単独で結論せず Permutation と SHAP を併記する。
「2022→2023 で総人口が増えた県」を分類対象にすると、 増加は東京都 1 県のみ・減少 46 県という極端な不均衡。 このとき「全県を減少と予測」する多数決ベースラインの精度は 0.979、 RF の OOB 精度も 0.979 で両者が区別できない。 accuracy だけ見れば「97.9% の高精度」に見えるが、 少数クラス(増加県)は 1 つも当てられていない可能性がある。 不均衡時は class_weight='balanced'、 F1・ROC-AUC・recall・PR 曲線での評価、 BalancedRandomForestClassifier などを使う。
47 県の小標本では、 分割閾値もランダム化する Extra Trees の方が RF より安定することがある(実測 CV5 R²:RF 0.931 ± 0.034 に対し Extra Trees 0.956)。 一方、 中〜大規模の構造化データでは逐次補正でバイアスを詰める XGBoost/LightGBM/CatBoost が RF を上回ることが多い。 RF は木を深く多数持つほどメモリと推論時間が線形に増える点、 単一木の解釈性は失われ SHAP 等の後付け説明が要る点も実務コスト。 OOB 推定は各サンプルが平均 37% の木でしか未使用にならないため、 木が少ない(上表 n=1〜5)とそもそもOOB 予測が付かず不安定になる(sklearn も警告を出す)。
max_features を小さくするほど木は脱相関するがバイアスは増える。 バイアス-バリアンスのトレードオフをこの 1 パラメータで動かす。n_estimators は「多いほど安定・過学習しない」(上表で実証)。 過学習を制御するのは max_depth/min_samples_leaf。 本データでは信号が強く、 max_depth を 1→2→3→None と深めると OOB R² が 0.794→0.910→0.936→0.942 とむしろ改善(深さが常に過学習を招くわけではない実例)。※ 本節の R²・重要度・精度・外挿値はいずれも SSDSE-B-2026(2023 年・47 県)での実測。 乱数列 NOISE_rand のみ「架空」の合成列(seed 固定)で、 それ以外の特徴量・目的変数はすべて実データ列。