この用語と一緒に検索・参照されやすいタグ。 関連ページに飛ぶときの手がかりにも使えます。
「bias variance」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「bias variance」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「bias variance の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
予測のズレを分ける考え方です。
正解に近づくために使います。
テストの勉強量と点数の関係に似ています。
結論を短くまとめて説明します。
予測モデルの誤差を バイアス(偏り)+バリアンス(ばらつき)+ノイズに分解する考え方。 過学習・未学習を統一的に説明。
ここまでが要点です。 ただし実際に使う前に、 このページの「⚠️ よくある落とし穴」で挙げた 訓練 MSE で判断する/バリアンス削減 = 正則化と思い込む/バイアスとモデル誤差を混同 には必ず目を通してください。 つまずくのは知識が無いときより、 知ってはいたが確認を飛ばしたときです。
🍰 まずはやさしく
モデル選びのヒントになる道具です。
一番いい予測方法を決めるために使います。
スマホのアプリで最適な設定を探すときと同じです。
どんな場面で使うのかを解説します。
回帰・分類のモデル選択で、 「もっと複雑なモデルを使えば精度が上がる」と短絡的に考えがちですが、 汎化性能(未知データへの性能)は逆 U 字を描きます。 本サイトの重回帰や決定木の章で繰り返し登場する基本概念。
この用語は一見すると単独で理解できそうに見えますが、 実際には前提となる概念(測定・尺度・サンプリングなど)と組合せて初めて意味を持ちます。 「定義を覚える」より「どんな問いに答える道具なのか」を捉えるのが効率的です。
🍰 まずはやさしく
的当てのようなイメージです。
誤差の原因を直感的に理解するために使います。
部活の練習で、狙いと散らばりを考えるときと同じです。
図や例を使って仕組みを説明します。
バイアスとバリアンスはモデルの誤差を分解する 2 成分です。 SSDSE-B-2026 の「総人口(A1101)→ ごみ総排出量(H5609)」を予測する場面なら、 単純な定数モデルはバイアスが高くバリアンスが低い(どの県でも同じ平均を出す)、 47 次多項式はバイアスが低くバリアンスが高い(県を 1 件差し替えるだけで予測が大きく揺れる)。 この両者の和を最小化するのが汎化です。
概念は「読む」より「動かす」ほうが速く身につきます。 下のスライダーで モデル複雑度(多項式次数) と ノイズ量 を変えると、 3 つの図がリアルタイムで連動します。 このシミュレーションは 既知の真の関数 f(x) から毎回ランダムにデータを作り直し、 そのたびにモデルを訓練する モンテカルロ法で Bias²・Variance・総誤差を実際に計算しています(数値のからくりは本ページの実測「深掘り 1〜5」と同じ原理)。
複雑度を上げると Bias² は下がり Variance は上がる。 その和(+既約ノイズ σ²)である 総誤差 は必ず U 字 を描き、 谷の底が最適複雑度。 緑の破線=最適、 オレンジの縦線=いま選んでいる複雑度。
黒い太線が真の関数 f(x)、 点は 1 つの訓練標本。 薄い線は データを引き直すたびに得られる予測曲線。 単純なモデル=線がまとまるが真の関数から系統的にズレる(高バイアス)/複雑なモデル=線がバラバラに暴れる(高バリアンス) を目で確認できます。
列=バリアンス(左:小/右:大)、 行=バイアス(上:小/下:大)。 中央の的が真値。 いまの複雑度が該当する象限が 光って 表示され、 複雑度を動かすと点の「散らばり」と「中心ズレ」が連動して象限を移動します。
上のシミュレーションで見た挙動を、 概念として整理します。 各項目は本サイトの関連ページへの入口でもあります。
モデルを複雑にするほど、 手元のデータには良く当てはまりますが、 データの偶然の揺らぎまで学習してしまいます。 これが「複雑さを上げると Bias↓・Variance↑」の正体です。 逆に単純すぎると、 真の関係を表現しきれず、 どんなデータでも同じように外します。 最適点は両者の和が最小になる中間 にあり、 それは①の総誤差カーブの谷として現れます。
期待二乗誤差は $\mathbb{E}[(y-\hat f)^2] = \text{Bias}^2 + \text{Var} + \sigma^2$ と 3 つの非負成分の和に分解できます。 この分解のご利益は、 誤差の「原因」を特定して対策を選べる ことです。 高バイアス(未学習)なら複雑度を上げる・特徴量を足す、 高バリアンス(過学習)なら正則化・データ追加・平均化、 σ² が大きいなら測定設計そのものを見直す ── と打ち手が一意に決まります。 詳しい実務判定は本ページ「深掘り 2:学習曲線」を参照。
モデル複雑度は、 バイアスとバリアンスを同時に反対方向へ動かす「ダイヤル」です。 複雑度が低すぎる領域=未学習(高バイアス)、 高すぎる領域=過学習(高バリアンス)。 バイアス・バリアンス分解は、 この 2 つの失敗モードを 同じ 1 枚の U 字カーブ上の左右 として統一的に説明する枠組みです。
正則化(Ridge / Lasso / ElasticNet)は、 係数を 0 方向へ縛ることで 実効的な複雑度を下げ、 バリアンスを抑える 手段です。 「少しバイアスを足す代わりに、 大きくバリアンスを削る」という明確なトレードオフを持ち、 罰則の強さ α が①の U 字上の動作点を左へずらすツマミに相当します。 実測は本ページ「深掘り 3:Ridge / Lasso」を参照。
アンサンブルは、 単一モデルのトレードオフを部分的に 回避 します。 バギング/ランダムフォレストは独立に近い予測器を平均して バリアンスを 1/N 方向へ縮め、 ブースティングは誤差に順次フィットして バイアスを削ります。 「バイアスを増やさずにバリアンスだけ下げたい」ときの主力です。 実測は本ページ「深掘り 4:アンサンブル」を参照。
このセクションは既存の「🎨 直感」「🧭 要点整理」「⚠️ 落とし穴」「🔬 深掘り 1〜5」を 壊さずに補う追記 です。 同じ結論を別の角度から言い換え、 さらに 本ページでまだ出していない実測(SSDSE-B-2026 の 2023 年度・47 都道府県、 KFold(shuffle=True, random_state=0) 固定)で「トレードオフの直感が崩れる場面」を具体的に示します。
期待二乗誤差 = バイアス² + バリアンス + ノイズ の 3 語を、 「射手が同じ的を撃ち続ける」比喩で 役割ごとに 言い直します(本文の射撃比喩を別軸で補強)。
| 成分 | 正体(一言で) | 射手の比喩 | 効く対処 |
|---|---|---|---|
| バイアス² | 何度データを引き直しても 同じ方向へ外すクセ(単純すぎ) | 照準そのものがズレている | 複雑度↑・特徴量追加(照準補正) |
| バリアンス | 偶然の揺らぎに振り回され 毎回別の答えを出す過敏さ(複雑すぎ) | 手ブレで弾がばらつく | 正則化・平均化・データ追加(ブレ抑制) |
| ノイズ σ² | どんな腕でも消せない 既約の下限 | 的そのものが風で揺れている | 測定設計の見直し(モデルでは不可) |
ポイントは 3 つが「非負の和」であること。 合計を下げたいなら いちばん大きい項を狙い撃つ のが定石で、 「照準補正(バイアス対策)」と「ブレ抑制(バリアンス対策)」は 別の道具 だと切り分けられます。 これが本ページ全体を貫く「処方箋の切り分け」の核です。
(a) U 字の谷は「必ず 1 点に定まる」わけではない。 本ページ深掘り 1 は単一分割で「d=2 が CV MSE 最小(42.25)」でしたが、 分割の引き方を変えて 100 回平均(RepeatedKFold, 5 分割 × 20 反復, random_state=0)すると、 最適複雑度の順位が入れ替わります。
💬 読み方:単一 seed では d=2(42.25)が最良でしたが、 100 通りの分割で平均すると d=1(52.41)が d=2(55.79)を下回り、 優劣が逆転します。 さらに標準偏差は平均と同オーダー(d=2 で mean 55.79 に対し std 75.78、 min 2.26〜max 458 と 200 倍の開き)。 つまり N=47 では 「谷の位置」自体が推定誤差に埋もれ、 「d=2 が最適」と 1 回の CV で断言するのは危険です。 これが「トレードオフの谷は常にきれいに 1 点へ定まる」という思い込みの落とし穴で、 対策は 複数分割の平均 ± 標準偏差で報告すること(→ 交差検証/ブートストラップ)。
(b) 正則化は「使える複雑度の上限」を右へ動かす。 トレードオフ点は固定ではなく、 正則化の強さで移動します。 無正則化と Ridge(α=1) を 同じ次数で 比較した実測(KFold, random_state=0):
💬 読み方:無正則化では d≥3 で CV MSE が爆発しますが、 Ridge(α=1) は d=5 を 4733 → 111.75、 d=6 を 595 万 → 317 と抑え、 「安全に使える複雑度の上限」を押し上げています(=トレードオフ点が右へ移動)。 ただし代償として、 有用な低次(d=2)では 42.25 → 77.88 と悪化(α=1 が過収縮でバイアスを足しすぎ)。 さらに d=4 では Ridge でも 21360 と暴れており、 N=47・東京都という単一の高レバレッジ点の下では「正則化しても最適 α や最適次数の選択が不安定」という、 本ページ深掘り 3 と同じ教訓が別角度で再現します。
(c) アンサンブルは「バリアンス低減の万能薬」ではない。 一般に バギングは独立に近い予測器の平均でバリアンスを下げますが、 効くのは「そこそこ安定した高分散学習器」に対してです。 d=5 多項式を BaggingRegressor(50 本) で平均した実測:
💬 読み方:バギングは むしろ悪化しました(4733 → 112436)。 高次多項式の暴れは データ範囲外への外挿(テスト側に回った東京都の外側)で起き、 各ブートストラップ標本でも同じ方向に発散するため、 平均しても尾が抑えられないからです。 「アンサンブル=必ずバリアンス↓」と機械的に信じるのは落とし穴で、 外挿型の高分散学習器には まず複雑度を下げる(低次化)ほうが先(→ 決定木ベースの ランダムフォレストが効く条件は本ページ深掘り 4 を参照)。
(d) バリアンスをバイアスと誤認しない。 「訓練誤差が高い=高バイアス」とは限りません。 強い正則化やデータ不足でも訓練誤差は上がります。 見分けは値の大小ではなく learning curve のギャップ(訓練 vs 検証の差)で行う(本ページ深掘り 2)。 「単に予測が外れている」ことと「関数族の選択を誤っている(=真のバイアス)」は別物です。
(e) 分解は二乗誤差“固有”。 bias² + variance + σ² という きれいな加法分解が成り立つのは二乗誤差だからです。 0-1 損失や交差エントロピーでは一般にこの形にはならず、 別定義(例: Domingos 2000 の統一分解)を要します(→ ログ損失/交差エントロピー)。 分類問題で「bias²+var+noise」をそのまま口にするのは不正確なので、 実務では learning curve とエラーレートで判定するのが安全です。
🍰 まずはやさしく
誤差を数式で表したものです。
正確に計算して分析するために使います。
買い物で予算を細かく分けるときと同じです。
数式を使って厳密な意味を説明します。
やさしい説明で掴んだ感覚を、ここで 二乗誤差の分解(回帰) の定義式に対応づけます。下の式は左辺 $\mathbb{E}[(y - \hat{f}(x))^2]$ が何で決まるかを右辺で書き下したもので、σ(標準偏差) が現れます。それぞれの記号が何の量を指すのかは、次の「🔬 数式を言葉で読み解く」で 1 つずつ確かめてください。
数式を眺めるだけでは身につかないので、 各記号がどんな役割を担っているかを言葉で押さえます。 「数式を音読する習慣」がつくと、 論文や教科書を読むスピードが体感で 2 倍ほど上がります。
バイアス・バリアンスは「机上の概念」と思われがちですが、 実データで 多項式次数 d を変えるだけ で目に見える形で観測できます。 ここでは SSDSE-B-2026 の 2023 年度(47 都道府県)から「総人口(A1101)」を入力 X、「ごみ総排出量(H5609)」を出力 y に取り、 d=1〜10 で次数を増やしながら 5-fold CV(KFold は shuffle=True, random_state=0 で固定)で MSE を測定し、 同時に bias² と variance を Monte Carlo シミュレーションで推定します。
このコードでやること:SSDSE-B-2026 を 2023 年度でフィルタして人口とごみ総排出量を取り出し、 多項式次数を d=1〜10 まで動かしながら、 訓練 MSE・テスト MSE を 5-fold CV(seed 固定)で測る。 訓練と CV の差を見ると「複雑になるほど CV が悪化する」古典的な U 字曲線が現れる。
📥 入力データ(SSDSE-B-2026 の 2023 年度抜粋、 47 都道府県):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd import numpy as np from sklearn.preprocessing import PolynomialFeatures, StandardScaler from sklearn.linear_model import LinearRegression from sklearn.pipeline import make_pipeline from sklearn.model_selection import cross_validate, KFold df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df2023 = df[df['SSDSE-B-2026'] == 2023] # 2023年度・47都道府県のみ X = df2023[['A1101']].values / 1e6 # 総人口(百万人) y = df2023['H5609'].values / 1e4 # ごみ総排出量(万トン) kf = KFold(n_splits=5, shuffle=True, random_state=0) # 再現性のため seed 固定 for d in [1, 2, 3, 5, 8, 10]: model = make_pipeline(StandardScaler(), PolynomialFeatures(d, include_bias=False), LinearRegression()) cv = cross_validate(model, X, y, cv=kf, scoring='neg_mean_squared_error', return_train_score=True) print(f'd={d:2d} train_MSE={-cv["train_score"].mean():8.2f} cv_MSE={-cv["test_score"].mean():8.2f}') |
📤 実行例(実際の出力):
💬 読み方:訓練 MSE は d を増やすほど単調減少(=モデルがデータに合わせ込んでいる)、 一方で CV MSE は d=2 の 42.25 が最小で、 d=3 で 5 倍以上に悪化、 d=8 以上では桁が壊れるほど爆発します。 これが 「高 d = 高バリアンス、 低 d = 高バイアス」 の実証です。 SSDSE-B-2026 の 1 年度分は 47 都道府県しかなく、 しかも総人口 1,400 万人の東京都という高レバレッジ点を含むため、 高次多項式はテスト側に回った東京都への外挿で破綻します(上の出力は seed 固定の実測値。 scikit-learn のバージョンによって端数は変動しえます)。
古典的なバイアス・バリアンス分解の理論式は、 「同じ true function から何度もサンプリングし、 そのたびにモデルを訓練し、 同じテスト点で予測を集める」 ことで初めて経験的に検証できます。 SSDSE-B-2026 だけでは true function が分からないので、 47 都道府県のデータに対してブートストラップ再抽出で擬似的に「複数のサンプル」を作り、 各 d でのテスト点予測のばらつきを観測します。
このコードでやること:SSDSE-B-2026 の 2023 年度 47 都道府県をブートストラップで 200 回再サンプリング、 d=1, 3, 5, 8 でそれぞれ多項式回帰を訓練し、 固定したテスト点(人口 = 2.0, 5.0, 10.0 百万人)での予測値の平均と分散から bias² と variance を計算する。 乱数は default_rng(20260524) で固定しており、 同一環境なら出力は完全に再現される(ライブラリのバージョン差で端数が変わる可能性はある)。
📥 入力データ:上のセクションと同じ X (A1101) と y (H5609)。 ブートストラップは np.random.choice(n, n, replace=True) で添字を再抽出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | rng = np.random.default_rng(20260524) # 再現性のため固定 seed n = len(X) x_test = np.array([[2.0], [5.0], [10.0]]) # 200万人, 500万人, 1000万人 のテスト点 for d in [1, 3, 5, 8]: preds = [] for _ in range(200): idx = rng.choice(n, n, replace=True) # 公的データのブートストラップ model = make_pipeline(StandardScaler(), PolynomialFeatures(d, include_bias=False), LinearRegression()) model.fit(X[idx], y[idx]) preds.append(model.predict(x_test)) preds = np.array(preds) # shape=(200, 3) mean_pred = preds.mean(axis=0) var_pred = preds.var(axis=0) # 簡易 true: 線形回帰 d=1 を「真の関数」と見立てる(教育用近似) true_y = LinearRegression().fit(X, y).predict(x_test) bias2 = (mean_pred - true_y)**2 print(f'd={d} bias²={bias2.mean():8.2f} variance={var_pred.mean():8.2f}') |
📤 実行例(200 回ブートストラップ、 seed=20260524 固定の実測値):
💬 読み方:d が増えるにつれて bias²(この実験では d=1 の全データ当てはめを「真の関数」と見立てた教育用近似)と variance が 両方 増え、 とくに variance は d=1 の 17.22 から d=5 で約 1,000 万、 d=8 では 10 兆超のオーダーまで発散します。 これは「教育的にきれいな U 字」ではなく、 47 都道府県という小サンプルでは variance が支配的 になる典型例です。 東京都がブートストラップ標本に入るかどうかだけで高次多項式の予測曲線が別物になることが、 この爆発の正体。 言い換えると、 SSDSE-B-2026 の 1 年度規模では「シンプルなモデル(d=1〜2)」が最も安全です。
| 数式の部品 | 日本語訳 | SSDSE-B-2026 でのイメージ |
|---|---|---|
| E[(y - ŷ(x))²] | 「真の値 y と予測 ŷ の差」を 2 乗して、 訓練データのランダム性で平均 | 47 都道府県をブートストラップで再抽出するたびに、 北海道予測値がどれだけブレるか |
| Bias²(ŷ) = (E[ŷ] - f(x))² | 予測の平均値が真の関数からどれくらいずれているか | d=1 の線形回帰は曲線関係を捉えきれず、 平均予測が真値からずれる量 |
| Variance(ŷ) = E[(ŷ - E[ŷ])²] | 同じ点での予測が、 訓練データを変えるたびにどれくらいブレるか | d=10 では 47 都道府県を入れ替えるだけで予測曲線が大きく変わる |
| σ² (irreducible) | どんなモデルでも消せない、 観測の本質的ノイズ | 県によって統計の取り方や定義微差から生じる ±数% のばらつき |
この 3 項目に分解できるからこそ、 「過学習対策には variance を下げる正則化」、 「未学習対策には bias を下げる特徴量追加」、 「irreducible が大きいなら、 そもそも測定設計を見直す」と 処方箋を切り分けられる のが、 バイアス・バリアンス分解の最大の効用です。
バイアス・バリアンスの実務的な使い道は、 「今このモデルは高バイアス/高バリアンスのどっち?」 を判定し、 次の打ち手を決めることです。 答えは learning curve(訓練サイズ vs エラーの関係)に明確に表れます。 high-bias なら訓練もテストも高エラーで平らに横ばい、 high-variance なら訓練エラーが低く、 テストエラーとのギャップが大きい。
このコードでやること:SSDSE-B-2026 の 2023 年度 47 都道府県を訓練サイズ 9, 18, 27, 37 と段階的に増やしながら、 シンプルモデル(d=1)と複雑モデル(d=5)の訓練 MSE と CV MSE を測り、 learning curve を直接プリントする。
📥 入力データ:上のセクションと同じ X (A1101=総人口) と y (H5609=ごみ総排出量)、 CV 分割も同じ kf(seed 固定)。 サイズ別の評価には sklearn.model_selection.learning_curve を使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from sklearn.model_selection import learning_curve for d, label in [(1, 'simple (d=1)'), (5, 'complex (d=5)')]: model = make_pipeline(StandardScaler(), PolynomialFeatures(d, include_bias=False), LinearRegression()) sizes, tr, te = learning_curve( model, X, y, train_sizes=[0.25, 0.5, 0.75, 1.0], cv=kf, scoring='neg_mean_squared_error') print(f'--- {label} ---') for n_i, t, v in zip(sizes, -tr.mean(axis=1), -te.mean(axis=1)): gap = v - t print(f' n={n_i:2d} train={t:7.1f} cv={v:7.1f} gap={gap:7.1f}') |
📤 実行例:
💬 読み方:シンプルモデルは n=18 以降 gap が 5〜15 まで狭まり、 cv は 53〜54 付近で 頭打ち になります。 これが 高バイアスのサイン =「データを増やしても改善しない、 モデル自体が不十分」。 一方、 複雑モデル(d=5)は gap が n=9 で約 1,220 万、 n=37 で約 4,600 と 桁違いに大きいが、 データを増やすと急速に縮小 しています。 これは 高バリアンスのサイン =「データを増やせばまだ伸びる」。 SSDSE-B-2026 の 1 年度 N=47 では「データを増やす」打ち手が取れないので、 結論は「d=1〜2 の単純モデルを採用しつつ、 特徴量を追加してバイアスを下げる」になります。
| 観察パターン | 診断 | 次の打ち手 |
|---|---|---|
| 訓練・CV ともエラー高、 gap 小、 N を増やしても水平 | 高バイアス(underfit) | モデル容量↑、 特徴量追加、 正則化↓、 ハイパーチューニング |
| 訓練エラー低、 CV エラー高、 gap 大、 N を増やすと縮小 | 高バリアンス(overfit) | データ追加、 正則化↑、 モデル容量↓、 dropout/augment |
| 訓練エラー低、 CV エラーも低、 gap 小 | 良好(適合済) | この設定で本番投入、 ただし新しいデータ分布で再検証 |
| 訓練エラー 0、 CV エラー非常に高、 N を増やしても gap 維持 | データリーク疑い/タスク本質的に高ノイズ | 特徴量を見直し、 ラベル定義をチェック、 irreducible noise を推定 |
バリアンスを下げる王道が 正則化 です。 SSDSE-B-2026 のように特徴量を多次特徴へ展開して d=5 にすると過学習しますが、 Ridge(L2 正則化)の α を上げると、 係数を 0 方向に引き寄せて variance を実質的に下げられます。 重要なのは、 正則化は bias を上げる代わりに variance を下げる という明確なトレードオフを持っていることです。
このコードでやること:SSDSE-B-2026 で d=5 の多項式特徴量を展開し、 Ridge の α を 1e-4〜1e3 まで変えて訓練 MSE・CV MSE・係数ノルムを観測する。 α が大きくなるにつれて、 「訓練 MSE は徐々に悪化、 CV MSE は最初下がってから上がる U 字、 係数ノルムは単調減少」という古典的な振る舞いを確認する。
📥 入力データ:これまでと同じ X (A1101=総人口), y (H5609=ごみ総排出量)。 CV 分割も同じ kf(seed 固定)。 多項式 5 次に展開すると特徴量は 5 個(標準化込み)になる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from sklearn.linear_model import Ridge for alpha in [1e-4, 1e-2, 1.0, 10.0, 100.0, 1000.0]: model = make_pipeline(StandardScaler(), PolynomialFeatures(5, include_bias=False), Ridge(alpha=alpha)) cv = cross_validate(model, X, y, cv=kf, scoring='neg_mean_squared_error', return_train_score=True) # 係数ノルム測定のため一度全体で fit model.fit(X, y) coef = model.named_steps['ridge'].coef_ print(f'alpha={alpha:8.4f} train={-cv["train_score"].mean():8.2f} cv={-cv["test_score"].mean():8.2f} |w|={np.linalg.norm(coef):7.2f}') |
📤 実行例:
💬 読み方:係数ノルム |w| は α を上げるほど 87.95 → 5.38 と 単調減少し、 「α を上げる = 係数を縛る = variance を抑える」が定量的に確認できます。 CV MSE は α=1 で 111.75 と最小になり、 ほぼ無正則化(α=0.0001)の 4716 から 約 40 分の 1 に改善します(=深掘り 1 で爆発していた d=5 の過学習を Ridge が救済)。 ただし α をさらに上げると CV MSE は単調な U 字を描かず、 α=10 で 218522 まで 暴れます。 これは N=47・単一の高レバレッジ点(東京都)という小サンプルでは、 fold ごとの東京都への外挿が CV を支配し、 最適 α の選択自体が不安定になるためです(上の出力は KFold(shuffle=True, random_state=0) 固定の実測値。 scikit-learn のバージョンで端数は変動しえます)。 実務では単一分割でなく RepeatedKFold や入れ子 CV で α を選ぶべき、 というのがこの実データからの教訓です。
Ridge は L2 ノルムで係数全体を縮めるのに対し、 Lasso は L1 ノルムで一部の係数を 厳密に 0 にします。 SSDSE-B-2026 で多項式 5 次を展開した場合、 Lasso の α を上げると「2 次・3 次の係数だけが残り、 4 次・5 次は 0 になる」といったスパース解が得られ、 結果として「実質的な多項式次数を自動で下げる」効果を持ちます。 教育的な目安として、 特徴量が多くて一部が不要だと予想される → Lasso、 全特徴量に小さい寄与がある → Ridge、 両方を混ぜたい → ElasticNet と覚えると実務でも迷いません。
| 手法 | 正則化項 | 解の性質 | 適する場面 |
|---|---|---|---|
| Ridge (L2) | α‖w‖² | 係数は全て 0 でない、 小さくなる | 特徴量間に相関があり、 すべて少しずつ寄与する場合 |
| Lasso (L1) | α‖w‖₁ | 一部の係数が厳密に 0(スパース) | 特徴量選択も同時に行いたい、 解釈性が重要 |
| ElasticNet | α(ρ‖w‖₁ + (1-ρ)‖w‖²) | L1/L2 の混合、 ρ で制御 | 相関の強い特徴量群が複数あり、 群単位でスパースにしたい |
| 早期終了 | 学習エポック数の制限 | 最適化途中で停止 → 暗黙の正則化 | 勾配ブースティング、 NN で実質コスト 0 の variance 削減 |
単一モデルではバイアスとバリアンスはトレードオフですが、 アンサンブル学習はこのトレードオフを 緩める 強力な手段です。 バギング(Bagging/Random Forest) は variance を、 ブースティング(GBM/XGBoost) は bias を、 それぞれ重点的に削減します。 SSDSE-B-2026 のような小サンプルでも、 アンサンブルは単独モデルより安定した予測を提供します。
このコードでやること:SSDSE-B-2026 で同じ X, y を使い、 単一決定木・ランダムフォレスト・勾配ブースティングの 3 つを 5-fold CV で比較。 ベースモデル(決定木 max_depth=5)と、 そのバギング、 ブースティングを並べて MSE・標準偏差を比較する。
📥 入力データ:これまでと同じ X, y。 ベース決定木 1 本 vs RandomForest(200 本のバギング)vs GradientBoosting(200 本のブースティング)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from sklearn.tree import DecisionTreeRegressor from sklearn.ensemble import (RandomForestRegressor, GradientBoostingRegressor) models = { 'Tree d=5': DecisionTreeRegressor(max_depth=5, random_state=0), 'RF (200本)': RandomForestRegressor(n_estimators=200, max_depth=5, random_state=0), 'GBM (200本)': GradientBoostingRegressor(n_estimators=200, max_depth=3, learning_rate=0.05, random_state=0), } for name, model in models.items(): cv = cross_validate(model, X, y, cv=kf, scoring='neg_mean_squared_error', return_train_score=True) tr = -cv['train_score'].mean() te = -cv['test_score'].mean() sd = cv['test_score'].std() print(f'{name:12s} train={tr:7.1f} cv={te:7.1f} cv_std={sd:7.1f}') |
📤 実行例:
💬 読み方:単独決定木(max_depth=5)は train=2.2 と低いのに CV=688.6 で過学習(high variance)。 ランダムフォレストは 200 本の平均で単独木の過学習を抑え(train は 2.2→69.2 と上がる=当てはめを緩めた証拠)、 CV も 688.6→613.5、 cv_std も 902.0→881.0 と わずかに 下がります。 ただし削減幅が小さいのは、 特徴量が「総人口」1 個しかないためです。 RF の variance 削減は「特徴量サブセット抽出で木同士の相関を下げる」ことに依るので、 特徴量が 1 個だと RF は実質ただのバギングに退化し、 しかも東京都という単一の高レバレッジ点が fold の CV を支配するため、 200 本平均しても劇的には改善しません。 GBM は train=0.2 まで下げても CV=683.8 と RF に及ばず、 3 手法は 610〜690 の同じ土俵に並びます。 この単一特徴量・N=47 の問題で効く主レバーはアンサンブルではなくモデル複雑度(木の深さ・多項式次数)であり、 アンサンブルの真価は特徴量が多い問題で初めて出る、 というのが実測からの教訓です(CV は seed 固定の kf による実測値)。
バギングの数学的本質は 「N 個の独立な予測器の平均は、 単独予測器の variance を 1/N に下げる(相関 0 の場合)」 という統計学の基礎結果です。 実際には木同士が完全独立ではないので削減幅は 1/N より小さくなりますが、 ランダムフォレストの「特徴量サブセット抽出」で木同士の相関をさらに下げる工夫が入っています。 一方ブースティングは 「前のモデルが間違えた点に重みを集中して次のモデルを訓練し、 直列に積み上げる」 仕組みで、 各ステップで bias を少しずつ削っていく構造です。 同時 bias 削減もしたければ XGBoost や LightGBM のような勾配ブースティング系、 高速で安定した variance 削減には Random Forest、 という棲み分けが実務的な経験則です。
2019 年頃から、 「モデルがパラメータ数で訓練データ数を大幅に超えると、 一度悪化したテストエラーが再び下がる」 という現象(double descent)が深層学習で広く観測され、 古典的バイアス・バリアンス曲線の単純な U 字像が再考を迫られました。 Belkin et al.(2019)の「Reconciling modern machine-learning practice and the classical bias–variance trade-off」が嚆矢で、 ResNet・Transformer などの大規模モデルがいずれもこの現象を示しています。
| レジーム | パラメータ数 | 挙動 | 代表例 |
|---|---|---|---|
| underparameterized(古典) | ≪ データ数 | 古典的 U 字、 バイアス・バリアンスのトレードオフ | 線形回帰、 浅い決定木、 小規模 SVM |
| interpolation threshold | ≈ データ数 | テストエラーが ピーク を打つ | ちょうど訓練 MSE=0 を達成する境界 |
| overparameterized(現代) | ≫ データ数 | テストエラーが 再降下、 古典理論の予測に反する | ResNet, Vision Transformer, GPT 系の事前学習 |
この現象は 「implicit regularization(暗黙の正則化)」 によって説明されつつあります。 SGD で訓練するとき、 解空間の中で「最も滑らかな解」「最小ノルムの解」が選ばれやすい性質があり、 過剰パラメータ化されたモデルはこの暗黙の正則化のおかげで variance が抑えられる、 というのが現在の有力仮説です。 ただし SSDSE-B-2026 のような表形式・小サンプル問題では古典的 U 字が依然として支配的 で、 double descent を狙ってモデルを巨大化するのは現実的ではありません。 「double descent は深層学習・大規模データ前提の現象」と理解し、 古典的 ML タスクでは依然としてバイアス・バリアンスの U 字を念頭に置くべきです。
SSDSE-B-2026(47 都道府県、 2023 年度)から「総人口 A1101 → ごみ総排出量 H5609」を多項式回帰し、 次数を動かして Bias² と Var のトレードオフを観察します。 実測の U 字曲線(多項式次数 d=2 で CV MSE 最小)は「🔬 深掘り 1」に seed 固定で掲載済みです。 下の表は分解の 模式例(値を 0〜1 に規格化した概念図。 実測値ではありません)で、 U 字の形だけを直感的に示すものです。
1〜10 次多項式で SSDSE の総人口→ごみ総排出量を回帰した想定例:
| 次数 | Bias² | Var | Total |
|---|---|---|---|
| 1 | 0.80 | 0.05 | 0.85 |
| 2 | 0.20 | 0.10 | 0.30 ← 最適 |
| 5 | 0.10 | 0.40 | 0.50 |
| 10 | 0.05 | 1.20 | 1.25 |
この模式表では Total(Bias² + Var)が次数 2 で最小になる点に注目(実測でも d=2 が CV MSE 最小で、 深掘り 1 と整合)。 1 次は Bias² 過大(単純すぎ)、 10 次は Var 爆発(複雑すぎ)。 47 都道府県は標本サイズが小さいため特にこの U 字が顕著です。 実データでの正確な値は「🔬 深掘り 1」の seed 固定・実測出力を参照してください(本表は概念図であり、 実測値そのものではありません)。
真値 f = 5 に対する 5 個の予測 [4.2, 5.8, 4.5, 5.5, 4.9] を使い、 MSE = Bias² + Variance + Noise を Step 1〜4 で展開する。 Bias と Variance の足し算がそのまま MSE (ノイズ無し設定) と一致することを Python で再現する。
$$ \mathrm{MSE} = \mathbb{E}[(\hat{f}(x) - f(x))^2] = \underbrace{\big(\mathbb{E}[\hat{f}(x)] - f(x)\big)^2}_{\text{Bias}^2} + \underbrace{\mathbb{E}\big[(\hat{f}(x) - \mathbb{E}[\hat{f}(x)])^2\big]}_{\text{Variance}} + \sigma^2_{\text{noise}} $$
| 記号 | 意味 | 値 |
|---|---|---|
| f(x) | 真の値 (固定) | 5 |
| ŷ₁..ŷ₅ | 5 個の異なるモデルの予測 | 4.2, 5.8, 4.5, 5.5, 4.9 |
| n | サンプル数 | 5 |
| 項目 | 計算 | 結果 |
|---|---|---|
| E[ŷ] | (4.2 + 5.8 + 4.5 + 5.5 + 4.9) / 5 | 4.98 |
| (ŷ₁−f)² | (4.2−5)² = (−0.8)² | 0.64 |
| (ŷ₂−f)² | (5.8−5)² = (+0.8)² | 0.64 |
| (ŷ₃−f)² | (4.5−5)² = (−0.5)² | 0.25 |
| (ŷ₄−f)² | (5.5−5)² = (+0.5)² | 0.25 |
| (ŷ₅−f)² | (4.9−5)² = (−0.1)² | 0.01 |
| MSE | (0.64+0.64+0.25+0.25+0.01) / 5 | 0.358 |
| 項目 | 計算 | 結果 |
|---|---|---|
| Bias | E[ŷ] − f = 4.98 − 5 | −0.02 |
| Bias² | (−0.02)² | 0.0004 |
| (ŷ₁−E[ŷ])² | (4.2−4.98)² = (−0.78)² | 0.6084 |
| (ŷ₂−E[ŷ])² | (5.8−4.98)² = (+0.82)² | 0.6724 |
| (ŷ₃−E[ŷ])² | (4.5−4.98)² = (−0.48)² | 0.2304 |
| (ŷ₄−E[ŷ])² | (5.5−4.98)² = (+0.52)² | 0.2704 |
| (ŷ₅−E[ŷ])² | (4.9−4.98)² = (−0.08)² | 0.0064 |
| Variance | (0.6084+0.6724+0.2304+0.2704+0.0064) / 5 | 0.3576 |
| 項目 | 計算 | 結果 |
|---|---|---|
| Bias² + Variance | 0.0004 + 0.3576 | 0.3580 |
| Noise σ² | このデータには観測ノイズ無し | 0 |
| 合計 | 0.0004 + 0.3576 + 0 | 0.3580 |
| MSE (Step 2) | — | 0.3580 |
Bias²=0.0004 は微小だが、 Variance=0.3576 が大きい (予測がばらついている)。 過学習傾向のモデルに典型的な内訳。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import numpy as np f = 5.0 y_hat = np.array([4.2, 5.8, 4.5, 5.5, 4.9]) mse = np.mean((y_hat - f) ** 2) bias = y_hat.mean() - f bias2 = bias ** 2 var = np.mean((y_hat - y_hat.mean()) ** 2) total = bias2 + var print(f"E[y_hat] = {y_hat.mean():.4f}") print(f"MSE = {mse:.4f}") print(f"Bias^2 = {bias2:.4f}") print(f"Variance = {var:.4f}") print(f"Bias^2 + Variance = {total:.4f}") print(f"分解は一致するか = {np.isclose(mse, total)}") |
💬 手計算 (Step 4 = 0.3580) と Python 出力 (0.3580) が完全一致。 Bias² がほぼゼロ・Variance が大きい→「予測の平均は正しいが個別予測がばらつく」高分散モデルと診断できる。
公的統計(SSDSE-B-2026)を題材に、 最小限の Python コードで動作させます。 ファイルパス(data/raw/SSDSE-B-2026.csv)は自分の環境に合わせて変更してください。 まずはこのまま動かすことが理解の最短ルートです。
1 2 3 4 5 6 7 8 9 10 | import numpy as np from sklearn.model_selection import cross_val_score from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression for d in [1, 2, 5, 10]: pipe = make_pipeline(PolynomialFeatures(d), LinearRegression()) score = -cross_val_score(pipe, X, y, scoring='neg_mean_squared_error').mean() print(f'degree={d}: CV MSE={score:.3f}') |
▶ 実行 を押せばこのページの中でそのまま動きます(ライブラリもデータも同梱済みで、 準備は要りません)。 手元の Python に移して動かすときは pip install numpy pandas scikit-learn が必要です。 読んでいるデータは data/raw/SSDSE-B-2026.csv。 日本語を含むので encoding='cp932' の指定を落とさないでください。
本サイトの全コードは 論文一覧ページ から実例として確認できます。 自分のデータで試したい場合は、 列名・欠損記号・単位の違いだけ調整すれば、 ほぼそのまま流用できます。
「バイアス・バリアンス」を初めて使う方向けに、 ハンズオン的な実行手順を整理します。 上の Python 実装と組み合わせて、 1 度自分の手でなぞってみることを強く推奨します。
data/raw/ に配置(または自分のデータを用意)。 列名と単位を確認。df.head()、 df.describe()、 df.isna().sum() で全体像を把握。 ここで欠損や外れ値の見当を付ける。この 8 ステップを 1 度回すと、 「用語を読んで分かった気になる」段階から「実際に使える」段階に進めます。 知識は身体で覚えるのが結局のところ最速です。
バイアス・バリアンス分解で初学者が陥る典型ミス。 「訓練 MSE が小さい = 良いモデル」と判定する、 47 県の特殊事例(東京・大阪の都市バイアス)を見落とす、 など。 SSDSE-B-2026 のように標本サイズ 47 で複雑モデルを使うと Var が爆発するのが定石です。
TimeSeriesSplit を使うか、 ドメインベースで分割する。StandardScaler().fit_transform(X) するとテスト集合の平均・分散が訓練側に漏れる(リーク)。 必ず Pipeline で囲み、 fold ごとに fit する。統計データ解析コンペや学術論文・社内資料で「バイアス・バリアンス分析を行いました」と書く際の 過不足のないテンプレート を示します。 査読・上司レビューで「これが書かれていない」と指摘される典型項目を網羅。
| 項目 | テンプレート文例 |
|---|---|
| データ出典・規模 | 「分析には独立行政法人統計センター提供の SSDSE-B-2026(都道府県 47 件、 2023 年度)を用いた」 |
| 前処理 | 「総人口(A1101)を百万単位、 ごみ総排出量(H5609)を万トン単位にスケーリングし、 標準化は Pipeline 内で fold ごとに実施した(リーク防止)」 |
| 評価方法 | 「5-fold cross-validation(random_state=0)で MSE を測定し、 多項式次数 d=1〜10、 Ridge α=1e-4〜1e3 のグリッドで探索」 |
| 主結果 | 「単純線形回帰(d=1)で CV MSE=54.44、 多項式 d=2 で CV MSE=42.25(最良)、 Ridge(d=5, α=1)で CV MSE=111.75、 RandomForest(200 本, max_depth=5)で CV MSE=613.5、 GBM(200 本)で CV MSE=683.8」 |
| バイアス・バリアンス判定 | 「learning curve から、 単純モデルは高バイアス(train≈cv で頭打ち)、 d=5 多項式は高バリアンス(gap 大)と判定。 単一特徴量では RF/GBM の優位は小さく、 CV MSE が最小なのは多項式 d=2」 |
| 不確実性 | 「CV の標準偏差が RF で 881、 GBM で 899 と大きく、 N=47 ではモデル間の CV MSE 差(610〜690)はこの標準偏差に埋もれ、 GBM と RF の差は統計的に有意でないことが分かる」 |
| 限界 | 「N=47 は小サンプルで、 double descent 領域の検証は不可能。 単一年度(2023)のクロスセクションのため時系列変動は捉えられない」 |
| 再現性 | 「Python 3.11、 scikit-learn 1.5、 random_state=0 で固定。 コードは GitHub リポジトリ XXX に公開」 |
この 5 フェーズを 1 つの workflow として身につければ、 バイアス・バリアンスは「教科書の概念」から「実務で毎日使う言語」に変わります。 SSDSE-B-2026 のような公的データセットで 必ず手を動かして実感する ことが、 最短の習得ルートです。
| 症状(観察) | 診断 | 即時の打ち手 |
|---|---|---|
| train_MSE が下がらない | underfit / 高 bias | PolynomialFeatures(d=3) を追加、 max_depth↑、 α↓ |
| train≈0, test≫0 | overfit / 高 variance | Ridge α=10、 RandomForest n=200、 dropout=0.3 |
| CV ごとに結果が大きく違う | 高 variance + 小サンプル | cv=10 に増、 StratifiedKFold、 アンサンブル化 |
| 何やっても CV が頭打ち | irreducible noise が支配的 | 特徴量を根本から再設計、 ラベル定義を見直す |
| 論文に書く 1 行 | — | 「learning curve から train/CV gap=X → 高 variance と判定し、 Ridge(α=Y) で CV MSE を Z→W に改善」 |
このチートシートを 印刷してデスクに貼る だけで、 ML 実務の 80% の判断が即座にできるようになります。 残り 20% は本ページの「深掘り 1〜5」と参考文献を読んで補強してください。
補足:本ページ全体を通して使ってきた SSDSE-B-2026 のサンプルコードは data/raw/SSDSE-B-2026.csv をデフォルトパスとしています。 自分のデータに置き換える際は、 X = df[['特徴量']].values、 y = df['ターゲット'].values の 2 行だけを書き換えれば、 残りのすべてのコード(多項式回帰、 Ridge、 RF、 GBM、 learning curve、 Monte Carlo)がそのまま流用可能です。 これは「教育用と本番用のコードベースを 1 本化する」現代的な MLOps の発想にも合致します。
関連概念を視覚的に整理した概念マップ。
中心のバイアス・バリアンス分解 E[(y-ŷ)²]=Bias²+Variance+σ² から、 (上) 高バイアス側 (線形回帰のような単純モデル、 未学習)、 (右) 高バリアンス側 (深い決定木、 k=1 の k-NN、 過学習)、 (下) 中間最適点 (バランスのとれたモデル複雑度)、 (左) 解釈の道具 (学習曲線、 検証曲線、 交差検証 RMSE) へ放射状に接続している。 SSDSE-B-2026 で「都道府県の高齢化率を 5 変数から予測する」場合、 単回帰 (高バイアス低バリアンス) → 多項式回帰 → ランダムフォレスト → 深層モデル (低バイアス高バリアンス) と複雑度を変えながら、 5-fold CV の MSE が U 字を描く点が最適複雑度。 正則化 (L2/L1) はバリアンスを下げてバイアスを少し上げる、 アンサンブル (Bagging) はバリアンスを下げてバイアスは保つ、 という形で「U 字の底を低くする」道具と位置付けられる。
バイアス・バリアンス分解 E[(y-ŷ)²] = Bias² + Variance + σ² は汎化誤差を「未学習成分」「過学習成分」「既約ノイズ」に分け、 モデル選択の理論的根拠となる。
SSDSE-B-2026 で高齢化率予測モデルを構築する場合、 単回帰 (高バイアス)・ランダムフォレスト (中庸)・深層モデル (高バリアンス) を 5-fold CV で比較し、 U 字の底のモデル複雑度を選ぶのが標準ワークフロー。
「バイアス・バリアンス」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。
このフローに沿って判断することで、 「バイアス・バリアンス」を中核とした適切な手法選択ができる。