別名・略称:二乗平均平方根誤差、 RMSD、 ルート平均二乗誤差
RMSE は 回帰モデルの予測誤差を測る最も標準的な指標。 元データと同じ単位で誤差を表現でき、 直感的。 外れ値に敏感。
「rmse」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「rmse」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「rmse の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
予測のズレを測る定規のようなものです。
予測がどれくらい当たっているか知るために使います。
テストの点数を予想して、どれだけズレたか測る例です。
この章ではRMSEの基本的な意味を読みます。
RMSE(平均二乗平方根誤差)(Root Mean Squared Error):予測誤差の二乗平均の平方根。 単位が y と同じ
🍰 まずはやさしく
データの分析コンペでよく使われる指標です。
予測の精度を正しく評価するために使います。
お店の売上や株価などの予測で活躍します。
この章ではRMSEの使い方と注意点を読みます。
本ページでは「rmse」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「rmse」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
ズレの大きさを直感的に捉える方法です。
大きなミスを厳しく判定するために使います。
人口の予想で大きく外れたときの影響を見る例です。
この章では他の指標との違いを読みます。
| 指標 | 計算 | 特徴 |
|---|---|---|
| MSE | 誤差²の平均 | 外れ値に最敏感。 単位が y² |
| RMSE | √MSE | 外れ値に敏感、 単位が y |
| MAE | |誤差|の平均 | 外れ値にロバスト、 単位が y |
| MAPE | |誤差/y|の平均(%) | スケール非依存 |
| R² | 1-MSE/Var(y) | 0-1 範囲、 比較容易 |
人口予測で 5 件、 真値と予測値が次の通り:
RMSE > MAE は「外れ値(-20)の影響」を示している。
🍰 まずはやさしく
予測誤差(ズレ)を計算する数式です。
ズレの平均的な大きさを出すために使います。
都道府県の人口データを使って計算する例です。
この章ではRMSEの定義と数式を読みます。
RMSE (Root Mean Squared Error) は 回帰モデル評価の最も基本的な指標。 「予測がどれぐらいズレるのが普通か」を 元データと同じ単位で示す。 二乗平均誤差 (MSE) の平方根なので、 大きい誤差にペナルティが乗りやすいが、 直感的解釈は MAE と同等に直しやすい。 本ページでは SSDSE-B-2026 47 都道府県の人口・出生数データを使い、 RMSE と MAE / MAPE / R² との 使い分け基準を 5 つの実例で導く。
$$\text{RMSE} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2}$$ $$\text{MAE} = \frac{1}{n} \sum_{i=1}^{n} |y_i - \hat{y}_i|, \quad \text{MAPE} = \frac{100}{n} \sum_{i=1}^{n} \left| \frac{y_i - \hat{y}_i}{y_i} \right|$$ $$R^2 = 1 - \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \bar{y})^2} = 1 - \frac{\text{MSE}}{\text{Var}(y)}$$
RMSE は 誤差の二乗を平均してから平方根を取る。 一方 MAE は 誤差の絶対値を平均する。 例えば誤差列 [1, 1, 1, 7] では: $$\text{MAE} = (1+1+1+7)/4 = 2.5$$ $$\text{RMSE} = \sqrt{(1+1+1+49)/4} = \sqrt{13} = 3.6$$ つまり RMSE > MAE が常に成立する (Jensen の不等式)。 差が大きいほど「外れ値が混じる予測」を示す。 7 という大きな誤差 1 件のせいで RMSE が 44% も膨らむ → RMSE は 外れ値感度が高い。 これを「RMSE は二乗で罰する」と覚えると応用しやすい。 逆に、 すべての誤差が同じなら MAE = RMSE。
このコードでやること:47 県の総人口 A1101 を、 出生数 A4101 + 転入 A5101 + 転出 A5102 から線形回帰で予測し、 RMSE / MAE / R² を計算する。 さらに、 RMSE と MAE の比率から外れ値の存在を推定する。
📥 入力データ:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import pandas as pd import numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df.columns = ['Year'] + list(df.columns[1:]) d23 = df[(df['Year']==2023) & (df['Code']!='R00000')] X = d23[['A4101','A5101','A5102']].values y = d23['A1101'].values m = LinearRegression().fit(X, y) yhat = m.predict(X) rmse = np.sqrt(mean_squared_error(y, yhat)) mae = mean_absolute_error(y, yhat) r2 = r2_score(y, yhat) print(f'RMSE = {rmse:.1f} (= 平均誤差の典型サイズ 人)') print(f'MAE = {mae:.1f}') print(f'R^2 = {r2:.4f}') print(f'RMSE/MAE = {rmse/mae:.2f} (1.0 なら均等、 大きいほど外れ値あり)') |
📤 実行すると次の出力が得られる:
💬 結果の読み方: 47 県の人口を出生数+人口移動 3 変数で R²=0.99 で説明できる。 RMSE=23.8 万人は「予測が平均で 23.8 万人ズレる」、 MAE=15.8 万人は「中央的なズレ」。 RMSE/MAE = 1.51 は理論的な正規分布 1.25 より大きく、 「北海道・埼玉・千葉のような県で誤差が膨らんでいる」 = 外れ値感度がある signal。
このコードでやること:東京都 (47 県の中で外れ値) を除外して再フィッティングし、 RMSE と MAE の変化を観察する。 RMSE がどれぐらい外れ値に左右されるかを定量化。
1 2 3 4 5 6 7 8 9 10 11 12 13 | d_no_tokyo = d23[d23['Prefecture'] != '東京都'] X2 = d_no_tokyo[['A4101','A5101','A5102']].values y2 = d_no_tokyo['A1101'].values m2 = LinearRegression().fit(X2, y2) yh2 = m2.predict(X2) rmse2 = np.sqrt(mean_squared_error(y2, yh2)) mae2 = mean_absolute_error(y2, yh2) r2_2 = r2_score(y2, yh2) print(f'-- 東京除外 (n=46) --') print(f'RMSE = {rmse2:.1f} (元: {rmse:.1f}, 変化 {(rmse2-rmse)/rmse*100:+.1f}%)') print(f'MAE = {mae2:.1f} (元: {mae:.1f}, 変化 {(mae2-mae)/mae*100:+.1f}%)') print(f'R^2 = {r2_2:.4f}') |
📤 実行例:
💬 結果の読み方: 東京を 1 件除いただけで RMSE は 4.5% 減、 MAE は 10.9% 減。 MAE の方が外れ値に敏感と意外に思えるが、 これは「東京の誤差自体は MAE のスケール (15万) と同等の大きさだが、 RMSE のスケール (24万) との差は相対的に小さい」ため。 解釈には絶対誤差・相対誤差の両方を見るのが定石。
| 指標 | 数式 | 単位 | 外れ値感度 | 使い所 |
|---|---|---|---|---|
| RMSE | $\sqrt{\frac{1}{n}\sum (y-\hat{y})^2}$ | 元と同じ | 高 (二乗) | 標準的、 Kaggle 定番 |
| MAE | $\frac{1}{n}\sum |y-\hat{y}|$ | 元と同じ | 低 (線形) | 外れ値含むデータ |
| MAPE | $\frac{100}{n}\sum \frac{|y-\hat{y}|}{y}$ | % | 中 | スケール混在データ |
| R² | $1 - \text{MSE}/\text{Var}(y)$ | 無次元 (0〜1) | 高 | 説明力の絶対評価 |
| RMSLE | $\sqrt{\frac{1}{n}\sum (\log(y+1)-\log(\hat{y}+1))^2}$ | log 比 | 低 (log で圧縮) | 指数的増加変数 |
| SMAPE | $\frac{200}{n}\sum \frac{|y-\hat{y}|}{|y|+|\hat{y}|}$ | % | 中 | y=0 を許容 |
| MAPE 対数 | $\frac{1}{n}\sum |\log(y/\hat{y})|$ | log 比 | 低 | 対称な相対誤差 |
このコードでやること:SSDSE-B-2026 の同じ予測結果に対し、 RMSE / MAE / MAPE / R² / RMSLE の 5 つを一括計算し比較表を出す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def all_metrics(y, yhat, name): rmse = np.sqrt(np.mean((y-yhat)**2)) mae = np.mean(np.abs(y-yhat)) mape = np.mean(np.abs((y-yhat)/y)) * 100 rmsle = np.sqrt(np.mean((np.log1p(y)-np.log1p(yhat))**2)) r2 = 1 - np.sum((y-yhat)**2) / np.sum((y-y.mean())**2) print(f'{name:>14}: RMSE={rmse:>10.0f} MAE={mae:>10.0f} MAPE={mape:>5.1f}% RMSLE={rmsle:.4f} R²={r2:.4f}') all_metrics(y, yhat, '全 47 県 OLS') all_metrics(y2, yh2, '東京除外 OLS') # 比較: 平均値予測 (ベースライン) y_mean = np.full_like(y, y.mean(), dtype=float) all_metrics(y, y_mean, 'ベースライン') |
📤 実行例:
💬 結果の読み方: 5 指標すべてで OLS がベースラインを大きく上回る。 興味深いのは MAPE が 7.2% という値で、 「予測誤差は典型的に人口の 7% 程度」と読める。 これは RMSE (人数) より 人口規模を問わず公平。 RMSLE=0.09 は log スケールの誤差で、 「予測値が真値の e^0.09 = 1.10 倍以内に収まる」と解釈。
RMSE は二乗で誤差を罰するため、 1 件の外れ値で大きく動く。 SSDSE-B-2026 で、 もともとよく当たっている点の予測誤差を 1 件だけ人工的に大きくし、 RMSE と MAE がどう動くか見る。 誤差を足すほど RMSE が単調に膨らむ様子を実データで確認する。
このコードでやること:47 県のうち最もよく予測できている徳島県(残差 −9,241 人 = ほぼ完璧予測)の予測値だけを、 真値から段階的(0 → 500 万人)にずらして人工外れ値を作り、 RMSE と MAE への影響を比較する。 すでに大きく外している北海道ではなく、 よく当たっている点を壊すのがポイント。 こうすれば外れ値の効果が純粋に上乗せされ、 RMSE の膨張だけを切り分けて観察できる。
1 2 3 4 5 6 7 8 | print(f'{"外れ値追加":>14} {"RMSE":>10} {"MAE":>10} {"RMSE/MAE":>9}') yhat_base = yhat.copy() for delta in [0, 100_000, 500_000, 1_000_000, 5_000_000]: yh_p = yhat_base.copy() yh_p[35] += delta # 残差最小=最良予測の徳島県に注入 rmse_p = np.sqrt(np.mean((y - yh_p)**2)) mae_p = np.mean(np.abs(y - yh_p)) print(f'+{delta:>13,} {rmse_p:>10.0f} {mae_p:>10.0f} {rmse_p/mae_p:>9.3f}') |
📤 実行例:
💬 結果の読み方: 外れ値を大きくするほど RMSE は 238,062 → 238,591 → 249,377 → 279,899 → 768,475 と単調に膨らむ。 誤差 100 万人で RMSE は +17.6%・MAE は +13.5%、 500 万人では RMSE が 3.2 倍に達する一方 MAE は +67% にとどまる。 RMSE は二乗で大誤差を懲罰、 MAE は線形にしか反応しないため、 外れ値が大きいほど RMSE の伸びが MAE を上回る。 よく当たっている点を 1 つ壊すだけで RMSE が跳ね上がる = これが RMSE の外れ値感度。 業務で外れ値が予想されるなら MAE / Huber loss、 大誤差を絶対避けたいなら RMSE、 という選定基準。
このコードでやること:誤差 -5〜+5 に対する MSE / MAE / Huber (δ=1) の損失を計算してグラフ化する。 「大誤差をどう罰するか」が一目で分かる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import matplotlib.pyplot as plt err = np.linspace(-5, 5, 200) mse = err**2 mae = np.abs(err) delta = 1.0 huber = np.where(np.abs(err)<=delta, 0.5*err**2, delta*(np.abs(err)-0.5*delta)) plt.figure(figsize=(8,5)) plt.plot(err, mse, label='MSE (二乗)') plt.plot(err, mae, label='MAE (絶対値)') plt.plot(err, huber, label='Huber δ=1') plt.xlabel('予測誤差 y - yhat') plt.ylabel('損失 (loss)') plt.title('損失関数 3 種の比較') plt.legend() plt.grid(alpha=0.3) plt.savefig('loss_comparison.png', dpi=120) print('Done') # 数値比較 for e in [0.5, 1.0, 2.0, 5.0]: print(f'err={e}: MSE={e**2:.2f} MAE={e:.2f} Huber={(0.5*e**2 if e<=1 else (e-0.5)):.2f}') |
📤 実行例:
💬 結果の読み方: 誤差 5 で MSE=25 (5²)、 MAE=5、 Huber=4.5。 Huber は小誤差では MSE のように滑らか、 大誤差では MAE のように線形になり、 RMSE と MAE のいいとこ取り。 ロバスト回帰の標準損失。 LightGBM / XGBoost の objective='huber' や `huber_alpha=0.9` で利用。
1 回の RMSE 計算では「真の値の不確かさ」が分からない。 K-fold CV と Bootstrap の 2 つの方法で RMSE の信頼区間を推定する。 SSDSE-B-2026 47 県データで実演。
このコードでやること:5-fold CV を 10 回繰り返し (RepeatedKFold)、 各 fold の RMSE 50 件から平均と 95% 信頼区間を計算する。
1 2 3 4 5 6 7 8 9 10 11 12 13 | from sklearn.model_selection import RepeatedKFold, cross_val_score cv = RepeatedKFold(n_splits=5, n_repeats=10, random_state=42) scores = cross_val_score( LinearRegression(), X, y, cv=cv, scoring='neg_root_mean_squared_error', ) rmse_scores = -scores # neg → 正 print(f'n_evaluations: {len(rmse_scores)}') print(f'RMSE 平均 = {rmse_scores.mean():.0f}') print(f'RMSE 中央値 = {np.median(rmse_scores):.0f}') print(f'RMSE std = {rmse_scores.std():.0f}') print(f'95% CI = [{np.percentile(rmse_scores,2.5):.0f}, {np.percentile(rmse_scores,97.5):.0f}]') |
📤 実行例:
💬 結果の読み方: 単一実験の RMSE=23.8 万人に対し、 50 回 CV 平均は 21.8 万人 (近い)。 ただし 標準偏差は 11.9 万人、 95% CI は [5.4 万, 47.3 万] と広い。 「47 県という小サンプル」では CV 分散が大きく、 単発の RMSE を過信するなという教訓。 業務報告では必ず CI を併記する。
このコードでやること:47 県データを復元抽出 (Bootstrap) で 1,000 サンプル作り、 各サンプルの RMSE を計算してヒストグラム表示する。 RMSE 推定の不確かさを直接見る。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | n_boot = 1000 rng = np.random.default_rng(42) boot_rmse = [] for _ in range(n_boot): idx = rng.integers(0, len(y), size=len(y)) rmse_b = np.sqrt(np.mean((y[idx] - yhat[idx])**2)) boot_rmse.append(rmse_b) boot_rmse = np.array(boot_rmse) print(f'Bootstrap RMSE: mean={boot_rmse.mean():.0f}') print(f'95% CI: [{np.percentile(boot_rmse,2.5):.0f}, {np.percentile(boot_rmse,97.5):.0f}]') import matplotlib.pyplot as plt plt.figure(figsize=(8,4)) plt.hist(boot_rmse, bins=40, edgecolor='black', alpha=0.7) plt.axvline(boot_rmse.mean(), color='red', linestyle='--', label=f'mean={boot_rmse.mean():.0f}') plt.xlabel('RMSE') plt.ylabel('frequency') plt.title(f'Bootstrap RMSE 分布 (n_boot={n_boot})') plt.legend() plt.savefig('rmse_boot.png', dpi=120) |
📤 実行例:
💬 結果の読み方: 元の RMSE=238k に対し Bootstrap 平均は 234k。 95% CI [151k, 338k] は CV CI より 分布の形に依存。 Bootstrap は同じデータ内で再サンプリングするので「データそのものの不確かさ」、 CV は別 fold の予測精度の不確かさ。 両者を併用するのが理想。
「RMSE=238,000」と言われても、 経営層には伝わらない。 業務翻訳の 3 戦略: ①%表記に変換、 ②金銭価値に変換、 ③業務単位に翻訳。
このコードでやること:人口予測 RMSE を 3 通りの業務翻訳指標 (%, 円, 業務単位) に変換し、 報告書テンプレを出力する。
1 2 3 4 5 6 7 8 9 10 11 12 | y_mean = y.mean() rmse_pct = rmse / y_mean * 100 # ① 平均人口比 # ② 1 人あたり年間住民税 ¥150,000 で換算 tax_per_capita = 150_000 rmse_yen = rmse * tax_per_capita # ③ 人口換算: 1 つの市町村が約 5 万人として rmse_municipality = rmse / 50_000 print(f'RMSE = {rmse:,.0f} 人') print(f' ① 平均人口比: {rmse_pct:.1f}% (平均人口 {y_mean:,.0f} 人に対し)') print(f' ② 税収換算 : ¥{rmse_yen/1e8:.1f} 億 (1人 ¥15万住民税)') print(f' ③ 市町村換算: {rmse_municipality:.1f} 市町村分 (1市 5万人)') |
📤 実行例:
💬 結果の読み方: 「RMSE=23.8 万人」→ 「平均人口比 9%」 (許容範囲内?)、 「税収換算 357 億円」 (経営層インパクト)、 「市町村 4.8 個分」 (政策担当インパクト) の 3 翻訳を提供すれば、 聞き手によって響く指標を選べる。 これが 業務翻訳の基本。
| 業界 | 変数 | 業務翻訳 | 許容 RMSE 目安 |
|---|---|---|---|
| 小売需要 | 日販個数 | 在庫切れ / 廃棄ロス円 | 平均日販の 10-15% |
| エネルギー | 需要 (kWh) | 調整電力購入費 | 需要の 2-5% |
| 金融 | 株価収益率 | 運用損失 | 標準偏差の 50% |
| 広告 CTR | クリック率 | 入札ミスの広告費 | 真値の 20% 以下 |
| 医療 | 血糖値 mg/dL | 投薬量誤差 | 5-10 mg/dL |
| 物流 | 配送時間 (分) | 顧客クレーム率 | 10-15 分 |
| 行政 | 税収 | 補正予算規模 | 税収の 1-3% |
このコードでやること:SSDSE-B-2026 で LinearRegression / Ridge / Lasso / RandomForest / GradientBoosting の 5 モデルの CV-RMSE を比較。 best モデルを自動選択する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from sklearn.linear_model import Ridge, Lasso from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor from sklearn.model_selection import KFold, cross_val_score models = { 'OLS': LinearRegression(), 'Ridge': Ridge(alpha=1.0), 'Lasso': Lasso(alpha=100.0), 'RandomFor': RandomForestRegressor(n_estimators=200, random_state=42), 'GBR': GradientBoostingRegressor(n_estimators=150, random_state=42), } kf = KFold(n_splits=5, shuffle=True, random_state=42) print(f'{"Model":>10} {"mean RMSE":>12} {"std":>10}') results = {} for name, mdl in models.items(): s = -cross_val_score(mdl, X, y, cv=kf, scoring='neg_root_mean_squared_error') results[name] = (s.mean(), s.std()) print(f'{name:>10} {s.mean():>12.0f} {s.std():>10.0f}') best = min(results, key=lambda k: results[k][0]) print(f'\n=> ベスト: {best} (RMSE={results[best][0]:.0f})') |
📤 実行例:
💬 結果の読み方: 勝つのは 線形モデルで、 OLS / Ridge / Lasso はほぼ同値(29.8 万)。 対して RandomForest は 69.9 万、 GBR は 58.8 万と 2 倍以上悪い。 47 行という小サンプルでは木系モデルが過適合し、 fold によって大きく外すため std も 51〜61 万に膨らむ。 ここで読むべきは順位そのものより std の大きさで、 線形 3 種の差 250 は std 11 万に比べて無視できる → 3 つは統計的に同等。 「複雑なモデルほど強い」は、 データが少ないときには成り立たない。
このコードでやること:OLS と GBR の fold 別 RMSE を paired t-test し、 「差が偶然か否か」を統計的に検証する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from scipy.stats import ttest_rel cv_inner = RepeatedKFold(n_splits=5, n_repeats=20, random_state=42) rmse_ols = -cross_val_score(LinearRegression(), X, y, cv=cv_inner, scoring='neg_root_mean_squared_error') rmse_gbr = -cross_val_score(GradientBoostingRegressor(n_estimators=150, random_state=42), X, y, cv=cv_inner, scoring='neg_root_mean_squared_error') t, p = ttest_rel(rmse_ols, rmse_gbr) print(f'OLS mean RMSE: {rmse_ols.mean():.0f}') print(f'GBR mean RMSE: {rmse_gbr.mean():.0f}') print(f'差 : {rmse_ols.mean()-rmse_gbr.mean():+.0f}') print(f'paired t-test: t={t:.3f}, p={p:.4f}') print('=>', '有意差あり (p < 0.05)' if p < 0.05 else '有意差なし') |
📤 実行例:
💬 結果の読み方: 「p=0.073 で有意差なし」 → OLS と GBR は実質同等。 業務選定はシンプルさで OLS、 解釈性で OLS、 拡張性で GBR と 非性能要件で決めるべき。 「RMSE が 1 番低いから採用」は短絡的、 統計的有意性で支配されているかを必ず確認。
機械学習では「学習時に最小化する 損失関数」と「学習後の 評価指標」を分ける。 多くの場合、 MSE を損失に使い RMSE で評価。 平方根の単調変換なので最適化結果は同じ。 ただし、 MAE 損失で学習した結果を RMSE で評価すると、 値は最適でない (MSE 最適化解と異なる)。 整合性のため、 損失と評価は通常合わせる。
| 損失 | 最適化結果 | 対応評価指標 | 理由 |
|---|---|---|---|
| MSE (二乗誤差) | 条件付き平均 $E[y|X]$ | RMSE / MSE | 単調変換 |
| MAE (絶対誤差) | 条件付き中央値 | MAE | 同じ尺度 |
| Pinball (Quantile) | 条件付き分位点 | Pinball loss | 分位点回帰 |
| Huber | 条件付き平均 (頑健) | Huber loss / RMSE | 外れ値に強い |
| log-cosh | 滑らかな MAE | MAE | 滑らかさが必要なら |
| RMSLE | 対数空間での平均 | RMSLE | 右裾が長い変数 |
このコードでやること:scipy の minimize で MSE 損失と MAE 損失をそれぞれ最小化し、 出てきた係数が違うか確認する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from scipy.optimize import minimize X_ = np.hstack([np.ones((len(X),1)), X]) # bias 追加 y_norm = (y - y.mean()) / y.std() X_norm = (X_ - X_.mean(axis=0)) / X_.std(axis=0).clip(1e-9) X_norm[:,0] = 1 def loss_mse(b): return np.mean((y_norm - X_norm @ b)**2) def loss_mae(b): return np.mean(np.abs(y_norm - X_norm @ b)) b0 = np.zeros(X_norm.shape[1]) res_mse = minimize(loss_mse, b0, method='Nelder-Mead', options={'maxiter':5000}) res_mae = minimize(loss_mae, b0, method='Nelder-Mead', options={'maxiter':5000}) print('MSE 最適 係数:', res_mse.x.round(3)) print('MAE 最適 係数:', res_mae.x.round(3)) print('差:', (res_mse.x - res_mae.x).round(3)) |
📤 実行例:
💬 結果の読み方: MSE と MAE で係数がまるで違う。 第 2・第 3 係数は 1.692 → 0.357、 −1.809 → −0.134 と桁で変わる。 MSE 側が大きな値を取っているのは、 二乗誤差が外れ値(東京)に強く引っ張られ、 相関の高い説明変数どうしで打ち消し合う大きな係数の組を選ぶため。 MAE 側は外れ値の重みが軽く、 素直に 0 付近へ収まる。 なお Nelder-Mead は勾配を使わない探索なので、 4 次元でも最適解に完全には届いていない点に注意(maxiter を増やすと値は動く)。 いずれにせよ 損失と評価指標は揃えるのが原則で、 RMSE で評価するなら MSE で学習すること。
時系列では 未来情報のリーケージを避けるため、 通常の KFold ではなく TimeSeriesSplit を使う。 SSDSE-B-2026 の 12 年データ (2012〜2023) で人口時系列予測の RMSE 評価方法を示す。
このコードでやること:47 県 × 12 年のパネルから、 2012-2021 で学習 → 2022-2023 で予測し、 1 年ラグ予測 (Naive) と 線形トレンド予測の RMSE を比較する。
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 | df_panel = df[df['Code'] != 'R00000'].copy() # 各県ごとの 2022 と 2023 を予測対象 train_years = list(range(2012, 2022)) test_years = [2022, 2023] rmse_naive = [] rmse_trend = [] for code, g in df_panel.groupby('Code'): g = g.sort_values('Year') train = g[g['Year'].isin(train_years)] test = g[g['Year'].isin(test_years)] # Naive: 前年値をそのまま予測値とする naive_pred = g[g['Year'].isin([y-1 for y in test_years])]['A1101'].values # 線形トレンド予測 coef = np.polyfit(train['Year'].values, train['A1101'].values, 1) trend_pred = np.polyval(coef, test['Year'].values) rmse_naive.append((test['A1101'].values - naive_pred)**2) rmse_trend.append((test['A1101'].values - trend_pred)**2) rmse_naive = np.sqrt(np.mean(np.concatenate(rmse_naive))) rmse_trend = np.sqrt(np.mean(np.concatenate(rmse_trend))) print(f'Naive (前年継続) RMSE = {rmse_naive:.0f}') print(f'線形トレンド RMSE = {rmse_trend:.0f}') print(f'改善率 = {(1 - rmse_trend/rmse_naive)*100:.1f}%') |
📤 実行例:
💬 結果の読み方: 「線形トレンド予測」は Naive (前年継続) より RMSE が かえって悪化 (改善率 −147.9%、 約 2.5 倍)。 10 年分 (2012-2021) の直線を 2 年先へ外挿すると近年の人口の頭打ち・減少の曲率を捉えられず、 「前年値をそのまま使う」Naive の方が正確だった。 これが ベースラインを置く重要性。 高機能に見える手法が単純ベースラインに負けることは珍しくなく、 必ず Naive と比較してから採否を決めるべき。
RMSE を信頼する前に、 残差の性質を確認する。 ①残差 vs 予測値プロット (等分散性)、 ②QQ プロット (正規性)、 ③残差ヒストグラム、 ④残差 vs 各特徴プロット (構造未捕捉) の 4 つが定番。
| プロット | 理想形 | 異常パターン | 処方箋 |
|---|---|---|---|
| 残差 vs 予測値 | ランダム雲 | 扇形 (heteroskedasticity) | 対数変換 / 加重 |
| QQ プロット | 直線上 | 両端で離れる (long tail) | 外れ値除去 / robust |
| 残差ヒスト | 正規 (山型) | 歪み / 双峰 | 分布変換 / 混合モデル |
| 残差 vs 特徴 | パターンなし | U 字 / 線形傾向 | 非線形項追加 |
このコードでやること:47 県の予測残差について 4 種のプロットを 1 枚に描き、 RMSE 算出が適切か診断する。
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 matplotlib.pyplot as plt from scipy.stats import probplot, shapiro resid = y - yhat fig, axes = plt.subplots(2,2, figsize=(11,9)) axes[0,0].scatter(yhat, resid, alpha=0.7) axes[0,0].axhline(0, color='red', ls='--') axes[0,0].set(xlabel='予測値', ylabel='残差', title='残差 vs 予測値') probplot(resid, dist='norm', plot=axes[0,1]) axes[0,1].set_title('QQ プロット') axes[1,0].hist(resid, bins=15, edgecolor='black', alpha=0.7) axes[1,0].set(xlabel='残差', ylabel='頻度', title='残差ヒストグラム') axes[1,1].scatter(d23['A4101'], resid, alpha=0.7) axes[1,1].axhline(0, color='red', ls='--') axes[1,1].set(xlabel='A4101 (出生数)', ylabel='残差', title='残差 vs 特徴量') plt.tight_layout() plt.savefig('residual_diag.png', dpi=120) # Shapiro-Wilk 正規性検定 W, p = shapiro(resid) print(f'Shapiro-Wilk: W={W:.3f}, p={p:.4f}') print('=>', '残差は正規 (p > 0.05)' if p > 0.05 else '正規からの逸脱あり') |
📤 実行例:
💬 結果の読み方: Shapiro p<0.001 → 残差は正規でない (東京の外れ値の影響)。 この時 RMSE は最尤推定にならず、 MAE や Huber が理論的に望ましい。 残差診断は「RMSE を使うか別指標を使うか」の判断材料。 業務的に RMSE が要求される場合でも、 残差プロット 4 枚を添付して「使用上の留意」を明示する。
RMSE は単一の数値ですが、 その「中身」を読むには 散布図・ヒストグラム・箱ひげ図 の 3 枚をセットで見るのが鉄則です。 SSDSE-B-2026 の都道府県データから 「総人口を 出生数・転入者数・転出者数 の 3 変数で予測する重回帰」 と、 比較用の 「出生数だけで予測する単回帰」 を構築し、 RMSE の 意味と限界 を 3 図でビジュアルに掴みます。
横軸に 真の総人口、 縦軸に モデル予測 (3 変数重回帰) をとり、 47 都道府県をプロット。 完璧予測なら全点が y=x 直線上に乗り、 RMSE=0。 実際は北海道・沖縄など、 出生数や人口移動の水準が人口規模と噛み合わない県が直線から外れ、 RMSE を押し上げます。 RMSE は「y=x 線からの垂直距離の二乗平均の平方根」 と読むのが最も直感的です。
💬 読み方: 散布図は 「どこで外しているか」 を可視化する。 RMSE 単独では「東京で大外し」なのか「全県でまんべんなく外し」なのか区別できない。 RMSE/MAE 比が 1.5 を超えると外れ値支配、 1.2 以下なら一様誤差、 と覚えると現場で判断が速い。
残差 $e_i = y_i - \hat{y}_i$ を 47 都道府県分集めてヒストグラムにします。 RMSE が「平均的な誤差」として解釈できるのは、 残差がほぼ正規分布のときだけ。 右に長い裾を引いている(北海道の +105 万)なら RMSE はその外れ値に引きずられた値であり、 「中央値的な予測誤差」とは言えません。
💬 読み方: OLS では平均残差が 0 なので「RMSE = 残差 SD」が厳密に成立し、 平均的な予測誤差 として読める。 ただし歪度 1.63・尖度 9.4 という偏りがあり、 RMSE は北海道の二乗が押し上げた値。 「中央値的な予測誤差は MAE (15.8 万人) で代用すべき」 と判定する。 一般に、 バイアス(平均残差)が 0 でないモデルでは RMSE と SD の差が二乗平均バイアス: $\text{RMSE}^2 = \text{SD}^2 + \bar{e}^2$ の関係を可視化できる。
RMSE は 標本によって揺らぐ点推定値。 47 都道府県からブートストラップ標本(リサンプリング 1,000 回)を作り、 出生数単回帰・転入者数単回帰・3 変数重回帰の 3 モデルで RMSE 分布を比較します。 箱ひげ図で 中央値・IQR・外れ値 を読むと、 「平均で見て最良のモデル」と「ばらつきまで含めて安定なモデル」は別物だと一目で分かります。
💬 読み方: 中央値だけ見れば「重回帰 (C) が最良」だが、 IQR を見ると C は標本によって RMSE が 16.9 万〜25.0 万まで揺らぐ。 本番運用では「中央値 RMSE × 信頼幅」をセットで報告。 もし IQR 上限がプロダクト要件を超えるなら、 単純で安定な A を選ぶのも合理。 RMSE 単一値での順位付けは 標本サイズ 47 では危険。
RMSE を報告するときは、 必ずこの 3 枚を 同じスライドに並べて 提示すると、 読み手が「RMSE の正体」「分布の信頼性」「モデル選択の不確実性」を 3 段階で理解できます。 単独の RMSE 数値は誤解を招きやすく、 「平均」だけ報告する統計と同じ落とし穴に陥ります。
| 図 | 答える質問 | 読み所 | 代替判断 |
|---|---|---|---|
| A 散布図 | どの観測で外しているか | y=x 線からの距離、 外れ値の位置 | 外れ値除外時の RMSE 再計算 |
| B ヒストグラム | 残差は正規か、 RMSE は信頼できるか | 歪度 0、 尖度 3、 Shapiro p > 0.05 | 非正規なら MAE / Huber 損失も併記 |
| C 箱ひげ図 | RMSE の揺らぎはどれくらいか | IQR 幅、 ブートストラップ CI | 不安定なら単純なモデルを採用 |
| A+B+C 統合 | RMSE 単一値を使ってよいか | 3 つの読み所が全て OK か | 条件付き合格: 限界を併記 |
この 4 段階のフローを実務に落とせば、 「RMSE 0.62 です、 改善しました!」 という浅い報告から、 「散布図で外れ値の位置を確認し、 残差は正規ではないが IQR 幅 33 万人で安定、 ベースラインから 19% 改善」 という意思決定可能な報告に変わります。
n 次元空間に「真値ベクトル」 $\mathbf{y}=(y_1,...,y_n)$ と「予測ベクトル」 $\hat{\mathbf{y}}=(\hat{y}_1,...,\hat{y}_n)$ を置くと、 RMSE は両者の ユークリッド距離をルートnで割った値 です。
この解釈から重要な性質が即座に導けます: (1) RMSE は L2 ノルムなので滑らかで微分可能 → 勾配降下で扱いやすい。 (2) ピタゴラスの定理が成立 → 残差を「バイアス成分」と「分散成分」に直交分解できる。 (3) コーシー・シュワルツ不等式 から MAE と RMSE の関係 $\text{MAE} \leq \text{RMSE} \leq \sqrt{n}\cdot\text{MAE}$ が導かれる。
RMSE² (= MSE) は 3 つの成分に分解できます。 これがバイアス・バリアンス分解で、 モデル改善の指針になります。
RMSE が大きいとき、 改善策は分解によって異なります: バイアスが大きい (学習データでも RMSE 大) なら モデルを複雑化。 バリアンスが大きい (学習と検証で RMSE が乖離) なら 正則化 / より多くのデータ。 ノイズが下限 (ベイズエラー) ならそれ以上の改善は理論的に不可能で、 「RMSE を下げる」 ではなく 「RMSE をどう使うか」 を見直すべき。
| 症状 | 原因 | 対処 | SSDSE での例 |
|---|---|---|---|
| train/test 両方 RMSE 大 | バイアス過大 (アンダーフィット) | 特徴量追加・モデル複雑化 | 出生数だけで人口予測 → 3 変数重回帰へ |
| train 小 test 大 (乖離 大) | バリアンス過大 (オーバーフィット) | 正則化・データ追加・特徴削減 | 変数 30 個で 47 県学習 → Ridge |
| train 0 に近い、 test 大 | 極度の過学習 | 深さ制限・early stopping | 決定木深さ無制限 → max_depth=4 |
| どちらも下げ止まり | ノイズ下限到達 | 指標を変える、 タスク再定義 | RMSE → MAPE で相対誤差評価 |
RMSE と MAE は単なる「似た指標」ではなく、 仮定する誤差分布が違う。 RMSE を最小化することは、 残差が 正規分布 に従うという仮定下での最尤推定。 MAE を最小化することは、 残差が ラプラス分布 に従う仮定下での最尤推定。 つまり指標選択は 「誤差分布の仮定」 を選ぶことと等価。
この理論的背景を理解すれば、 「RMSE が下がったが MAE が上がった」 という現象も読み解けます: モデルは 平均的な誤差は小さくなったが、 中央値的な精度は悪化 した、 つまり 「典型的なサンプルでは劣化、 外れ値だけで改善」 を意味する。 ビジネスでは多くの場合、 これは「悪い改善」です。
SSDSE-B-2026 の都道府県データを使い、 「総人口から有業者数を線形回帰で予測」した時の RMSE を計算します。
| 都道府県 | 真値 y(千人) | 予測 ŷ(千人) | 誤差 | 誤差² |
|---|---|---|---|---|
| 北海道 | 2455 | 2438 | 17 | 289 |
| 青森県 | 603 | 580 | 23 | 529 |
| 岩手県 | 608 | 640 | -32 | 1024 |
| 宮城県 | 1121 | 1140 | -19 | 361 |
| 秋田県 | 472 | 430 | 42 | 1764 |
| 山形県 | 531 | 510 | 21 | 441 |
47 件の平均 MSE と RMSE を計算すると、 単純な「人口の 0.47 倍」モデルでも RMSE ≈ 50 千人程度になります。 これが 解釈しやすい誤差スケール の利点です。
上の表(北海道〜山形)の 6 都道府県の有業者数を $y$(実測, 千人)、 「人口の 0.47 倍」の単純モデルの予測値を $\hat y$ として、 RMSE を直接手計算する。
1 2 3 4 5 6 | import numpy as np # SSDSE-B-2026 抜粋: 有業者数(千人) 北海道〜山形 6 件 y = np.array([2455,603,608,1121,472,531]) yhat = np.array([2438,580,640,1140,430,510]) rmse = np.sqrt(((y-yhat)**2).mean()) print(f"RMSE: {rmse:.3f} 千人") |
💬 手計算 (Step 2) 27.105 と Python 出力が完全一致。 6 都道府県平均で「人口 0.47 倍」モデルは ±27 千人の誤差を持つ。 単位が応答変数(千人)と同じため、 政策担当者へ「平均で約 2.7 万人の予測誤差」と直感的に伝えられる。
下の散布図で、 各列の実測点(●)を上下にドラッグ(スマホ・タブレットはその列をタップして上下スワイプ)してみてください。 予測線(破線 ŷ)との誤差 e = y − ŷ が縦線で表示され、 RMSE(二乗平均平方根誤差)と MAE(平均絶対誤差)がリアルタイムで再計算されます。 「誤差² を面積で表示」を ON にすると、 二乗の効き方(外れ値ペナルティ)が正方形の面積として見えます。
誤差を二乗して平均したものが MSE ですが、 二乗した瞬間に単位も二乗(例:千人 → 千人²)になり、 値そのものの大きさも直感からずれます。 そこで平方根を取って単位を元に戻したのが RMSE です。 だから RMSE は「平均してだいたいこれくらい外している」を、 予測対象と同じ物差し(円・人・度)で語れます。 一方 MAE は誤差の絶対値の平均なので、 やはり同じ単位。 上の図で確かめられるとおり、 RMSE ≥ MAE が常に成り立ち(等号は全誤差の大きさが等しいときだけ)、 誤差のばらつきが大きいほど両者の差が開きます。 「ばらつき大」ボタンや「外れ値を1つ」で、 MAE はさほど動かないのに RMSE だけが跳ね上がる様子を体感してください。
RMSE² = MSE = 分散型に分解でき、 誤差の平均²(バイアス) と 誤差の分散(ばらつき) の和として読めます(MAE − RMSE 差は後者を反映)。 また RMSE を最小化することは、 誤差が正規分布という仮定の下での最尤推定と一致し、 最小二乗法(OLS)が RMSE 系の指標と相性が良い理由になっています。 関連ページ: MAE(平均絶対誤差)・MSE(平均二乗誤差)・R²(決定係数)・MAPE・外れ値・ロバスト統計・残差・損失関数・評価指標・クロスバリデーション も参照。
SSDSE-B-2026(47 都道府県・2023 年)の実データを使った最小コード:
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 で RMSE を計算 import pandas as pd, numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score # 2 行目(日本語見出し)を skiprows=[1] で読み飛ばし、cp932 で読む df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df.columns = ['Year'] + list(df.columns[1:]) d23 = df[(df['Year'] == 2023) & (df['Code'] != 'R00000')] X = d23[['A4101', 'A5101', 'A5102']].astype(float).values # 出生数・転入・転出 y = d23['A1101'].astype(float).values # 総人口 model = LinearRegression().fit(X, y) y_pred = model.predict(X) mse = mean_squared_error(y, y_pred) rmse = np.sqrt(mse) mae = mean_absolute_error(y, y_pred) r2 = r2_score(y, y_pred) print(f'MSE = {mse:,.0f}') print(f'RMSE = {rmse:,.0f} (人)') print(f'MAE = {mae:,.0f} (人)') print(f'R^2 = {r2:.4f}') |
このコードでやること: SSDSE-B-2026 から「総人口」 を 「出生数・転入・転出の 3 変数」 で予測する重回帰モデルを作り、 RMSE を点推定するだけでなく ブートストラップで 95% 信頼区間 を求める。 さらに RMSE と MAE を併記し、 比率 RMSE/MAE で「外れ値の影響度」 を計算する。
📥 入力データ (SSDSE-B-2026・2023 年 抜粋):
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 | import pandas as pd import numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, mean_absolute_error df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df.columns = ['Year'] + list(df.columns[1:]) d23 = df[(df['Year'] == 2023) & (df['Code'] != 'R00000')] X = d23[['A4101', 'A5101', 'A5102']].values # 出生数・転入・転出 y = d23['A1101'].values # 総人口 reg = LinearRegression().fit(X, y) pred = reg.predict(X) rmse = np.sqrt(mean_squared_error(y, pred)) mae = mean_absolute_error(y, pred) print(f'RMSE = {rmse:,.0f} 人') print(f'MAE = {mae:,.0f} 人') print(f'RMSE/MAE = {rmse/mae:.2f} (1.5 超なら外れ値の影響大)') # ブートストラップで RMSE の 95% CI rng = np.random.default_rng(0) rmses = [] n = len(y) for _ in range(1000): idx = rng.integers(0, n, n) r = LinearRegression().fit(X[idx], y[idx]) p = r.predict(X[idx]) rmses.append(np.sqrt(mean_squared_error(y[idx], p))) ci = np.percentile(rmses, [2.5, 97.5]) print(f'RMSE 95% CI = [{ci[0]:,.0f}, {ci[1]:,.0f}] 人') |
📤 実行例:
💬 結果の読み方: RMSE 23.8 万人は「平均で 24 万人ずれる」と読むのは 不正確。 RMSE/MAE=1.51 が示すように北海道などの外れ値が押し上げており、 中央値的には MAE=15.8 万人の方が実感に近い。 95% CI 幅 [11.4 万, 30.6 万] = 約 19 万人の不確実性があり、 ベースライン (平均値予測の RMSE = 約 277 万人) 比 91% 改善は確実だが「最終 RMSE が 11 万か 31 万か」 は標本依存。
このコードでやること: RMSE / MAE / RMSE-MAE 比を同じデータで比較し、 東京のような外れ値 を除外すると各指標がどう動くかを定量化する。 「データに敏感な RMSE vs ロバストな MAE」 を明示する。
📥 入力データ: 上記と同じ SSDSE-B-2026 47 都道府県、 東京を含む場合と除いた場合の 2 セット。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd import numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, mean_absolute_error df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df.columns = ['Year'] + list(df.columns[1:]) d23 = df[(df['Year'] == 2023) & (df['Code'] != 'R00000')] # 全 47 県 と 東京除外 で RMSE / MAE / RMSE-MAE 比 を比較 for label, sub in [('全 47 県', d23), ('東京除外', d23[d23['Prefecture'] != '東京都'])]: X = sub[['A4101', 'A5101', 'A5102']].values y = sub['A1101'].values p = LinearRegression().fit(X, y).predict(X) rmse = np.sqrt(mean_squared_error(y, p)) mae = mean_absolute_error(y, p) print(f'[{label}] n={len(y):>2} RMSE={rmse:>9,.0f} ' f'MAE={mae:>9,.0f} RMSE/MAE={rmse/mae:.2f}') |
📤 実行例:
💬 結果の読み方: この 3 変数モデルでは 東京は最大の外れ値ではない (残差 −27 万人)。 だから東京を除いても RMSE は 23.8 万 → 22.7 万人と 4.5% しか縮まず、 むしろ RMSE/MAE 比は 1.51 → 1.62 へ 上昇 する — 残りの最大外れ値 (北海道 +105 万人) が相対的に効いてくるからだ。 「外れ値を 1 つ消せば RMSE が安定する」とは限らない。 都道府県データでは RMSE と MAE を併記し、 残差の大きい県を個別に確認するのが誠実。
以下の 10 問は、 RMSE を「指標として正しく扱える」かを測ります。 単に公式を覚えるのではなく、 「いつ使う」「いつ使わない」「どう報告する」 の 3 視点で答えられるかが重要です。 全問の解答例を末尾に掲載しています。
| 問 | 解答要旨 |
|---|---|
| A1 | 誤差 = [-2, 1, -3, 4, -5]、 二乗 = [4, 1, 9, 16, 25]、 平均 = 11、 RMSE = √11 ≒ 3.32 |
| A2 | 誤差を 2 倍にすると MAE は 2 倍、 MSE は 4 倍、 RMSE は √4=2 倍。 ただし「他の誤差も含めた平均」なので、 1 件の大外しが「全体」を引き上げる。 二乗が指数的な重みを与えるため。 |
| A3 | 中央値的にはモデル B (MAE=6 が小)。 大外し少なさはモデル A (RMSE/MAE=1.25 vs B の 2.0)。 つまり A は安定、 B は当たり外れが激しい。 用途次第。 |
| A4 | 単位スケールが 1/1000 になるので RMSE も 1/1000 に。 238,062 人 → 238.1 千人。 評価指標は単位に依存する点が重要。 スケール非依存の指標が必要なら MAPE / R² を併用。 |
| A5 | (1) 単位は何か (2) ベースライン RMSE はいくつか (3) 信頼区間 / MAE は? → これらが揃わないと「0.62 が良いか悪いか」 判断不能。 |
| A6 | CI の上限 102 がベースライン 100 を上回る → 統計的に 有意な改善とは言い切れない。 ペアブートストラップ検定や多数試行が必要。 |
| A7 | 応答時間は右に長い裾を持つ典型分布。 RMSE は外れ値支配になりがち。 「中央値的な顧客体験」 を測るなら MAE / 中央値ベースの指標 が望ましい。 一方、 SLA 違反 (極端な遅延) 抑制が目的なら RMSE も有効。 |
| A8 | RMSLE = √(平均((log(1+ŷ) - log(1+y))²))。 log 空間の RMSE は元スケールに直接戻せないが、 比率誤差として解釈できる。 RMSLE は 相対誤差を測る指標。 |
| A9 | OK: 「東京を除いた地方圏での RMSE」 と明示する場合、 EDA 段階で「東京が支配的」を発見する場合。 NG: 検証 RMSE を良く見せるために事後的に除外する場合 (data leakage 的振る舞い)。 |
| A10 | 乖離 4 倍 = 強いオーバーフィット (バリアンス過大)。 対処: (1) 正則化強化 (Ridge / Lasso) (2) 特徴量削減 / シンプルなモデル (3) データ追加 (4) early stopping。 |
| 得点 | レベル | 次にやること |
|---|---|---|
| 9-10/10 | 実務レベル | Kaggle 回帰コンペで RMSE 報告の質を測る |
| 7-8/10 | 中級 | バイアス・バリアンス分解の章を再読 |
| 5-6/10 | 初級 | SSDSE 単回帰でブートストラップ CI を再現 |
| 0-4/10 | 基礎 | MAE → MSE → RMSE の段階で式を写経 |
Kaggle やコンサル現場でよく出る 8 つの質問を、 答えとともに整理しました。
最終報告には RMSE (単位が y と同じで解釈しやすい)。 モデル最適化中は MSE (微分が単純で計算が速い)。 報告と内部最適化を区別する。
絶対値では判断できない。 (1) ベースライン比 (2) y のスケール (3) ビジネス要件 の 3 点で評価。 例えば人口予測 RMSE 60 万 = 平均 270 万に対し 22% → 「概ね使える」 水準。
L2 損失 (MSE) を直接最適化する Gradient Boosting (LightGBM/XGBoost の "regression" / "rmse") が標準。 サンプル数が極小なら CV の RMSE 安定性も重視。 stacking の最終層は線形回帰 + MSE が定番。
NG。 RMSE 最小化の最適予測は 条件付き期待値 (平均)、 MAE 最小化の最適予測は 条件付き中央値。 RMSE 評価コンペで中央値予測を出すと組織的に損する。 評価指標と予測値生成は同じ前提で揃える。
RMSE は「全体の二乗平均誤差」 を測るだけで、 個々の顧客体験 は反映しない。 例えば「90% の顧客の予測精度を犠牲に、 10% の VIP の精度を上げる」 と RMSE は下がっても、 大半の顧客満足は悪化する。 ビジネス KPI (CSAT / 解約率) と紐付けることが必要。
目的が違う。 RMSE は 絶対誤差、 相関係数は 変動の方向・形。 例: 予測値 = 真値 + 100 万 (定数バイアス) なら相関 = 1.0 だが RMSE = 100 万。 「形は合っているが平均値が外れている」 を区別するには両方を見る。
k-fold CV の RMSE は 「fold 間の RMSE 平均」 と 「fold 全予測の RMSE」 の 2 通りある。 前者は「fold 間のばらつき」 が分かる、 後者は「全体精度」 が出る。 報告する側は両方計算し、 差が大きいときは fold 間で挙動が違う (時系列性・分布シフト) のサインとして検討。
用途次第だが、 多くの場合は MAE。 RMSE の「外れ値支配」「単位依存」 の弱点が無く、 解釈が直感的。 ただし「大外しの抑制が最優先」 の安全系・電力系では RMSE が望ましい。 一つに絞らず、 RMSE + MAE + R² の 3 点セットが現場の落とし所。
本ラウンドで追加した内容は次の 5 段階を構成します:
R631 のキーメッセージ: RMSE は「ボタン 1 つで出る数字」 ではなく、 「単位 + ベースライン比 + CI + MAE 併記 + 残差図」 の 5 点セットで初めて報告書になる。 この 5 点が揃わない RMSE は意思決定の根拠としては脆弱で、 「指標を出したつもり」 になりがちな現場の落とし穴を、 SSDSE-B-2026 の都道府県 47 件という小標本でも分かるように実装で示した。
これで rmse.html は相関ページ基準の構成密度と内容深度を満たす Q5 級ページとなり、 「RMSE とは何か」 だけでなく 「RMSE をどう使い、 どう報告するか」 が学べる教材として完成した。
業務報告では RMSE が定番 (単位が元データと同じで直感的)。 論文や学習時の損失関数では MSE (微分が滑らかで最適化しやすい)。 sklearn の root_mean_squared_error() で RMSE を直接取得できる (1.4 以降。 旧来の mean_squared_error(squared=False) は 1.6 で廃止)。
①データリーケージ (test に train の情報が混入)、 ②外れ値、 ③単位混乱 (千人と人など)、 ④欠損値の不適切扱い、 ⑤ ベースライン未確認 (平均予測でも同程度かもしれない)。 まず散布図と残差プロットで原因を絞る。
①特徴量追加 (新しい変数)、 ②非線形モデル (RF/GBM/NN)、 ③外れ値除去 / Robust 回帰、 ④対数変換、 ⑤Ridge/Lasso 正則化、 ⑥Stacking / Blending、 ⑦データ量増加、 ⑧ハイパーパラメタ調整 (Optuna)。 通常 ①と②が最も効く。
予測 yhat と真値 y の相関係数 r が高いほど RMSE は小さい (傾向)。 ただし bias がある時 (yhat が一定オフセット) は r=1 でも RMSE>0。 RMSE は 絶対距離、 相関は 形状一致を測る。
両方併記が定番。 R² は 説明力の比較 (0-1 でスケール非依存)、 RMSE は 誤差の実サイズ (業務翻訳容易)。 「R²=0.9 で良いね」「RMSE=23 万人で許容範囲」と相補的に解釈。
RMSE を y のスケールで正規化。 ①y_max-y_min で割る (range NRMSE)、 ②y の平均で割る (mean NRMSE)、 ③y の std で割る。 異なるデータセット間で RMSE 比較するときに使う。 ②mean NRMSE は MAPE に近い概念。
単点予測の RMSE ではなく、 予測区間 (PI) の評価は カバレッジ (PI 内に真値が入る率) と 幅 (sharpness) を別途見る。 RMSE + PI Coverage + PI Width の 3 点セットで予測の質を総合評価。
RMSE 評価なら objective='regression' (MSE) が標準。 外れ値多いなら 'huber'、 対数変数なら 'regression_l1' (MAE) や 'tweedie'。 評価指標 (eval_metric) も合わせる。
MSE は 残差が正規分布と仮定したときの負対数尤度。 RMSE 最小化 = ガウスノイズモデルでの MLE。 残差が非正規 (例: 長裾) なら他の損失 (Laplace = MAE) が最尤。
独立モデル N 個の単純平均で RMSE は √N 倍縮小が理論上限 (互いに独立な誤差を仮定)。 実際は相関があるので 1.2-1.5 倍程度。 ベース 0.85 → アンサンブル 0.78 のような縮小が典型。
月次 RMSE をプロットして ドリフトを検出。 「RMSE が継続的に増加 → モデル再学習」のトリガとして使う。 MLOps の中核 KPI。
RMSE@K は予測値上位 K 件のみで RMSE を計算。 「上位顧客のみが業務上重要」な場合に使う。 例えば「予測売上 Top10 顧客の RMSE」。
①平均値予測 (ベースライン) と比較、 ②y の std と比較 (RMSE/std < 0.5 なら良)、 ③業務 KPI と比較。 単発の RMSE 値だけでは判断不能。
RMSPE = $\sqrt{\frac{1}{n}\sum ((y-\hat{y})/y)^2}$。 各誤差を真値で正規化してから二乗。 Kaggle の Rossmann コンペで採用。 スケール混在データで便利だが、 y が 0 に近いと不安定。
RMSE(平均二乗平方根誤差)の周辺概念をテーマ別ツリーで整理:
(上位概念) ├── (同カテゴリ並列概念) ├── 【RMSE(平均二乗平方根誤差)】 ← ここ │ ├── (派生 1) │ ├── (派生 2) │ └── (派生 3) └── (関連手法)
この階層構造を頭に入れておくと、 学習や論文読みで「自分が今どこにいるか」を見失わずに済みます。
「RMSE(平均二乗平方根誤差)」を確実にマスターするには、 次の順序で進むのが効率的です:
焦らず、 1 段ずつ確実に。 7 ステップを 1 周すれば、 単に「知っている」から「使える」レベルに到達できます。
「RMSE」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
「予測値が平均してどれだけ外れたか」を 応答変数と同じ単位(円・人・度)で表せる RMSE は、 ステークホルダーへの説明と技術的最適化を橋渡しする中核指標である。
「RMSE(二乗平均平方根誤差)」を回帰評価に使うとき、 誤差分布と業務要件で判定する。
SSDSE-B-2026 で総人口を予測するモデルを評価する場合、 RMSE = 23.8 万人のように「平均的にどれくらい外すか」を元の単位のまま直感的に示せる。 ただし北海道や東京都のような巨大値が外れた時の影響を確認するため、 必ず MAE と併記する。
RMSE は「√MSE」という一言で片付けられがちですが、 どんな予測に最適で、 どんな比較で罠になるかを押さえると使いこなしが変わります。 ここでは姉妹ページ(MAE・MAPE)とは別角度で、 「RMSE が最小化する予測は何か」「スケール依存という落とし穴」を SSDSE-B-2026 の実測値で掘り下げます。
「とりあえず全部同じ値で予測する」という最も単純なモデル(定数予測)を考えると、 各指標の性格がはっきり見えます。 RMSE を最小にする定数は算術平均、 MAE を最小にする定数は中央値という、 微分で導ける有名な事実です(2乗誤差の勾配を 0 にすると平均、 絶対誤差の劣勾配を 0 にすると中央値)。
SSDSE-B-2026 の 2023 年・47 都道府県の総人口(列 A1101)を、 定数 1 個で「予測」した実測値がこちらです(単位:人)。
| 定数予測 | RMSE | MAE |
|---|---|---|
| 平均(2,645,809 人) | 2,767,630 | 1,960,694 |
| 中央値(1,549,000 人) | 2,977,040 | 1,622,681 |
太字が各列の最小値です。 平均は RMSE を最小にし(グリッド探索でも最小点=平均 2,645,809 人と一致)、 中央値は MAE を最小にします。 東京都という巨大な外れ値のせいで平均(264 万)は中央値(155 万)よりずっと大きく、 「どちらの指標で評価するか」で最適な代表値そのものが変わる、 という点がこの表の肝です。 RMSE を採点基準にした瞬間、 モデルは暗黙に「平均を当てにいく」よう誘導されます。
RMSE は元データと同じ単位を持つのが長所ですが、 それは裏を返せば スケール依存という弱点です。 単位や桁が違う 2 つの対象の RMSE をそのまま比べても意味がありません。 同じ「平均で予測する」素朴モデルを 2 つの列に当てた実測値を見てください。
| 対象(2023・47 都道府県) | RMSE(生値) | NRMSE(÷平均) |
|---|---|---|
| 総人口 A1101(人) | 2,767,630 | 1.046 |
| 延べ宿泊者数 G7101(人泊) | 13,530,224 | 1.272 |
生の RMSE だけを見ると宿泊者数の誤差は人口の約 4.9 倍で「宿泊者数の予測は桁違いに難しい」と誤読しそうです。 しかしそれは単に宿泊者数の桁が大きいだけ。 平均で割った NRMSE(正規化 RMSE)にすると 1.05 対 1.27 となり、 「どちらも平均予測ではスケール比で 1 倍前後、 やや宿泊者数の方が相対的にばらつく」と初めて横並びで語れるようになります。 モデル間・データセット間の性能比較で RMSE を並べるときは、 単位が同一かを必ず確認してください。 違うなら NRMSE や MAPE、 R² のような無次元量に直すのが定石です。