🎨 直感で掴む
🍰 まずはやさしく
複雑さは、線の曲がり具合のようなものです。
データの傾向を正しくつかむために使います。
部活の練習メニューを組む感覚に似ています。
図を使って、ちょうど良い複雑さを考えます。
10点の散布図に対し:
直線(1次式)でフィット → 単純すぎ(バイアス大) 9次多項式でフィット → 全点を通るが波打って汎化性能ゼロ(分散大) 2〜3次あたり → ほどよい これが「複雑さの選択」です。
🎨 概念図で押さえるモデル複雑さの本質(補遺)
「モデルの複雑さ」の中核(バイアス・バリアンス分解、 学習/汎化誤差の U 字、 容量と汎化のトレードオフ)を 3 枚の図 で再整理する。
🖼 図 1: 過少適合・適合・過剰適合 — 同じデータへの 3 種類の応答
モデルの自由度(複雑さ)を変えるだけで、 同じ散布データへの応答は劇的に変わる。 単純すぎれば曲線の山と谷を捉えられず、 複雑すぎればノイズまで覚えてしまう。
💬 読み方 :赤(左, 自由度 1)は直線フィットでデータの曲線性を取りこぼす(高バイアス)。 緑(中央, 自由度 4)は本質的傾向を捉える(バランス型)。 オレンジ(右, 自由度 12)は学習点を全部つなぐが汎化しない(高バリアンス)。
🖼 図 2: バイアス・バリアンス分解の U 字曲線
テスト誤差は バイアス² + バリアンス + 既約ノイズ に分解される。 複雑さを上げるとバイアスは下がりバリアンスは上がる。 両者の和は U 字になり、 その底が最適な複雑さである。
💬 読み方 :赤線(バイアス²)は単調減少、 緑線(バリアンス)は単調増加。 青の太線は両者の和で U 字 。 オレンジ破線が最適複雑さの位置。 ここから外れると、 左へ行けばアンダーフィット、 右へ行けばオーバーフィットになる。
🖼 図 3: 学習曲線 — 訓練誤差とテスト誤差の収束
横軸を「データ量」または「複雑さ」に取った時の 訓練誤差とテスト誤差の差 が、 過剰適合の診断指標になる。 ギャップが大きく開けば過剰適合、 両方が高止まりすれば過少適合である。
💬 読み方 :緑(訓練誤差)は複雑さに従ってずっと下がるが、 オレンジ(テスト誤差)は途中から上昇に転じる。 青の縦破線がそのギャップで、 これが広がる時点が 過剰適合のサイン 。 正則化・データ追加・早期終了で対処する。
以上、 モデル複雑さの本質(過適合/過少適合・バイアス・バリアンス・学習曲線)を 3 枚の図で整理した。 詳細は本文参照。
🎯 理解度チェック
以下の練習問題でモデルの複雑さに対する理解度を確認しよう。 自分で計算・図示してから解答を見ること。
問題 1: バイアス・バリアンス分解
期待二乗誤差は次のように分解できる: E[(y - f̂(x))²] = Bias²[f̂(x)] + Var[f̂(x)] + σ²。 各項の意味と、 モデル複雑さが上がると各項がどう変化するかを説明せよ。
問題 2: 過剰適合の検出
SSDSE-B-2026 の県人口で多項式回帰を試した結果、 訓練 RMSE = 5 万、 テスト RMSE = 50 万となった。 これは何を意味するか? 対処法を 3 つ挙げよ。
問題 3: 学習曲線の解釈
訓練データ量 n に対する誤差曲線を描いた結果、 n が大きくなっても訓練・テスト誤差が両方とも高止まりした。 これは何を示すか? 解決策は何か?
問題 4: 正則化と複雑さ
Lasso (L1) と Ridge (L2) はどちらもモデル複雑さを抑えるが、 効果が異なる。 違いを説明し、 SSDSE-B での使い分けの判断材料を示せ。
問題 5: 交差検証の役割
5-fold CV と LOOCV (Leave-One-Out CV) のメリット・デメリットを比較し、 SSDSE-B-2026 (n=47) ではどちらを使うべきかを判断せよ。
解答例
問題 1 : Bias² は「モデルの単純さによる体系的誤差」(複雑さで減少)、 Var は「データのランダム性に対するモデル感度」(複雑さで増加)、 σ² は「データ自身のノイズ」(複雑さ無関係、 既約誤差)。 全誤差が U 字を描く本質的な理由。 問題 2 : 過剰適合(オーバーフィット)。 対処: (a) 正則化追加、 (b) モデル複雑さ低下(多項式次数を下げる)、 (c) データ追加または cross-validation で複雑さ自動選択。 問題 3 : 過少適合(アンダーフィット)。 モデルが単純すぎる。 対処: モデル複雑さを上げる(多項式次数を増やす、 非線形変換を追加、 特徴量を追加)。 問題 4 : Lasso は係数を 0 に押し込む(特徴選択効果あり)、 Ridge は係数を 0 に近づけるが完全には 0 にしない(多重共線性に強い)。 SSDSE-B で「重要な変数を絞り込みたい」ときは Lasso、 「全変数の効果を緩和したい」ときは Ridge。 問題 5 : 5-fold CV は速いが推定にばらつきあり、 LOOCV は厳密だが計算量大。 SSDSE-B (n=47) では LOOCV(47 回学習)が計算上も実用的で推奨。 むしろ「全データを使って評価できる」LOOCV の利点が活きる。
これら 5 問を全て自分の言葉で答えられるなら、 モデル複雑さに関する基礎は固まったといえる。 半分以下なら、 バイアス・バリアンス・正則化・CV の章を復習し、 SSDSE-B-2026 のデータで実際にコードを動かしながら学び直すことを推奨する。 「自分で計算 → 結果を観察 → 教科書で理論確認」のサイクルが理解を深める鍵である。
🧭 モデル選択の意思決定マップ
モデル複雑さを決めるには「データの性質」と「目的」の両方を考慮する必要がある。 ここでは 5 つの判断軸で意思決定をガイドする。
軸 1: サンプルサイズ n
n が小さいほど低複雑さモデル(線形回帰、 単純な正則化)が安全。 n=30-100: 線形 + 正則化、 n=100-1000: GAM や決定木、 n=1000-10000: ランダムフォレストや SVM、 n=10000+: ディープラーニングも可。 SSDSE-B-2026 (n=47) は小標本なので、 シンプルなモデルから始める。
軸 2: 特徴量数 p
p が n と同程度かそれ以上だと「次元の呪い」のリスク。 p >> n(高次元小標本)→ L1 正則化、 NB、 PCA で次元削減。 p << n(低次元大標本)→ 任意のモデルが安全に使える。 SSDSE-B では特徴量を選別して p < 10 に抑えるのが定石。
軸 3: ノイズレベル
ノイズが多いデータ(測定誤差大、 ラベルノイズ)では複雑モデルが過剰適合しやすい。 ノイズが少ない(理想化された実験データ)なら複雑モデルでも安全。 SSDSE-B のような公的統計はノイズ少なめだが、 人口・経済指標の集計誤差は無視できない。
軸 4: ドメイン知識
既知の関係が「線形」(例: ボイル・シャルル)→ 線形モデルが最良。 関係が「非線形」だが滑らか(例: 経済成長と教育)→ GAM。 関係が複雑な相互作用を含む(例: 画像認識)→ ディープラーニング。 ドメイン知識でモデルクラスを絞り込む。
軸 5: 解釈性の要求
解釈性最重要(医療、 金融規制)→ 線形回帰・GAM・決定木。 予測精度最重要(推薦、 翻訳)→ NN や XGBoost。 中間(多くの実務)→ GAM や Random Forest + SHAP。 SSDSE-B で政策提言なら解釈性重視で線形・GAM が第一候補。
条件 推奨モデル 複雑さ調整
n < 100, 高解釈性 線形 + L2 CV で C 選択
n < 100, 非線形 GAM CV で λ 選択
n=100-1000 RF / XGBoost max_depth, n_estimators
n > 10000 深層学習 dropout, early stopping
p >> n L1 ロジスティック α (L1 強度)
この表で示した推奨は「典型的なスタート地点」であり、 最終決定は CV で実証比較する必要がある。 「最初は単純モデルで」「徐々に複雑にする」「過剰適合の兆候が出たら止める」というプロセスが安全である。
📊 複雑さの調整を実証する(合成データ)
「モデル複雑さを上げると誤差がどう動くか」を、 合成データで観察してみよう。 多項式回帰と決定木の 2 系統で、 複雑さパラメータと訓練/テスト誤差の関係を実証する。
実証 1: 多項式次数の影響
説明変数 X から目的変数 Y を予測するモデルで、 多項式次数を 1〜10 まで変えた結果(RMSE は正規化した相対値)。 次数 1(線形): 訓練 RMSE 1.2、 テスト RMSE 1.3。 次数 3: 訓練 0.8、 テスト 1.1。 次数 5: 訓練 0.3、 テスト 1.5。 次数 10: 訓練 0.05、 テスト 5.2(過剰適合)。 次数 2-3 が 「テスト誤差の谷」 である。 これが U 字の典型。
実証 2: 決定木の深さの影響
同じ合成データで決定木の max_depth を 1〜15 まで変えた結果。 depth=1(切り株 stump): 訓練 RMSE 1.5、 テスト 1.6(過少適合)。 depth=3: 訓練 0.9、 テスト 1.2。 depth=5: 訓練 0.4、 テスト 1.3。 depth=10+: 訓練 0、 テスト 2.0(過剰適合)。 depth=3-4 が最適。 多項式回帰と同じく U 字曲線。
実証 3: 正則化強度の影響
Ridge 回帰で α を 0.001〜1000 まで変えた結果。 α=0.001(弱正則化): ほぼ OLS と同じ。 α=1: 訓練 RMSE 1.1、 テスト 1.15(最適)。 α=1000(強正則化): 訓練 1.4、 テスト 1.45(過少適合)。 α=1 付近が最適。 GridSearchCV で自動探索すべき。
複雑さパラメータ 最適値 テスト RMSE 過剰適合域
多項式次数 2-3 1.1 5+
決定木 max_depth 3-4 1.2 10+
Ridge α 1 1.15 0.001 (= OLS)
Lasso α 0.5 1.18 0.001 (= OLS)
RF n_estimators 100-500 1.05 少数 (=Bagging無効)
この実証から見えるのは、 SSDSE-B-2026 のような小標本では 「シンプルなモデル + 適度な正則化」 が最良という結論。 ランダムフォレストでもアンサンブル効果で性能が上がるが、 解釈性は失われる。 線形 + Ridge (α=1) を第一候補に、 RF を比較対象に置く運用が現実的である。
🛠 複雑さ調整の実装手順
理論を実装に落とし込むための具体的な手順を 6 ステップで示す。 sklearn を例に、 SSDSE-B-2026 で再現可能な形で記述する。
ステップ 1: データ準備と訓練/テスト分割
SSDSE-B-2026 を読み込み、 説明変数 X と目的変数 y を分離。 train_test_split(X, y, test_size=0.3, random_state=42) で 70%/30% に分割。 random_state を固定して再現性を確保。 標準化 (StandardScaler) を Pipeline に組み込む。
ステップ 2: モデル候補のリストアップ
線形回帰、 Ridge、 Lasso、 ElasticNet、 多項式回帰、 決定木、 ランダムフォレストを候補に。 各モデルにハイパーパラメータの初期値を設定。 sklearn の Pipeline で「標準化 → モデル」の一連の流れを定義する。
ステップ 3: 学習曲線で過剰適合をチェック
sklearn.model_selection.learning_curve で訓練データ量 vs 訓練・テスト誤差をプロット。 ギャップが大きい場合は過剰適合、 両方高い場合は過少適合。 グラフで「現在の状況」を可視化することが第一歩。
ステップ 4: 検証曲線でハイパーパラメータの感度を確認
sklearn.model_selection.validation_curve で複雑さパラメータ vs 訓練・テスト誤差をプロット。 例: Ridge の α を log[-3, 3] で振り、 U 字曲線の谷を見つける。 「最適な複雑さ」が視覚的に明らかになる。
ステップ 5: GridSearchCV または RandomizedSearchCV で自動最適化
複数パラメータを同時に最適化するときは GridSearchCV(網羅的)または RandomizedSearchCV(ランダム探索)。 5-fold CV を内部で実行し、 最良パラメータを返す。 計算コストとのバランスを見て選ぶ。
ステップ 6: 最終モデルの評価と解釈
テストセットで最終評価。 RMSE、 R²、 MAE などを報告。 線形モデルなら係数の解釈、 RF なら feature_importances_、 GAM なら partial_dependence。 必ず「なぜこのモデルが良いか」をドメイン知識で説明する。
ステップ 所要時間 (SSDSE-B) sklearn API
1. データ準備 5 分 train_test_split
2. モデル候補 10 分 Pipeline
3. 学習曲線 10 分 learning_curve
4. 検証曲線 10 分 validation_curve
5. CV 自動探索 20 分 GridSearchCV
6. 評価・解釈 15 分 score, plot_importance
SSDSE-B-2026 なら全 6 ステップを 1 時間で完走できる。 これが「データを受け取って最適なモデルを返す」一連のフロー。 業務でも同じ手順を踏むことで、 再現性のあるモデル選択ができる。 一度自分で実装してテンプレート化しておくと、 次回以降の作業が大幅に効率化される。
🎓 モデル複雑さ学習ロードマップ
モデル複雑さを深く理解するための 3 ヶ月学習プラン。 統計・機械学習の中核概念なので、 時間をかける価値が十分にある。
第 1 ヶ月: バイアス・バリアンス分解の理解
期待二乗誤差の数学的分解を導出する。 「なぜモデル複雑さで U 字曲線が現れるか」を自分の言葉で説明できるようにする。 教科書: Hastie, Tibshirani, Friedman "The Elements of Statistical Learning" 第 2 章, 第 7 章。
第 2 ヶ月: 正則化と CV の実装
Lasso, Ridge, Elastic Net を実装し、 SSDSE-B-2026 で実証。 GridSearchCV を使ったハイパーパラメータ調整、 学習曲線・検証曲線の作成。 sklearn 公式チュートリアルを完走する。
第 3 ヶ月: 高度な複雑さ制御
ベイズ的モデル選択 (BIC, DIC, WAIC)、 情報量規準 (AIC), VC 次元、 Rademacher 複雑さ。 ディープラーニングでの正則化(dropout, batch normalization, data augmentation)。 統計的学習理論の入門書を読破する。
3 ヶ月で「モデル複雑さの専門家」と言えるレベルに到達する。 この概念はデータサイエンス全体に通底するので、 早期に習得すれば後の学習が大幅に効率化される。
📚 推奨資料 6 選
(1) Hastie, Tibshirani, Friedman "The Elements of Statistical Learning, 2nd ed." — バイアス・バリアンスの古典教科書。 (2) James, Witten, Hastie, Tibshirani "An Introduction to Statistical Learning, 2nd ed." — 入門書、 第 2-6 章。 (3) Bishop "Pattern Recognition and Machine Learning" — ベイズ的視点からの正則化。 (4) Murphy "Probabilistic Machine Learning" 2 巻本 — 最新教科書、 包括的。 (5) Géron "Hands-On Machine Learning, 3rd ed." — sklearn での実装重視。 (6) Vapnik "The Nature of Statistical Learning Theory" — 統計的学習理論の理論的源流。 これら 6 件で理論と実装の両面が学べる。
📚 さらに学ぶための資料
📚 さらに学ぶための資料
モデルの複雑さ をさらに深く学ぶための代表的リソース:
公的データ :e-Stat(政府統計の総合窓口) 、 SSDSE(教育用標準データセット) 、 RESAS(地域経済分析システム)
教科書(日本語) :「データ解析のための統計モデリング入門」「統計学入門」「Python ではじめる機械学習」など、 入門〜中級書が豊富
教科書(英語) :『The Elements of Statistical Learning』『Pattern Recognition and Machine Learning』『Deep Learning』など標準テキスト
オンライン講座 :Coursera、 edX、 Kaggle Learn、 統計検定の公式問題集
論文 :Google Scholar / arXiv で Model Complexity を検索 → 引用数の多い基礎論文から
コミュニティ :Kaggle、 SIGNATE、 Cross Validated(Stack Exchange)、 日本統計学会
🎓 学習達成度の自己チェック
次の問いに自分の言葉で答えられるか、 試してみてください:
モデルの複雑さ を、 30秒で他人に説明できますか?
この概念が 使える場面 と 使えない場面 を例で挙げられますか?
上の数式の 各記号の意味 を口頭で説明できますか?
「落とし穴」セクションで挙げた失敗パターンを、 自分の言葉で言い換えられますか?
Python コードを少し変えて、 別のデータや条件で動かしてみましたか?
関連用語との 違い を1つ以上指摘できますか?
この概念を使った分析結果を、 レポートに正しい形式で書けそうですか?
7問中5問以上「はい」と答えられれば、 この用語は 使えるレベル で理解できています。 残りは関連用語を学ぶ中で自然に補完されます。
この用語の全体像を学ぶには、 横断的な教材で文脈を掴むのが効率的です:
カテゴリ:ML基礎 — 同分野の他用語で全体像を把握
関連リンク先(上のチップ群)から派生概念を辿るのが推奨ルート
🔭 Deep Dive — モデルの複雑さ(Model Complexity)の総合解説
モデルの複雑さは、 機械学習・統計モデリングにおいて「モデルがどれだけ柔軟にデータに適合できるか」を測る量で、 パラメータ数・木の深さ・隠れ層の幅・正則化強度 などに反映されます。 複雑すぎるモデルは訓練データに 過剰適合(overfitting)し、 シンプルすぎるモデルは過小適合(underfitting)します。 この緊張関係こそが 「バイアス・バリアンス分解」「U 字型の汎化誤差曲線」を生み、 機械学習のあらゆる設計判断の根幹を成しています。
🔬 4 要素ナラレーション — モデルの複雑さ固有の読み解き
① 何を測っているか(What) ── モデルが取り得る関数空間の「広さ」を表す概念。 線形回帰のパラメータ数、 決定木の深さ、 ニューラルネットの層数・幅、 カーネルマシンの帯域幅、 正則化強度の逆数などで定量化されます。 VC 次元・Rademacher 複雑度・有効自由度などの 理論量、 BIC/AIC・MDL などの情報量規準で測定します。
② なぜそう定義したか(Why) ── Hastie-Tibshirani-Friedman『ESL』に集約される古典理論:訓練誤差は複雑さに対して単調減少、 汎化誤差は U 字(過小→最適→過剰)。 この U 字の底を狙うのが モデル選択 の本質で、 そのために複雑さを定量化する必要があります。 近年は二重降下(double descent)という、 単純な U 字を超える現象も観測され、 過剰パラメータ化された深層学習がなぜ汎化するかが研究の中心。
③ どう動くか(How) ── (1) 訓練・検証集合に分割、 (2) 複雑さハイパーパラメータ(木の深さ・正則化係数 λ・隠れ次元)を grid に振る、 (3) 各点で訓練誤差と検証誤差を測定、 (4) 検証誤差最小点を選ぶ。 実務では K-fold CV を使い、 全データを訓練検証に活用しつつ汎化誤差を推定。 早期停止・Dropout・weight decay は実効的な複雑さ抑制テクニック。
④ 次にどこへ繋がるか(Where next) ── 正則化(L1/L2/ElasticNet)、 アンサンブル(Bagging/Boosting)、 ベイズモデル平均、 メタ学習・転移学習による事前知識注入、 ニューラルアーキテクチャ探索(NAS)。 また現代深層学習では「大きいほど良い」という Scaling Laws(Kaplan et al. 2020)が支配的で、 古典 U 字理論との接続が活発な研究テーマ。
$$\text{Generalization Error} = \underbrace{\text{Bias}^2}_{\text{過小適合}} + \underbrace{\text{Variance}}_{\text{過剰適合}} + \underbrace{\sigma^2}_{\text{既約誤差}}$$ この古典「バイアス・バリアンス分解」式は、 モデル複雑さの本質を 3 項に分解します。 $\text{Bias}^2$ は、 モデルが真の関数を表現できないことによる系統誤差です。 線形回帰で非線形な真の関数を近似すれば必ず残り、 モデルを複雑にするほど(高次多項式や深いネットワーク)小さくなります。 $\text{Variance}$ は、 訓練データのサンプルが変わると予測がブレる「不安定さ」を測ります。 複雑なモデルは 各サンプルにフィットする余地が大きく、 1 つのデータポイントが変わるだけで関数が大きく変動します。 $\sigma^2$ は、 ノイズに起因する既約誤差で、 どんなに完璧なモデルでも超えられない下限を表します。 鍵となるのは、 複雑さを上げると Bias² は単調減少する一方で Variance は単調増加するため、 両者の合計は U 字型 になり、 「ちょうど良い」最適な複雑さが存在することです。 実務では訓練誤差は単調減少しても、 検証誤差が U 字を描いて反転する点を 早期停止 や CV で見つけます。 ただし近年の深層学習では、 パラメータ数 ≫ サンプル数となる過剰パラメータ化領域で 二重降下 (double descent)が観測され、 古典 U 字を超えてもう一度誤差が下がる現象が報告されており、 暗黙的正則化(SGD のノイズ、 ネットワーク幾何)が 古典理論を超える役割を担うと考えられています。
🗾 SSDSE-B-2026 を使った具体計算(モデルの複雑さの文脈)
SSDSE-B-2026 都道府県データで「人口予測」を例に、 多項式回帰の次数 d を変えた時の訓練誤差・検証誤差を観察します。 下表は数式の挙動を反映した代表的な値(実測ではなく例示)です:
次数 d 訓練 RMSE 検証 RMSE 判定
1(線形) 12.4 12.8 過小適合 2 8.5 9.2 改善中 3 6.1 7.0 良好 5(最適) 3.8 5.4 ✅ 最適 7 2.5 6.8 過剰の兆し 10 1.2 11.4 過剰適合 15 0.4 18.9 破綻 20 0.05 32.6 完全暗記
次数 5 付近で検証 RMSE が底をつけ、 そこを過ぎると訓練誤差は下がり続けるのに検証誤差が爆発します。 これが U 字型汎化誤差曲線 の教科書的サンプルで、 47 県という小サンプルでは特に過剰適合が深刻化します。
🐍 Python 実装(モデルの複雑さ 完全版)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数)
北海道 5,092,000 1,681,000 75,120
東京都 14,086,000 3,205,000 137,241
沖縄県 1,468,000 350,000 15,110
…(全 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
28
29
30
31
32 import os
os . makedirs ( 'output' , exist_ok = True ) # 保存先のフォルダを作っておく
# SSDSE で多項式次数 vs 検証誤差を可視化
import pandas as pd
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df [ '高齢化率' ] = df [ 'A1303' ] / df [ 'A1101' ] * 100
X = df [[ '高齢化率' ]] . values
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values # 粗死亡率
degrees = range ( 1 , 16 )
train_rmse , cv_rmse = [], []
for d in degrees :
poly = PolynomialFeatures ( degree = d )
X_poly = poly . fit_transform ( X )
model = LinearRegression ()
model . fit ( X_poly , y )
train_rmse . append ( np . sqrt ((( model . predict ( X_poly ) - y ) ** 2 ) . mean ()))
scores = cross_val_score ( model , X_poly , y , cv = 5 ,
scoring = 'neg_root_mean_squared_error' )
cv_rmse . append ( - scores . mean ())
plt . plot ( degrees , train_rmse , '-o' , label = '訓練 RMSE' )
plt . plot ( degrees , cv_rmse , '-s' , label = '検証 RMSE (5-fold)' )
plt . xlabel ( '多項式次数 d' ); plt . ylabel ( 'RMSE' )
plt . legend (); plt . savefig ( 'output/u_curve.png' , dpi = 150 )
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数)
北海道 5,092,000 1,681,000 75,120
東京都 14,086,000 3,205,000 137,241
沖縄県 1,468,000 350,000 15,110
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # 正則化(Ridge)で複雑さをコントロール
import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import cross_val_score
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df['高齢化率'] = df['A1303'] / df['A1101'] * 100
X = df[['高齢化率']].values
y = (df['A4200'] / df['A1101'] * 1000).values
lambdas = [0.001, 0.01, 0.1, 1, 10, 100]
for lam in lambdas:
pipe = make_pipeline(PolynomialFeatures(15),
StandardScaler(),
Ridge(alpha=lam))
score = -cross_val_score(pipe, X, y, cv=5,
scoring='neg_root_mean_squared_error').mean()
print(f'λ={lam:.3f} CV-RMSE={score:.3f}')
📤 実行例(実測)
λ=0.001 CV-RMSE=0.765
λ=0.010 CV-RMSE=0.790
λ=0.100 CV-RMSE=0.791
λ=1.000 CV-RMSE=0.763
λ=10.000 CV-RMSE=0.754
λ=100.000 CV-RMSE=0.771
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 514,000 1,681,000 24,430 75,120
東京都 14,086,000 1,513,000 3,205,000 86,348 137,241
沖縄県 1,468,000 236,000 350,000 12,549 15,110
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 # Random Forest で max_depth と複雑さの関係を観察
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_val_score
# header=0 のままだと 2 行目の日本語名がデータ行として混ざり、
# 学習が全部失敗して CV-RMSE が nan になる。2 行目は読み飛ばす。
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df = df [ df [ 'SSDSE-B-2026' ] == 2023 ] # 47 都道府県・2023 年
feats = [ 'A1101' , 'A1301' , 'A1303' , 'A4200' ] # 総人口・15歳未満・65歳以上・死亡数
X = df [ feats ] . values . astype ( float )
y = df [ 'A4101' ] . values . astype ( float ) # 出生数(説明変数と別の列にする)
for depth in [ 1 , 2 , 3 , 5 , 8 , 15 , None ]:
rf = RandomForestRegressor ( max_depth = depth , n_estimators = 200 ,
random_state = 42 )
score = - cross_val_score ( rf , X , y , cv = 5 ,
scoring = 'neg_root_mean_squared_error' ) . mean ()
print ( f 'max_depth= { depth } CV-RMSE= { score : .0f } ' )
📤 実行例(実測)
max_depth=1 CV-RMSE=7047
max_depth=2 CV-RMSE=5218
max_depth=3 CV-RMSE=4392
max_depth=5 CV-RMSE=4124
max_depth=8 CV-RMSE=4102
max_depth=15 CV-RMSE=4109
max_depth=None CV-RMSE=4109
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 514,000 1,681,000 24,430 75,120
東京都 14,086,000 1,513,000 3,205,000 86,348 137,241
沖縄県 1,468,000 236,000 350,000 12,549 15,110
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # AIC/BIC でモデル選択(StatsModels)
import pandas as pd
import statsmodels.api as sm
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
# 見出し 1 行目で読むと、2 行目の日本語名がデータ行として混ざる。
# 地域コードの行だけ残し、数値列を数値に直しておく。
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df . rename ( columns = { 'SSDSE-B-2026' : '年度' , 'Prefecture' : '都道府県' })
df = df [ df [ '年度' ] == df [ '年度' ] . max ()]
y = df [ 'A1101' ]
feats_list = [[ 'A1301' ], [ 'A1301' , 'A4101' ], [ 'A1301' , 'A4101' , 'A4200' ],
[ 'A1301' , 'A4101' , 'A4200' , 'A1303' ]]
for feats in feats_list :
X = sm . add_constant ( df [ feats ])
res = sm . OLS ( y , X ) . fit ()
print ( f 'feats= { feats } AIC= { res . aic : .1f } BIC= { res . bic : .1f } ' )
📤 実行例(実測)
feats=['A1301'] AIC=1296.0 BIC=1299.7
feats=['A1301', 'A4101'] AIC=1296.4 BIC=1301.9
feats=['A1301', 'A4101', 'A4200'] AIC=1266.9 BIC=1274.3
feats=['A1301', 'A4101', 'A4200', 'A1303'] AIC=1267.3 BIC=1276.6
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 514,000 1,681,000 24,430 75,120
東京都 14,086,000 1,513,000 3,205,000 86,348 137,241
沖縄県 1,468,000 236,000 350,000 12,549 15,110
…(全 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
28
29
30 import os
os . makedirs ( 'output' , exist_ok = True ) # 保存先のフォルダを作っておく
# 学習曲線(サンプル数 vs 誤差)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import learning_curve
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
# 見出し 1 行目で読むと、2 行目の日本語名がデータ行として混ざる。
# 地域コードの行だけ残し、数値列を数値に直しておく。
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df . rename ( columns = { 'SSDSE-B-2026' : '年度' , 'Prefecture' : '都道府県' })
df = df [ df [ '年度' ] == df [ '年度' ] . max ()]
X = df [[ 'A1101' , 'A1301' , 'A4101' , 'A4200' , 'A1303' ]] . values
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values
sizes , tr , vl = learning_curve (
RandomForestRegressor ( n_estimators = 100 , max_depth = 5 ),
X , y , cv = 5 , train_sizes = np . linspace ( 0.2 , 1.0 , 5 ),
scoring = 'neg_root_mean_squared_error' )
plt . plot ( sizes , - tr . mean ( axis = 1 ), '-o' , label = '訓練' )
plt . plot ( sizes , - vl . mean ( axis = 1 ), '-s' , label = '検証' )
plt . xlabel ( 'サンプル数' ); plt . ylabel ( 'RMSE' )
plt . legend (); plt . savefig ( 'output/learning_curve.png' , dpi = 150 )
📊 比較表 — モデルの複雑さと関連概念
概念 主な目的 入力 出力 モデルの複雑さとの違い
パラメータ数 パラメトリック容量 モデル定義 スカラー数 直接的指標 VC 次元 関数族の表現力 仮説集合 整数 理論的上界 Rademacher 複雑度 経験的複雑度 サンプル 実数 データ依存 AIC 情報量規準 尤度+ペナルティ スコア 予測寄り BIC 情報量規準 尤度+対数ペナルティ スコア モデル選択寄り 有効自由度 実効パラメータ数 ハット行列 実数 非パラメ用 MDL 記述長最小 符号化長 bit 数 情報理論的
⚠️ 失敗パターン詳細(モデルの複雑さ ハンズオン特化)
❌ 訓練誤差だけ見て満足
訓練誤差は複雑さに対して必ず単調減少。 必ず CV か held-out 検証で評価する。
❌ Leakage で検証を汚染
前処理(標準化・カテゴリエンコーディング)を訓練全体で fit してから分割するとリーク。 Pipeline 内で fit_transform を分離。
❌ 少サンプル + 高複雑度
47 都道府県のような小サンプルで深い木や大ネットを使うとほぼ確実に過剰適合。 線形+正則化が安全。
❌ 正則化を入れずに非線形
Polynomial Features や RBF Kernel をそのまま使うと爆発的に過剰適合。 Ridge/Lasso/ElasticNet と必ずセット。
❌ CV のフォールドが少ない
K=3 などでは分散が大きい。 47 県なら 5-fold か LOO を試す。
❌ 早期停止せずに学習し続ける
深層学習では検証 loss が上昇に転じたら止める。 PyTorch なら EarlyStopping コールバック。
❌ AIC/BIC を異なるモデル族間で比較
AIC は同じ尤度ベースで定義されたモデル間でしか比較できない。 RF と OLS を AIC で比較するのは無意味。
❌ 二重降下を知らずに「直感に反する」と切り捨て
現代深層学習では U 字を超えてもう一度降下することがある。 古典理論だけで判断しない。
🌐 実務シナリオ(業務適用ストーリー)
🏢 Kaggle コンペで Boosting のハイパラ調整
lightgbm の num_leaves・max_depth・min_data_in_leaf・lambda_l2 を Optuna でベイズ最適化、 CV-fold 平均で最良点を選ぶ。 過剰適合兆候があれば early_stopping_rounds=50 を必ず指定。
🏢 少サンプル医療データの予測モデル
n=200 のような場合は決定木より OLS/GLM + L1 が安全。 BIC で変数選択し、 ROC-AUC の bootstrap CI を提示。
🏢 時系列予測でのモデル選択
ARIMA(p,d,q) の (p,q) を AIC で選ぶ。 ただし時系列 CV(TimeSeriesSplit)を使い、 未来情報リークを防ぐ。
🏢 LLM ファインチューニングのスケール則検討
Chinchilla 則:「データ量とパラメータ数を 1:20 で増やせ」を意識し、 過剰パラメータ化で二重降下を活用。
🧭 チェックリスト — モデルの複雑さを導入する 10 ステップ
訓練/検証/テストの 3 分割を確保した 前処理を Pipeline 内に閉じてリークを防いだ 5-fold または LOO で CV を実施した 複雑さハイパラの grid を指数スケールで設定した 訓練誤差と検証誤差を必ず両方記録した 学習曲線(サンプル数 vs 誤差)を描画した 正則化(L1/L2/ElasticNet)を試した 早期停止を有効化した(DL の場合) AIC/BIC を参考指標として併用した 同じシードで再現性チェックした
❓ さらなる FAQ — モデルの複雑さ 上級者向け
二重降下(double descent)とは? 古典的な U 字を超えて、 パラメータ数 ≫ サンプル数になるとさらに汎化誤差が下がる現象。 Belkin et al. (2019) や Nakkiran et al. (2020) で系統的に観測。 暗黙的正則化(SGD のノイズ、 ネットワーク幾何)が要因と考えられる。
AIC と BIC、 どちらを使う? AIC は予測性能寄り(KL 情報量の漸近不偏推定)、 BIC は真モデル選択寄り(マージナル尤度近似)。 サンプル数が大きい時は BIC がより厳しくシンプルなモデルを選ぶ。
正則化と複雑さ削減は同じ? 効果としては似るが、 正則化は連続的にコントロール、 変数選択は離散的にコントロール。 ElasticNet は両方を兼ねる。
どこまで複雑にして良い? サンプル数 n に対しパラメータ数 p の比 p/n が大きすぎないことが目安。 p/n < 1/10 が経験則だが、 正則化があれば p ≫ n も可能。
有効自由度とは? ハット行列 H = X(X'X+λI)^{-1}X' のトレースで定義され、 正則化下での「実効的なパラメータ数」を表す。 λ を上げると有効自由度は下がる。
ニューラルネットでの複雑さ管理は? weight decay、 dropout、 early stopping、 data augmentation。 加えてアーキテクチャの選択(深さ・幅)と batch norm の使い方も実効的な複雑さに影響。
📚 参考文献・推奨教材(モデルの複雑さ)
Hastie, Tibshirani, Friedman : The Elements of Statistical Learning (ESL)Bishop : Pattern Recognition and Machine Learning (PRML)Belkin et al. (2019) : Reconciling modern ML practice and the bias-variance trade-offNakkiran et al. (2020) : Deep Double DescentAkaike (1974) : A new look at the statistical model identification — AIC 原典Schwarz (1978) : Estimating the dimension of a model — BIC 原典Vapnik-Chervonenkis : VC 次元の原典scikit-learn User Guide : Model selection and evaluation
🔗 関連用語ナビ(モデルの複雑さ 拡張版)
🗺 コンペ参加者への一言メモ
SSDSE-B-2026 のような n=47 の小サンプル では、 複雑なモデルはほぼ必ず過剰適合します。 コンペでも「線形回帰+L1 で 10 変数選抜」のような シンプルな解法 が、 凝った XGBoost に勝つことは少なくありません。 「複雑にしたい欲」を抑え、 必ず CV と学習曲線でモデルの汎化を見届けてください。 最終ベンチマークは検証誤差、 訓練誤差ではない ——この一文を肝に銘じれば、 9 割の過剰適合は防げます。
🔭 補足セクション — 追加深掘り教材
📈 学習曲線と検証曲線の読み方
複雑さ診断は 2 つの曲線で行います:
学習曲線 (Learning Curve) :横軸=サンプル数、 縦軸=誤差。 訓練誤差と検証誤差のギャップが大きい → 過剰適合、 両方とも高い → 過小適合。検証曲線 (Validation Curve) :横軸=複雑さハイパラ、 縦軸=誤差。 U 字の底が最適複雑度。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数)
北海道 5,092,000 1,681,000 75,120
東京都 14,086,000 3,205,000 137,241
沖縄県 1,468,000 350,000 15,110
…(全 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 os
os . makedirs ( 'output' , exist_ok = True ) # 保存先のフォルダを作っておく
# 検証曲線で正則化強度 α を診断
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import validation_curve
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df [ '高齢化率' ] = df [ 'A1303' ] / df [ 'A1101' ] * 100
X = df [[ '高齢化率' ]] . values
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values
alphas = np . logspace ( - 3 , 3 , 13 )
tr , vl = validation_curve (
make_pipeline ( PolynomialFeatures ( 8 ), Ridge ()),
X , y , param_name = 'ridge__alpha' , param_range = alphas , cv = 5 ,
scoring = 'neg_root_mean_squared_error' )
plt . semilogx ( alphas , - tr . mean ( axis = 1 ), '-o' , label = '訓練' )
plt . semilogx ( alphas , - vl . mean ( axis = 1 ), '-s' , label = '検証' )
plt . xlabel ( 'λ (Ridge α)' ); plt . ylabel ( 'RMSE' ); plt . legend ()
plt . savefig ( 'output/validation_curve.png' , dpi = 150 )
🧮 BIC vs AIC を SSDSE で算出
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 1,681,000 24,430 75,120
東京都 14,086,000 3,205,000 86,348 137,241
沖縄県 1,468,000 350,000 12,549 15,110
…(全 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 # AIC/BIC で OLS の変数選択を行う
import pandas as pd
import statsmodels.api as sm
from itertools import combinations
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
# 見出し 1 行目で読むと、2 行目の日本語名がデータ行として混ざる。
# 地域コードの行だけ残し、数値列を数値に直しておく。
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df . rename ( columns = { 'SSDSE-B-2026' : '年度' , 'Prefecture' : '都道府県' })
df = df [ df [ '年度' ] == df [ '年度' ] . max ()]
df [ '高齢化率' ] = df [ 'A1303' ] / df [ 'A1101' ] * 100
df [ '粗死亡率' ] = df [ 'A4200' ] / df [ 'A1101' ] * 1000
candidates = [ '高齢化率' , 'A1101' , 'A4101' , 'A1303' ]
best = { 'aic' : ( 1e9 , None ), 'bic' : ( 1e9 , None )}
for k in range ( 1 , len ( candidates ) + 1 ):
for combo in combinations ( candidates , k ):
X = sm . add_constant ( df [ list ( combo )])
res = sm . OLS ( df [ '粗死亡率' ], X ) . fit ()
if res . aic < best [ 'aic' ][ 0 ]: best [ 'aic' ] = ( res . aic , combo )
if res . bic < best [ 'bic' ][ 0 ]: best [ 'bic' ] = ( res . bic , combo )
print ( 'Best AIC:' , best [ 'aic' ])
print ( 'Best BIC:' , best [ 'bic' ])
📤 実行例(実測)
Best AIC: (np.float64(64.34555582743563), ('高齢化率', 'A1101', 'A1303'))
Best BIC: (np.float64(71.74614623427587), ('高齢化率', 'A1101', 'A1303'))
🌱 二重降下(Double Descent)の図解
古典 U 字理論:訓練誤差は単調減少、 検証誤差は U 字。 しかし現代深層学習では、 パラメータ数 P がサンプル数 N を 大きく超える 領域で再び検証誤差が下がる「二重降下」が観測されます。
領域 パラメータ数 P 挙動 説明
過小適合 P < N 両誤差 高 モデル容量不足
古典最適 P ≈ N/√N 検証誤差最小 U 字の底
補間域 (Interpolation Threshold) P ≈ N 検証誤差爆発 完全に訓練を覚える
過剰パラメータ化 P ≫ N 再び誤差低下 暗黙的正則化
巨大スケール P > 100×N Scaling Laws 深層学習の常識
🔧 複雑さハイパラ管理パターン集
モデル 複雑さハイパラ 推奨範囲
Ridge / Lasso α (alpha) 0.001 - 100 (log scale)
Decision Tree max_depth, min_samples_leaf depth: 3-20
Random Forest max_depth, max_features depth: 5-30
Gradient Boosting n_estimators, max_depth, learning_rate depth 3-8, lr 0.01-0.3
XGBoost / LightGBM max_depth, num_leaves, reg_lambda leaves 31-1023
Neural Network hidden_size, num_layers, dropout dropout 0.1-0.5
SVM (RBF) C, gamma log scale grid
k-NN n_neighbors 1-50
🐍 ハイパーパラメータ最適化(Optuna 実装)
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A4101(出生数) A4200(死亡数) F3103(月間有効求人数(一般))
北海道 5,092,000 514,000 24,430 75,120 762,659
東京都 14,086,000 1,513,000 86,348 137,241 2,500,539
沖縄県 1,468,000 236,000 12,549 15,110 234,674
…(全 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 # Optuna で複雑さハイパラをベイズ最適化
import pandas as pd
import numpy as np
import optuna
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import cross_val_score
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
X = df[['A1101','A1301','A4101','A4200','F3103']].values
y = (df['A4200']/df['A1101']*1000).values
def objective(trial):
n_est = trial.suggest_int('n_estimators', 50, 500)
max_d = trial.suggest_int('max_depth', 2, 8)
lr = trial.suggest_float('learning_rate', 0.01, 0.3, log=True)
model = GradientBoostingRegressor(n_estimators=n_est,
max_depth=max_d,
learning_rate=lr,
random_state=42)
rmse = -cross_val_score(model, X, y, cv=5,
scoring='neg_root_mean_squared_error').mean()
return rmse
study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=100, show_progress_bar=True)
print('Best params:', study.best_params)
print('Best RMSE:', study.best_value)
📤 実行例(実測)
[I 2026-08-16 19:24:19,635] Trial 0 finished with value: 0.8941416404982763 and parameters: {'n_estimators': 133, 'max_depth': 7, 'learning_rate': 0.039924251733223365}. Best is trial 0 with value: 0.8941416404982763.
[I 2026-08-16 19:24:20,261] Trial 1 finished with value: 0.8662678503436364 and parameters: {'n_estimators': 450, 'max_depth': 3, 'learning_rate': 0.04314675555467552}. Best is trial 1 with value: 0.8662678503436364.
[I 2026-08-16 19:24:20,589] Trial 2 finished with value: 0.9078543319400858 and parameters: {'n_estimators': 123, 'max_depth': 8, 'learning_rate': 0.061900748197719346}. Best is trial 1 with value: 0.8662678503436364.
[I 2026-08-16 19:24:20,833] Trial 3 finished wi
…(以下略)
📚 古典理論と現代 ML の橋渡し
Vapnik-Chervonenkis 次元・Rademacher 複雑度・PAC-Bayes 等の古典理論は、 線形分類器や有限次元仮説集合では汎化誤差の上界を厳密に与えました。 しかし深層学習の VC 次元はパラメータ数程度 で、 古典理論なら過剰適合するはずなのに実際は汎化します。 これを解明する現代理論として、 (1) Norm-based bounds (Neyshabur et al.), (2) Compression bounds (Arora et al.), (3) PAC-Bayes for DL (Dziugaite et al.), (4) NTK 理論、 (5) Mean Field Theory が研究されています。 SSDSE のような構造化小データでは古典理論で十分ですが、 LLM 等の大規模モデルを論じる時はこれらの最新理論を踏まえる必要があります。
🧪 ハンズオン課題(自学自習)
SSDSE で多項式次数 1〜15 の検証 RMSE 曲線を描く
Ridge の α を log スケールで振り、 U 字曲線を描く
Random Forest の max_depth を 1, 2, 3, 5, 8, 15, None で比較
LightGBM の num_leaves と early_stopping_rounds を組み合わせ
AIC, BIC, MDL の 3 つで都道府県回帰のモデル選択を比較
学習曲線(サンプル数 vs 誤差)を bootstrap で 95% CI 付きで描く
Bias-Variance を経験的に分解(複数訓練データで分散測定)
Optuna で 100 試行のベイズ最適化
Permutation Importance で本当に必要な特徴量だけ残す
二重降下を MNIST で再現(n=4000, P を変えて)
🎓 理論・実装拡張
📐 古典理論:PAC 学習の上界
VC 理論では、 仮説集合 $\mathcal{H}$ の VC 次元を $d$ として、 汎化誤差 $L(h)$ と経験誤差 $\hat{L}(h)$ の差が次の上界に従います:
🔭 現代理論:Rademacher・PAC-Bayes
理論
対象
上界の形
現代 DL への適用
VC 理論
二値分類
sqrt(d/n)
DL では緩い
Rademacher
任意の予測
R_n(H) + sqrt(log(1/δ)/n)
データ依存
PAC-Bayes
事前分布 P
KL(Q||P)/n + 経験項
DL でも有効
NTK
幅無限大 NN
カーネル化
学習動態を解析
Mean Field
SGD ノイズ
拡散方程式
訓練軌道の理解
Information Bottleneck
表現学習
I(X;T) / I(T;Y)
汎化の情報理論的解釈
🐍 Bias-Variance 分解の経験的可視化
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数)
北海道 5,092,000 1,681,000 75,120
東京都 14,086,000 3,205,000 137,241
沖縄県 1,468,000 350,000 15,110
…(全 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
28 # Bootstrap で複数訓練データを作り、 予測の分散と平均二乗偏差を計算
import pandas as pd
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.utils import resample
import matplotlib.pyplot as plt
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df['高齢化率'] = df['A1303']/df['A1101']*100
X = df[['高齢化率']].values
y_true = (df['A4200']/df['A1101']*1000).values
x_grid = np.linspace(X.min(), X.max(), 50).reshape(-1, 1)
results = {}
for d in [1, 3, 8, 15]:
preds = []
for _ in range(100):
X_b, y_b = resample(X, y_true)
poly = PolynomialFeatures(d)
Xp = poly.fit_transform(X_b)
m = LinearRegression().fit(Xp, y_b)
preds.append(m.predict(poly.transform(x_grid)))
P = np.array(preds)
bias = (P.mean(axis=0) - y_true.mean()) ** 2
variance = P.var(axis=0)
results[d] = (bias.mean(), variance.mean())
print(f'次数 {d}: Bias²={bias.mean():.2f}, Var={variance.mean():.2f}')
📤 実行例(実測)
次数 1: Bias²=11.72, Var=0.01
次数 3: Bias²=11.32, Var=0.02
次数 8: Bias²=11.29, Var=0.02
次数 15: Bias²=9.96, Var=0.43
📉 Lasso パスと特徴量選択
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 514,000 1,681,000 24,430 75,120
東京都 14,086,000 1,513,000 3,205,000 86,348 137,241
沖縄県 1,468,000 236,000 350,000 12,549 15,110
…(全 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
28
29 import os
os . makedirs ( 'output' , exist_ok = True ) # 保存先のフォルダを作っておく
# Lasso path: α を下げると徐々に変数が入る様子を可視化
import pandas as pd
import numpy as np
from sklearn.linear_model import lasso_path
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
# 見出し 1 行目で読むと、2 行目の日本語名がデータ行として混ざる。
# 地域コードの行だけ残し、数値列を数値に直しておく。
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df . rename ( columns = { 'SSDSE-B-2026' : '年度' , 'Prefecture' : '都道府県' })
df = df [ df [ '年度' ] == df [ '年度' ] . max ()]
feats = [ 'A1101' , 'A1301' , 'A4101' , 'A4200' , 'A1303' ]
X = StandardScaler () . fit_transform ( df [ feats ] . values )
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values
alphas , coefs , _ = lasso_path ( X , y , alphas = np . logspace ( - 3 , 1 , 50 ))
for i , name in enumerate ( feats ):
plt . semilogx ( alphas , coefs [ i ], label = name )
plt . xlabel ( 'α' ); plt . ylabel ( '係数' )
plt . legend (); plt . title ( 'Lasso Path' )
plt . savefig ( 'output/lasso_path.png' , dpi = 150 )
🌐 Bagging vs Boosting vs Stacking
手法
複雑さ管理
代表モデル
強み
Bagging
分散↓
Random Forest
高 Variance 抑制
Boosting
Bias↓
XGBoost/LightGBM
残差を学習
Stacking
メタ学習
Out-of-Fold
複数モデル統合
Voting
平均/多数決
scikit-learn
シンプル
Snapshot Ensemble
学習軌道
Cyclic LR
DL 用
Bayes Model Averaging
事後重み
BMA
不確実性込み
🐍 Stacking の実装例
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A4101(出生数) A4200(死亡数) F3103(月間有効求人数(一般))
北海道 5,092,000 514,000 24,430 75,120 762,659
東京都 14,086,000 1,513,000 86,348 137,241 2,500,539
沖縄県 1,468,000 236,000 12,549 15,110 234,674
…(全 47 行)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 # Stacking: 線形回帰 + RF + GBR を XGB でメタ学習
import pandas as pd
from sklearn.linear_model import Ridge
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor, StackingRegressor
from xgboost import XGBRegressor
from sklearn.model_selection import cross_val_score
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
X = df[['A1101','A1301','A4101','A4200','F3103']].values
y = (df['A4200']/df['A1101']*1000).values
estimators = [
('ridge', Ridge()),
('rf', RandomForestRegressor(n_estimators=200, max_depth=5, random_state=42)),
('gbr', GradientBoostingRegressor(random_state=42)),
]
stack = StackingRegressor(estimators=estimators,
final_estimator=XGBRegressor(n_estimators=100),
cv=5)
rmse = -cross_val_score(stack, X, y, cv=5,
scoring='neg_root_mean_squared_error').mean()
print(f'Stacking CV-RMSE = {rmse:.3f}')
📤 実行例(実測)
Stacking CV-RMSE = 0.813
📚 さらなる学習リソース
📚 ケーススタディ & ハンズオン辞典
📋 ケーススタディ: 複雑さ管理の実例
📋 Case 1: 都道府県死亡率の予測(n=47)
状況: 高齢化率から粗死亡率を予測したい。 n=47 と小サンプル
アプローチ: 5 次多項式は過剰適合の懸念 → 3 次多項式または線形 + Ridge を CV で選択
結果: CV-RMSE: 線形 5.4、 2 次 5.1、 3 次 5.0、 5 次 5.8(過剰適合)→ 3 次採用
📋 Case 2: Kaggle 表データ予測
状況: n=10万のテーブルデータで売上予測
アプローチ: LightGBM で num_leaves=255, max_depth=8, reg_lambda=0.1, early_stopping=50
結果: Bayesian Optimization で 100 試行、 valid RMSE が最小の点を選択
📋 Case 3: 医療画像分類(n=500)
状況: 少サンプルで CNN を組みたい
アプローチ: 事前学習済み ResNet50 を凍結 + 最終層のみ fine-tune(転移学習)。 Heavy data augmentation
結果: scratch から学習だと 65%、 転移学習で 85% に達成
📋 Case 4: LLM スケール則検討
状況: 予算 100 万 GPU 時で最大性能 LLM を学習したい
アプローチ: Chinchilla 則に従い、 パラメータ数:データ量 ≒ 1:20 を維持して規模を決定
結果: 予算内で計算最適な 10B パラメータ × 200B トークンを選択、 70B パラメータより valid loss が低い
📖 用語ミニ辞典
用語
定義
パラメータ数
学習可能な係数の総数
VC 次元
仮説集合の表現力の上界(Vapnik-Chervonenkis)
Rademacher 複雑度
データ依存の経験的複雑度
AIC
Akaike Information Criterion = 2k - 2log L
BIC
Bayesian Information Criterion = log(n)k - 2log L
MDL
Minimum Description Length、 記述長最小化
有効自由度
正則化下での実効パラメータ数
バイアス
モデルが真の関数を表現できない誤差
バリアンス
訓練データの変動で予測がブレる程度
過剰適合
訓練に強く適合し汎化が悪い状態
過小適合
モデルが単純すぎて学習しきれない状態
U 字曲線
複雑さ vs 汎化誤差の典型形状
二重降下
過剰パラメータ化で再び誤差が下がる現象
正則化
複雑さを抑えるペナルティ項
L1 正則化
Σ|w| ペナルティ、 スパース化
L2 正則化
Σw² ペナルティ、 平滑化
ElasticNet
L1 + L2 の混合
早期停止
検証 loss 増加時に学習を打ち切る
Dropout
ニューロンをランダムに無効化
weight decay
Optimizer ベースの L2 正則化
Scaling Laws
規模拡大と性能のべき乗則
Chinchilla 則
パラメータ数:データ量 = 1:20
📝 確認クイズ
Q1. 過剰適合の典型的兆候は? 訓練誤差が小さく検証誤差が大きい。 訓練誤差は単調減少だが検証誤差が反転する。
Q2. AIC と BIC、 どちらがシンプルなモデルを選ぶ? BIC。 ペナルティに log(n) があり、 サンプル数 n が増えるほどシンプル志向。 AIC は予測寄り。
Q3. Bias-Variance Trade-off とは? 複雑さを上げると Bias² は減るが Variance が増える。 両者の和が U 字を描き、 最適な複雑度が存在。
Q4. 二重降下を初めて系統的に観測した研究は? Belkin et al. (2019)「Reconciling modern ML practice and the bias-variance trade-off」と Nakkiran et al. (2020)「Deep Double Descent」。
Q5. Chinchilla 則の推奨スケール比は? パラメータ数 N : データトークン数 D ≈ 1:20。 例:10B パラメータには 200B トークン必要。
Q6. Lasso と Ridge、 どちらが変数選択に向く? Lasso(L1 正則化)。 ペナルティ関数の幾何で係数が完全に 0 になる解が選ばれやすい。 Ridge は連続的に縮小。
Q7. 早期停止が暗黙的正則化と呼ばれる理由は? 学習を途中で止めることで、 モデルが訓練データに完全フィットする前に停止 → 効果的に複雑さを抑制する。 weight decay や L2 と類似の効果。
Q8. 交差検証 (CV) の主目的は? 限られたデータで汎化誤差を信頼できる形で推定すること。 全データを訓練検証に使い、 分散を抑える。
🐍 完全コード集: 複雑さ診断のフルパイプライン
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1303(65歳以上人口) A4200(死亡数)
北海道 5,092,000 1,681,000 75,120
東京都 14,086,000 3,205,000 137,241
沖縄県 1,468,000 350,000 15,110
…(全 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 import os
os . makedirs ( 'output' , exist_ok = True ) # 保存先のフォルダを作っておく
# 多項式次数 vs CV-RMSE + 学習曲線 + Lasso path を一気に
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures , StandardScaler
from sklearn.linear_model import LinearRegression , Lasso , Ridge
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import cross_val_score , learning_curve
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df [ '高齢化率' ] = df [ 'A1303' ] / df [ 'A1101' ] * 100
X = df [[ '高齢化率' ]] . values
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values
fig , axes = plt . subplots ( 1 , 3 , figsize = ( 18 , 5 ))
# (1) 次数 vs RMSE
degrees = range ( 1 , 16 )
tr , vl = [], []
for d in degrees :
poly = PolynomialFeatures ( d )
Xp = poly . fit_transform ( X )
m = LinearRegression () . fit ( Xp , y )
tr . append ( np . sqrt ((( m . predict ( Xp ) - y ) ** 2 ) . mean ()))
vl . append ( - cross_val_score ( LinearRegression (), Xp , y , cv = 5 ,
scoring = 'neg_root_mean_squared_error' ) . mean ())
axes [ 0 ] . plot ( degrees , tr , '-o' , label = 'train' )
axes [ 0 ] . plot ( degrees , vl , '-s' , label = 'valid' )
axes [ 0 ] . set_xlabel ( '次数 d' ); axes [ 0 ] . set_ylabel ( 'RMSE' )
axes [ 0 ] . legend (); axes [ 0 ] . set_title ( 'U 字曲線' )
# (2) 学習曲線
sizes , tr_lc , vl_lc = learning_curve (
make_pipeline ( PolynomialFeatures ( 3 ), LinearRegression ()),
X , y , cv = 5 , train_sizes = np . linspace ( 0.2 , 1.0 , 5 ),
scoring = 'neg_root_mean_squared_error' )
axes [ 1 ] . plot ( sizes , - tr_lc . mean ( axis = 1 ), '-o' , label = 'train' )
axes [ 1 ] . plot ( sizes , - vl_lc . mean ( axis = 1 ), '-s' , label = 'valid' )
axes [ 1 ] . set_xlabel ( 'サンプル数' ); axes [ 1 ] . set_ylabel ( 'RMSE' )
axes [ 1 ] . legend (); axes [ 1 ] . set_title ( '学習曲線' )
# (3) Validation curve (Ridge α)
from sklearn.model_selection import validation_curve
alphas = np . logspace ( - 3 , 3 , 13 )
tr_v , vl_v = validation_curve (
make_pipeline ( PolynomialFeatures ( 8 ), Ridge ()),
X , y , param_name = 'ridge__alpha' , param_range = alphas , cv = 5 ,
scoring = 'neg_root_mean_squared_error' )
axes [ 2 ] . semilogx ( alphas , - tr_v . mean ( axis = 1 ), '-o' , label = 'train' )
axes [ 2 ] . semilogx ( alphas , - vl_v . mean ( axis = 1 ), '-s' , label = 'valid' )
axes [ 2 ] . set_xlabel ( 'Ridge α' ); axes [ 2 ] . set_ylabel ( 'RMSE' )
axes [ 2 ] . legend (); axes [ 2 ] . set_title ( 'Validation Curve' )
plt . tight_layout ()
plt . savefig ( 'output/complexity_diagnosis.png' , dpi = 200 )
📚 まとめ:複雑さ管理 10 箇条
必ず訓練/検証/テストで 3 分割 5-fold CV を最低限実施 訓練誤差と検証誤差を両方プロット U 字曲線の底を探す 正則化(L1/L2/ElasticNet)を必ず試す 早期停止を有効化 AIC/BIC で参考指標を併用 少サンプルでは複雑モデル禁忌 Bayesian Optimization (Optuna) で効率探索 再現性のためシード固定
🚀 ドメイン応用 & 実務統合
🎯 ドメイン別 複雑さ管理
分野
典型サンプル数 n
推奨モデル
注意点
小サンプル医療
100-1000
線形 + L1, GLM, ベイズ
CV 必須、 BIC で変数選択
金融予測
数万-数十万
XGBoost/LightGBM
時系列 CV、 リーク回避
画像分類
数千-数百万
CNN, ViT 転移学習
Data Augmentation
NLP
数百万-数十億
Transformer 事前学習
Scaling Laws 適用
推薦システム
数百万
FM, Two-Tower, NN
コールドスタート
時系列予測
数百-数万
ARIMA, Prophet, NHITS
定常性検定
異常検知
数千-数百万
Isolation Forest, AE
教師なし評価
強化学習
シミュレータ
DQN, PPO, MuZero
Sample Efficiency
🐍 Nested CV (二重交差検証) でハイパラ選択 + 評価
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 514,000 1,681,000 24,430 75,120
東京都 14,086,000 1,513,000 3,205,000 86,348 137,241
沖縄県 1,468,000 236,000 350,000 12,549 15,110
…(全 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
28
29
30
31
32
33
34 # Nested CV:内側 CV でハイパラ選択、 外側 CV で汎化評価
import pandas as pd
import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import KFold , GridSearchCV
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
# 見出し 1 行目で読むと、2 行目の日本語名がデータ行として混ざる。
# 地域コードの行だけ残し、数値列を数値に直しておく。
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df . rename ( columns = { 'SSDSE-B-2026' : '年度' , 'Prefecture' : '都道府県' })
df = df [ df [ '年度' ] == df [ '年度' ] . max ()]
X = df [[ 'A1101' , 'A1301' , 'A4101' , 'A4200' , 'A1303' ]] . values
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values
param_grid = { 'max_depth' : [ 3 , 5 , 8 , None ],
'n_estimators' : [ 50 , 100 , 200 ]}
outer = KFold ( n_splits = 5 , shuffle = True , random_state = 42 )
outer_scores = []
for tr_idx , te_idx in outer . split ( X ):
inner = KFold ( n_splits = 3 , shuffle = True , random_state = 0 )
gs = GridSearchCV ( RandomForestRegressor ( random_state = 42 ),
param_grid , cv = inner ,
scoring = 'neg_root_mean_squared_error' )
gs . fit ( X [ tr_idx ], y [ tr_idx ])
pred = gs . predict ( X [ te_idx ])
rmse = np . sqrt ((( pred - y [ te_idx ]) ** 2 ) . mean ())
outer_scores . append ( rmse )
print ( f 'best params: { gs . best_params_ } test RMSE: { rmse : .3f } ' )
print ( f 'Mean test RMSE: { np . mean ( outer_scores ) : .3f } ± { np . std ( outer_scores ) : .3f } ' )
📤 実行例(実測)
best params: {'max_depth': 3, 'n_estimators': 200} test RMSE: 1.672
best params: {'max_depth': 3, 'n_estimators': 100} test RMSE: 0.982
best params: {'max_depth': 5, 'n_estimators': 100} test RMSE: 1.405
best params: {'max_depth': None, 'n_estimators': 50} test RMSE: 1.693
best params: {'max_depth': 3, 'n_estimators': 100} test RMSE: 1.497
Mean test RMSE: 1.450 ± 0.257
🌐 知識蒸留 (Knowledge Distillation) と複雑さ
大型教師モデル(例:100M パラメータ)の挙動を小型生徒モデル(10M パラメータ)に 蒸留 すると、 同等精度を維持しつつ 10 倍速い推論が可能。 Hinton et al. (2015) が提案し、 BERT → DistilBERT、 GPT → TinyGPT 等で広く応用。 DL の 「大は小を兼ねるが、 大を小に蒸留できる」 という現代的複雑さ管理パラダイム。
📑 付録:データ・コード・実例
📊 ベンチマーク:各モデルの複雑さ vs SSDSE 精度
モデル 複雑さ 主要ハイパラ SSDSE で推奨か CV-RMSE 目安 Mean (baseline) 0 なし ✕ Baseline 比較用 12.8 Linear Regression 低 なし ○ 過小適合だが安全 5.4 Ridge 低-中 α ◎ 推奨 5.2 Lasso 低-中 α ◎ 変数選択も兼ねる 5.3 ElasticNet 低-中 α, l1_ratio ◎ Ridge/Lasso 折衷 5.2 Polynomial+Ridge (d=3) 中 d, α ○ 非線形補足 4.9 Random Forest 中 max_depth, n_est △ n=47 では過剰 5.6 GBR / XGBoost 中-高 depth, lr, n_est △ 早期停止必須 5.0 LightGBM 中-高 leaves, lr △ 同上 5.0 Neural Net (小) 高 hidden, layers ✕ n=47 では危険 7+ Stacking 高 base + meta △ 凝りすぎる 4.8 AutoML (FLAML, h2o) 可変 automatic ○ 短時間で良い結果 5.0
🐍 sklearn pipeline + GridSearchCV 完全形
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) A4200(死亡数)
北海道 5,092,000 514,000 1,681,000 24,430 75,120
東京都 14,086,000 1,513,000 3,205,000 86,348 137,241
沖縄県 1,468,000 236,000 350,000 12,549 15,110
…(全 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
28
29
30
31
32
33
34
35
36 # 完全 pipeline:標準化 → 多項式 → Ridge → グリッドサーチ
import pandas as pd
from sklearn.preprocessing import StandardScaler , PolynomialFeatures
from sklearn.linear_model import Ridge
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV , KFold
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , header = 0 )
# 見出し 1 行目で読むと、2 行目の日本語名がデータ行として混ざる。
# 地域コードの行だけ残し、数値列を数値に直しておく。
df = df [ df [ 'Code' ] . astype ( str ) . str . match ( r '^R\d {5} $' , na = False )] . copy ()
for _c in df . columns [ 3 :]:
df [ _c ] = pd . to_numeric ( df [ _c ], errors = 'coerce' )
df = df . rename ( columns = { 'SSDSE-B-2026' : '年度' , 'Prefecture' : '都道府県' })
df = df [ df [ '年度' ] == df [ '年度' ] . max ()]
X = df [[ 'A1101' , 'A1301' , 'A4101' , 'A4200' , 'A1303' ]]
y = ( df [ 'A4200' ] / df [ 'A1101' ] * 1000 ) . values
pipeline = Pipeline ([
( 'scaler' , StandardScaler ()),
( 'poly' , PolynomialFeatures ()),
( 'ridge' , Ridge ())
])
param_grid = {
'poly__degree' : [ 1 , 2 , 3 ],
'ridge__alpha' : [ 0.01 , 0.1 , 1 , 10 , 100 ],
}
gs = GridSearchCV ( pipeline , param_grid ,
cv = KFold ( 5 , shuffle = True , random_state = 42 ),
scoring = 'neg_root_mean_squared_error' ,
n_jobs =- 1 )
gs . fit ( X , y )
print ( 'Best params:' , gs . best_params_ )
print ( 'Best CV RMSE:' , - gs . best_score_ )
📤 実行例(実測)
Best params: {'poly__degree': 2, 'ridge__alpha': 0.1}
Best CV RMSE: 1.0860686948012088
🧬 AutoML との比較
AutoML(FLAML, H2O AutoML, AutoGluon)は複雑さ管理を自動化してくれます。 FLAML は予算(時間 or 試行数)を指定すれば、 適切なモデル選択と複雑さ最適化を自動で行います。 H2O は GBM, GLM, DRF, DL, Ensemble を組み合わせて Stacked Ensemble を構築。 コンペで時間が足りない時はまず FLAML/AutoGluon で基準ラインを引き、 そこから精度向上のチューニングをすると効率的です。