論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
回帰タスク
Regression Task
ML基礎

🔖 キーワード索引

回帰Regression連続値予測RMSEMAER²線形回帰GBR外挿残差分析

本ページは 回帰タスク(Regression Task)を 12 のセクションで多角的に解説します。 上のチップは検索・関連語の手がかりです。 以下のリンクで各セクションに直接ジャンプできます:

💡 30秒結論 | 📍 文脈 | 🎨 直感 | 📐 数式 | 🔬 数式を言葉で読み解く | 🧮 実値計算 | 🐍 Python 実装 | ⚠️ 落とし穴 | 🧭 さらに深く | 🌐 関連手法 | 🔗 関連用語 | 📚 グループ教材

💡 30秒で分かる結論

🍰 まずはやさしく

数値を当てるための道具です。

正確な量を予測するために使います。

スマホで明日の気温を調べるようなことです。

この章では回帰タスクの基本を学びます。

💡 30秒で分かる結論

📍 文脈 — どこで使う概念か

🍰 まずはやさしく

機械学習の大きな柱の一つです。

データの「量」を調べたいときに使います。

お店で商品の売れる数を予想するようなことです。

どのような場面で使うのかを解説します。

回帰タスクは機械学習の二大タスクの一つ(もう一方は分類タスク)。 出力が「量」を表すとき適用します。 実務では 需要予測・価格設定・設備寿命予測・スコアリングなど、 産業の根幹に関わる場面で多用されます。 単純な単回帰から多変量・非線形まで、 幅広い手法が含まれます。

🎨 直感で掴む — 具体例で理解する

🍰 まずはやさしく

答えが数字になる予測のことです。

具体的な数値を導き出すために使います。

部活の練習量から得点を予想するようなことです。

具体例を使って直感的に理解しましょう。

回帰タスクとは、 「入力 $\mathbf{x}$ から、 連続値の出力 $y$ を予測する」こと。

タスク例入力 $\mathbf{x}$出力 $y$
住宅価格予測不動産査定立地、 面積、 築年数価格(万円)
需要予測店舗の発注計画曜日、 天気、 過去売上売上(個)
スポーツ予測選手のパフォーマンス練習量、 年齢、 経歴スコア
医療予測入院日数の見積診断、 検査値、 年齢日数

共通点は 出力が「量」であること。 「猫か犬か」のようなカテゴリ判定(=分類)とは区別されます。

🎨 もう一歩踏み込む直感

「回帰タスク」を本当に使いこなすには、 教科書的な定義だけでは足りません。 ここでは現場で役立つ追加の比喩・実例を整理します。 上の「🎨 直感で掴む」を補強する内容です。

📊 「回帰タスク」の判定基準:手元の問題が回帰か分類か迷ったら、 まず y の値が大小関係を持つかを確認する。 「医師数 250 人 vs 200 人」は 差が 50 人と意味を持つので回帰。 一方「血液型 A vs B」は差が意味を成さないので分類。 SSDSE-B-2026 の列で言えば、 A1101 (総人口) や A4101 (出生数) は回帰、 もし「過疎指定 1/0」のような列があれば分類になります。 連続値か順序ありかカテゴリかを見抜くのが第一歩。

🎮 触って理解する

回帰タスクは 「散布図に曲線を当てはめて連続値を予測する」問題です。 下の図で モデルの複雑さ(多項式の次数)をスライダーで変えると、 当てはめ曲線と誤差がリアルタイムに変化します。 次数を小さくすると直線的で当てられない(未学習)、 次数を大きくすると訓練点を無理に通ってぐにゃぐにゃになる(過学習)様子を体感してください。 分類タスクと違い、 評価は 連続値の誤差(MSE・R²)で測ります。

● 青=訓練点(曲線を当てはめるのに使用)/○ 橙=検証点(当てはめには不使用・汎化性能の確認用)。 点はドラッグで移動、 図の空白をクリック/タップで訓練点を追加できます。

訓練誤差(当てはめに使った点)
MSE = – / R² = –
検証誤差(未使用の点で確認)
MSE = – / R² = –

🔎 観察のヒント:次数を上げると訓練 MSE はどんどん下がるのに、 検証 MSE は途中で下げ止まり、 やがて悪化(U 字)します。 訓練誤差だけを見て「良いモデル」と判断すると過学習を見逃します。 これが回帰タスクで 交差検証 や 検証データ が不可欠な理由です。

🧭 もっと深く — 直感・落とし穴・発展

💡 直感:連続値を「当てる」
分類が「どのカテゴリか」を選ぶのに対し、 回帰は 数直線上の一点を指し当てます。 予測が正解より 3 でも 30 でもズレていれば、 そのズレの大きさそのものがペナルティ(MSE は二乗、 MAE は絶対値)。 上の図で曲線を点に近づけるほど MSE が小さくなるのは、 このズレを縮めているからです。
⚠️ よくある落とし穴
  • 過学習:次数を上げれば訓練誤差は必ず下がる。 だが過学習したモデルは新しいデータで大外し。 訓練誤差でなく検証誤差で選ぶ。
  • 外挿:高次多項式は学習範囲の両端で暴走する。 スライダーを 9 にして端の点をドラッグすると曲線が跳ね上がるのが分かる。 データ範囲外の予測は危険。
  • 分類との混同:目的変数が「A/B」のようなカテゴリなら回帰ではなく分類タスク。 評価指標も精度・F1 に変わる。
🚀 発展
正則化(正則化・Ridge・Lasso)は、 高次でも係数を小さく抑えてぐにゃぐにゃを自動で抑制します。 直線では捉えきれない曲線関係には、 多項式のほかに 一般化加法モデル(GAM) や決定木・ニューラルネットといった非線形回帰も選べます。 評価指標の詳細は 評価指標・MSE・決定係数 R² を参照。

📐 定義・数式

🍰 まずはやさしく

予測の仕組みを数式にしたものです。

計算で正しい答えを出すために使います。

買い物での合計金額を計算するようなことです。

回帰タスクの定義と数式について読みます。

回帰モデルの一般形:

【回帰モデル】
$$y = f(\mathbf{x}; \boldsymbol{\theta}) + \varepsilon, \quad \varepsilon \sim \mathcal{N}(0, \sigma^2)$$
$f$ = モデル、 $\boldsymbol{\theta}$ = パラメータ、 $\varepsilon$ = 誤差項

最小二乗法による学習:

【損失関数(MSE)】
$$\mathcal{L}(\boldsymbol{\theta}) = \frac{1}{n}\sum_{i=1}^{n} (y_i - f(\mathbf{x}_i; \boldsymbol{\theta}))^2$$
予測値と実値の二乗誤差の平均。 これを最小化する $\boldsymbol{\theta}$ が最適解

📐 数式・定義

回帰タスクを数式 / 形式定義で表す:

$$y = f(\mathbf{x}; \boldsymbol{\theta}) + \varepsilon, \quad \varepsilon \sim \mathcal{N}(0, \sigma^2)$$

回帰モデルの一般形:$y$ は説明変数 $\mathbf{x}$ とパラメータ $\boldsymbol{\theta}$ の関数 + 正規ノイズ $\varepsilon$。

📐 もう一段の数式表現

「回帰タスク」を厳密に書き下すと、 以下の形になります。 既出の数式と合わせて読むと、 概念の骨格が見えてきます。

【回帰タスク・追加表現】
$$ \hat{y} = f(\mathbf{x};\,\boldsymbol{\theta}),\quad L(\boldsymbol{\theta}) = \frac{1}{n}\sum_{i=1}^n (y_i - \hat{y}_i)^2 $$
回帰タスクの一般形と平均二乗誤差(MSE)損失。 θ をこの損失最小化で学習する。

🔬 記号・要素の読み解き

$y$(目的変数)
予測したい連続値(価格、 売上、 日数 など)
$\mathbf{x}$(説明変数)
予測に使う特徴量ベクトル(多次元)
$f$(モデル)
線形・木・NN など、 入力→出力の写像
$\boldsymbol{\theta}$(パラメータ)
学習で求める係数や重み
$\varepsilon$(誤差)
予測しきれないノイズ。 通常は正規分布を仮定
$\sigma^2$(分散)
誤差の大きさ。 予測の不確実性

🔬 数式を言葉で読み解く

上の記号表を、 2023 年度の 47 県で「総人口(万人)から出生数を当てる」単回帰に当てはめて読む。 最小二乗法で求めた式は ŷ = −676.9 + 61.04 × 総人口(万人)である。

記号この例での中身北海道の値
$y_i$県 i の出生数(A4101、 人)24,430 人
$\mathbf{x}_i$県 i の総人口(A1101 を万人に換算)。 説明変数が 1 つなのでベクトルの長さは 1509.2 万人
$\boldsymbol{\theta}$切片 −676.9 と傾き 61.04(総人口 1 万人あたり出生数が 61 人増える)47 県共通
$f(\mathbf{x}_i;\boldsymbol{\theta})$予測値 ŷi = −676.9 + 61.04 × xi30,406 人
$\varepsilon_i$残差 yi − ŷi。 モデルが説明しきれなかった分−5,976 人(47 県で最大の外れ)
$\sigma^2$残差の分散。 残差平方和 1 億 2,359 万を自由度 47 − 2 = 45 で割って平方根をとると 1,657 人47 県共通

損失関数 $\mathcal{L}(\boldsymbol{\theta})$ は、 この残差を 47 県ぶん 2 乗して平均したものなので、 最小化した後の値は 123,592,264 ÷ 47 ≈ 2,629,623、 その平方根(学習データ上の RMSE)は 1,622 人になる。 σ の推定値 1,657 人より少し小さいのは、 割る数が 47 か 45 かの違いである。

🧮 数値例・実値計算

例:47都道府県のデータで、 高齢化率から死亡率を予測する単回帰:

項目値
切片 $\beta_0$−5.17
傾き $\beta_1$(高齢化率)+0.610
$R^2$0.945
RMSE0.49 ‰

解釈:「高齢化率が 1% 上がると、 死亡率が約 0.61‰ 上がる」。 $R^2 = 0.945$ より、 死亡率の変動の 94.5% が高齢化率で説明できる。

🧮 SSDSE-B 実値計算 — 都道府県データで手を動かす

SSDSE-B-2026 で 「総人口 A1101・65歳以上人口 A1303 → 出生数 A4101」を予測する回帰を実装し、 RMSE / MAE / R² の 3 指標で評価する。

使用データ:SSDSE-B-2026.csv(独立行政法人 統計センター提供、 47 都道府県 × 12 年分 × 110 超の社会経済指標)。 出典

🎯 このコードでやること: SSDSE-B-2026 を読み込み、年度で 2023 に絞り、学習用と評価用に分割、モデルを学習、予測を取得、精度を評価。

📥 入力例 # 入力: data/raw/SSDSE-B-2026.csv (47都道府県 × 12年。年度列 SSDSE-B-2026 で絞る) # 2023年度 先頭3行(A1101=総人口, A1303=65歳以上人口, A4101=出生数): # pref A1101 A1303 A4101 # 北海道 5092000 1681000 24430 # 青森県 1184000 417000 5696 # 岩手県 1163000 407000 5432
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]          # 2023年度の47都道府県だけ抽出
df = df.rename(columns={df.columns[2]: 'pref'})

X = df[['A1101', 'A1303']].fillna(0).values   # 総人口・65歳以上人口
y = df['A4101'].values                        # 出生数
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
m = GradientBoostingRegressor(n_estimators=200, max_depth=4, random_state=42)
m.fit(X_tr, y_tr)
pred = m.predict(X_te)
print(f'RMSE = {np.sqrt(mean_squared_error(y_te, pred)):.2f}')
print(f'MAE  = {mean_absolute_error(y_te, pred):.2f}')
print(f'R²   = {r2_score(y_te, pred):.3f}')
📤 実行例 RMSE = 11028.87 MAE = 5748.45 R² = 0.815

💬 読み方: skiprows=[1] で日本語ラベル行を除外し、 df[df['SSDSE-B-2026']==2023] で 1 年分に絞り、 encoding='cp932' で文字化けを回避 / random_state=42 を固定すると再現性が確保される / GBR は少数データ(47 件)では線形回帰より当てはまりが落ちることもある。

▲ 上記コードはそのまま実行可能。 CP932 エンコーディング・skiprows=[1](日本語ラベル行をスキップ)・年度列 SSDSE-B-2026 で 2023 を抽出・列名の英数字コード(A1101 = 総人口 など)に注意。

🧮 SSDSE-B-2026 で追加実値計算

『教育用標準データセット SSDSE-B-2026』(47 都道府県 × 12 年度、 112 列のうち数値 109 列)の 2023 年度 47 県で、 総人口から出生数を当てる単回帰の結果を数値で確かめる。

対象 計算結果
SSDSE-B:総人口で出生数を単回帰 → 傾き≈ 61 人/万人
MAE(全 47 都道府県)≈ 1,146 人
R²0.991(非常に高い説明力)

🧮 数式に値を入れて手で計算する: SSDSE-B-2026 で回帰タスク評価指標

SSDSE-B-2026(2023年度)から 6 都道府県(北海道〜山形)の出生数 A4101 を真値 y、 「全国出生率 0.00585 × 総人口」モデルの予測を ŷ として、 MAE / RMSE / R² を手計算する。

Step 1: y, ŷ, 誤差

y = [24430, 5696, 5432, 12328, 3611, 5151] (SSDSE-B-2026 出生数 A4101) ŷ = [29788, 6926, 6804, 13244, 5347, 6002] ( 0.00585×総人口 モデル ) e = y - ŷ = [-5358, -1230, -1372, -916, -1736, -851] |e| = [5358, 1230, 1372, 916, 1736, 851]

Step 2: 指標

MAE = (5358+1230+1372+916+1736+851)/6 = 11463/6 ≈ 1910.5 MSE = (28708164+1512900+1882384+839056+3013696+724201)/6 = 36680401/6 ≈ 6113400 RMSE = √6113400 ≈ 2472.53 ȳ = (24430+5696+5432+12328+3611+5151)/6 ≈ 9441.33 SST = Σ(y-ȳ)² ≈ 315,494,995、 SSE = 36,680,401 R² = 1 - 36680401/315494995 ≈ 0.8837

🐍 Python で再現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import numpy as np
# SSDSE-B-2026 (2023年度) 抜粋: 出生数 A4101 北海道〜山形 6 件
y = np.array([24430, 5696, 5432, 12328, 3611, 5151])
pop = np.array([5092000, 1184000, 1163000, 2264000, 914000, 1026000])
yhat = np.round(pop * 0.00585)   # 全国出生率(0.00585)×総人口 の単純モデル
e = y - yhat
mae = np.abs(e).mean()
rmse = np.sqrt((e**2).mean())
r2 = 1 - (e**2).sum() / ((y - y.mean())**2).sum()
print(f"MAE: {mae:.3f}, RMSE: {rmse:.3f}, R²: {r2:.4f}")

📤 実行結果

MAE: 1910.500, RMSE: 2472.529, R²: 0.8837

💬 手計算 (Step 2) と Python 出力が完全一致。 R²≈0.884 は「全国出生率×総人口」の単純モデルが 6 都道府県の出生数の変動の約 88% を説明することを示す(人口と出生数の強い連動)。 残差 e がすべて負なのは、 この 6 県の出生率が全国平均をやや下回るため。

🧮 RMSE と MAE の差から「大きく外す県」を読む

上の 6 県の手計算と同じ「全国の出生数 ÷ 総人口 × その県の総人口」というモデルを 47 県全部に当てはめる。 RMSE は残差を 2 乗してから平均するので、 少数の県の大きな外れに引っ張られる。 RMSE ÷ MAE の比は、 誤差がすべて同じ大きさなら 1 になり、 大きく外す県があるほど大きくなる。

🎯 このコードでやること:2023 年度の 47 県で全国一律の出生率モデルの残差を求め、 残差の大きい県と、 MAE・RMSE・その比を、 東京都または北海道を除いた場合と比べる。

📥 入力例 SSDSE-B-2026 の 2023 年度 47 行 Prefecture A1101(総人口) A4101(出生数) 北海道 5,092,000 24,430 青森県 1,184,000 5,696 ... 沖縄県 1,468,000 11,818
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d = df[df['SSDSE-B-2026'] == 2023].set_index('Prefecture')
rate = d['A4101'].sum() / d['A1101'].sum()          # 全国の「出生数 ÷ 総人口」
err = d['A4101'] - rate * d['A1101']                 # 残差 = 実測 − 予測(人)

def report(e, label):
    mae, rmse = e.abs().mean(), np.sqrt((e ** 2).mean())
    print(f'{label}: n={len(e)}  MAE={mae:,.0f}  RMSE={rmse:,.0f}  RMSE/MAE={rmse / mae:.2f}')

print(f'全国の出生数 / 総人口 = {rate:.5f}')
print('残差の絶対値が大きい 3 県:')
print(err.loc[err.abs().sort_values(ascending=False).index[:3]].round(0).to_string())  # 符号つき
report(err, '47 都道府県')
report(err.drop('東京都'), '東京都を除く 46 道府県')
report(err.drop('北海道'), '北海道を除く 46 都府県')
📤 実行例(実測) 全国の出生数 / 総人口 = 0.00585 残差の絶対値が大きい 3 県: Prefecture 北海道 -5350.0 愛知県 4673.0 福岡県 4097.0 47 都道府県: n=47 MAE=1,199 RMSE=1,769 RMSE/MAE=1.48 東京都を除く 46 道府県: n=46 MAE=1,139 RMSE=1,690 RMSE/MAE=1.48 北海道を除く 46 都府県: n=46 MAE=1,109 RMSE=1,605 RMSE/MAE=1.45

💬 全国の出生率は 0.00585 で、 残差がいちばん大きいのは東京都ではなく北海道(−5,350 人。 人口のわりに出生数が少ない)、 次が愛知県(+4,673 人)と福岡県(+4,097 人)だった。 47 県の MAE は 1,199 人、 RMSE は 1,769 人で、 比は 1.48。 東京都を除いても MAE 1,139 人・RMSE 1,690 人とほとんど変わらず、 北海道を除いたほうが RMSE は 1,605 人まで下がる。 人口の多い県ほど残差の絶対値も大きくなるので、 「外れ値 = 東京都」と決めつけずに残差を並べて確かめる。

✅ 理解度チェック — このページの数値で解く

  1. 問:「合計特殊出生率を当てる」と「合計特殊出生率が 1.5 以上かを当てる」は、 それぞれ回帰タスクか分類タスクか。
    答:前者は連続値を当てるので回帰タスク、 後者は 2 値を当てるので分類タスク。 データは同じでも問題の立て方でタスクが決まる。
  2. 問:6 県の手計算で SSE = 36,680,401、 SST ≈ 315,494,995 だった。 R² はいくつか。
    答:1 − 36,680,401 ÷ 315,494,995 = 0.8837。 平均値だけで当てる場合に比べて、 二乗誤差を約 88% 減らしたという意味になる。
  3. 問:47 県で MAE = 1,199 人、 RMSE = 1,769 人。 全県の残差の絶対値が同じ 1,199 人だったとしたら RMSE はいくつになるか。
    答:1,199 人(RMSE ÷ MAE = 1)。 実際は 1.48 倍なので、 北海道・愛知県・福岡県のように大きく外す県がある。
  4. 問:⚠️ 章の実験で、 564 行を行ごとに分けた KFold の R² = 0.605、 県ごとに分けた GroupKFold の R² = −0.103 だった。 新しい県に当てはめるときの性能として信じてよいのはどちらか。
    答:GroupKFold。 KFold では同じ県の別年度が訓練側に入り、 モデルが「その県の値」を覚えているだけで高く出る。
  5. 問:🔬 章の単回帰 ŷ = −676.9 + 61.04 × 総人口(万人)で、 総人口 53.7 万人の鳥取県の出生数を予測し、 実測 3,263 人との残差を求めよ。
    答:ŷ = −676.9 + 61.04 × 53.7 = 2,601 人、 残差 = 3,263 − 2,601 = +662 人。 人口が最少の県では切片 −676.9 の影響が大きく、 直線は出生数を少なめに見積もる。 当てはめた範囲の端(人口の最少・最大付近)ほど予測は崩れやすい。

🐍 Python 実装例

最小コードで動かしてみる例:

🎯 このコードでやること: 学習用と評価用にデータを分割、モデルを学習、予測を取得、精度を評価。

📥 入力例 # 入力: data/raw/SSDSE-B-2026.csv を header=1(日本語の列名)で読み、最新の 2023 年度に絞る # X: 総人口・65歳以上人口(47 × 2)、 y: 出生数(47,)→ 訓練 37 県 / テスト 10 県
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# ── この抜粋で使うデータを用意します(SSDSE-B の 47 都道府県・最新年度)──
import pandas as pd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1)
df = df[df['地域コード'].astype(str).str.match(r'^R\d{5}$', na=False)].copy()
df['年度'] = pd.to_numeric(df['年度'], errors='coerce')
df = df[df['年度'] == df['年度'].max()]
for _c in ('総人口', '65歳以上人口', '出生数'):
    df[_c] = pd.to_numeric(df[_c], errors='coerce')

# 説明のとおり「総人口・65歳以上人口」から「出生数」を当てにいく
_feats = ['総人口', '65歳以上人口']
df = df.dropna(subset=_feats + ['出生数'])
X = df[_feats].to_numpy(dtype=float)
y = df['出生数'].to_numpy(dtype=float)

import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.model_selection import train_test_split

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
model = GradientBoostingRegressor(n_estimators=200, max_depth=4, random_state=42)
model.fit(X_tr, y_tr)
pred = model.predict(X_te)
rmse = np.sqrt(mean_squared_error(y_te, pred))
print(f'RMSE={rmse:.3f}, R2={r2_score(y_te, pred):.3f}')
📤 実行例(実際に走らせた出力) # 総人口・65歳以上人口 から 出生数 を当てにいった場合 RMSE=11028.872, R2=0.815

💬 読み方: 日本語の列名(header=1)で読んでも、英字コードで読んだ最初の例と同じ 47 県・同じ分割なので、RMSE 11,028.872・R² 0.815 は最初の例と一致する。テスト 10 県の R² 0.815 は、同じ分割で線形回帰に替えた②の 0.982 より低く、200 本の木を重ねた勾配ブースティングでも、人口に比例する関係を 37 県から学ぶのは直線のほうが得意だと分かる。

🐍 Python 実装バリエーション

「回帰タスク」を扱う代表的なライブラリ別実装。 同じ目的でも書き方が違うため、 自分のプロジェクトの依存関係に合わせて選択する:

① pandas + numpy(最小依存)

🎯 このコードでやること: SSDSE-B-2026 を読み込み。

📥 入力例 # 入力: data/raw/SSDSE-B-2026.csv (47都道府県 × 12年。年度で絞って使う) # 2023年度 先頭3行(A1101=総人口, A1303=65歳以上人口, A4101=出生数): # pref A1101 A1303 A4101 # 北海道 5092000 1681000 24430 # 青森県 1184000 417000 5696 # 岩手県 1163000 407000 5432
1
2
3
4
5
6
7
8
9
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]              # 年度で1年分に絞る
df = df.rename(columns={df.columns[2]: 'pref'})

print('行数:', len(df), '列数:', df.shape[1])
print(df[['pref', 'A1101', 'A1303', 'A4101']].head())
📤 実行例 行数: 47 列数: 112 pref A1101 A1303 A4101 0 北海道 5092000 1681000 24430 12 青森県 1184000 417000 5696 24 岩手県 1163000 407000 5432 36 宮城県 2264000 662000 12328 48 秋田県 914000 357000 3611

💬 読み方: skiprows=[1] で日本語ラベル行を除外し、 df[df['SSDSE-B-2026']==2023] で 1 年分に絞り、 encoding='cp932' で文字化けを回避。

② scikit-learn(学習・評価)

🎯 このコードでやること: 学習用と評価用にデータを分割、回帰モデルを学習、予測を取得、精度を評価。

📥 入力例 # 入力: ① で 2023 年度に絞った df # X: A1101・A1303(47 × 2)、 y: A4101(47,)→ 訓練 37 県 / テスト 10 県
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error
from sklearn.model_selection import train_test_split
import numpy as np

X = df[['A1101', 'A1303']].fillna(0).values
y = df['A4101'].values
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
m = LinearRegression().fit(X_tr, y_tr)
pred = m.predict(X_te)
print(f'R²   = {r2_score(y_te, pred):.3f}')
print(f'RMSE = {np.sqrt(mean_squared_error(y_te, pred)):.2f}')
📤 実行例 R² = 0.982 RMSE = 3438.97

💬 同じ 37 県 / 10 県の分割で、線形回帰はテスト R² 0.982・RMSE 3,438.97 人と、冒頭の勾配ブースティング(R² 0.815・RMSE 11,028.87 人)の 3 分の 1 以下の誤差になる。出生数は総人口にほぼ比例するので、直線 1 本のほうが、木の階段状の予測より訓練範囲の端にある大きな県を当てやすい。

③ scipy.stats(統計検定・分布)

🎯 このコードでやること: scipy.stats で、総人口と出生数の Pearson 相関と、県別の出生率(人口千人あたり)の平均が全国値と異なるかの 1 標本 t 検定を行う。

📥 入力例 # 入力: ① で 2023 年度に絞った df の A1101(総人口)と A4101(出生数)、47 行
1
2
3
4
5
6
7
8
9
10
11
12
from scipy import stats

# 例: 2 変数の Pearson 相関 + p 値
r, p = stats.pearsonr(df['A1101'], df['A4101'])
print(f'相関係数 r = {r:.3f}, p 値 = {p:.2e}')

# 例: 1 標本 t 検定(県別の出生率〔人口千人あたり〕の平均が全国値と異なるか)
rate = df['A4101'] / df['A1101'] * 1000
national = df['A4101'].sum() / df['A1101'].sum() * 1000
t, p = stats.ttest_1samp(rate, popmean=national)
print(f'全国の出生率 = {national:.3f}‰, 県別出生率の平均 = {rate.mean():.3f}‰')
print(f't = {t:.3f}, p = {p:.3f}')
📤 実行例 相関係数 r = 0.995, p 値 = 1.53e-47 全国の出生率 = 5.848‰, 県別出生率の平均 = 5.726‰ t = -1.191, p = 0.240

💬 読み方: 総人口と出生数の相関は r = 0.995(p = 1.53e-47)で、出生数を総人口から当てる回帰がよく当たる理由がこれ。一方、県別出生率の平均 5.726‰ は全国値 5.848‰ より低いが、t = −1.191・p = 0.240 で差は有意でない。県の平均が全国値を下回るのは、東京都(6.13‰)・大阪府(6.31‰)・愛知県(6.47‰)・福岡県(6.65‰)など出生率が全国値より高い大きな県が全国値を押し上げ、県を 1 票ずつ数える平均にはそれが効かないため。

④ 可視化(matplotlib + seaborn)

🎯 このコードでやること: 総人口を横軸・出生数を縦軸にした 47 都道府県の散布図を描き、out.png に保存する。

📥 入力例 # 入力: ① で 2023 年度に絞った df の A1101(総人口)と A4101(出生数)、47 行
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots(figsize=(8,5))
sns.scatterplot(data=df, x='A1101', y='A4101', ax=ax)
ax.set_xlabel('総人口')
ax.set_ylabel('出生数')
ax.set_title(f'{len(df)} 都道府県の関係')
plt.tight_layout()
plt.savefig('out.png', dpi=120)
plt.close()
📤 実行例 (明示的な print なし。 Jupyter 上では最終行が表示される)

💬 読み方: このブロックは図を保存するだけで何も表示しない。out.png では東京都(1,408.6 万人・86,348 人)が右上に離れた 1 点になり、残りの県は左下に固まる。r = 0.995 の直線関係でもこの 1 点が回帰直線の傾きを大きく左右するので、東京都を除いた当てはめとも比べておくとよい。

🐍 Python 実装(拡張版)

SSDSE-B-2026(2023年度)で総人口 A1101 から出生数 A4101 の回帰を線形・多項式・RF で比較。 MAE/MSE/R² の 3 指標を併記。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A4101(出生数) 北海道 5,092,000 24,430 東京都 14,086,000 86,348 沖縄県 1,468,000 12,549 …(全 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
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.pipeline import make_pipeline
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]
X = df[['A1101']]   # 総人口
y = df['A4101']     # 出生数
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=42)

models = {
    'Linear': LinearRegression(),
    # 総人口 (〜10^7) の 2 乗は 〜10^14 になるので、展開後に標準化してから回帰する
    'Poly2':  make_pipeline(PolynomialFeatures(2), StandardScaler(), LinearRegression()),
    'RF':     RandomForestRegressor(n_estimators=100, random_state=42),
}
for name, m in models.items():
    m.fit(Xtr, ytr)
    p = m.predict(Xte)
    print(f'{name:6s}: MAE={mean_absolute_error(yte,p):,.0f}  '
          f'MSE={mean_squared_error(yte,p):,.0f}  R²={r2_score(yte,p):.3f}')
📤 実行例: Linear: MAE=1,504 MSE=4,292,054 R²=0.991 Poly2 : MAE=1,621 MSE=6,525,917 R²=0.987 RF : MAE=4,436 MSE=98,186,473 R²=0.801

💬 テスト 15 県で、直線の Linear が MAE 1,504 人・R² 0.991 と最も良く、2 次の項を足した Poly2(MAE 1,621 人)はわずかに悪化、RandomForest は MAE 4,436 人・R² 0.801 と大きく落ちる。木は訓練データにある値の範囲でしか予測できないので、訓練側の最大(神奈川県 922.9 万人)を超えるテスト側の東京都(86,348 人)を 49,963 人と予測し、36,385 人も外してしまう。MSE で見ると RF の 98,186,473 は Linear の約 23 倍で、少数の大きな外れが MSE を押し上げていることが分かる。

R² だけでなく MAE(外れ値に頑健)と MSE(大誤差を強調)を併記する習慣を。 用途次第で「重視する誤差」が異なる。

⚠️ よくある落とし穴

❌ 外挿の危険
学習データの範囲外で予測すると、 線形回帰は無限に伸び続け、 木モデルは端の値で止まる。 どちらも信頼性低し。
❌ 外れ値に弱い
MSE は二乗するため、 外れ値の影響が極端に強い。 Huber 損失や MAE で頑健化、 もしくは前処理で対処。
❌ 目的変数の分布
右に大きく歪んだ分布(収入など)はそのままだと精度低下。 対数変換で正規に近づける。
❌ 特徴量スケール
線形回帰や NN ではスケール差で学習が不安定。 標準化または正規化を行う。
❌ R² だけで判断
$R^2$ は単純比較に良いが、 過学習に気づきにくい。 必ず CV や ホールドアウトで検証。

⚠️ よくある落とし穴(6 件)

「回帰タスク」を実務・試験で扱うときに頻発する典型的なミスです。 各項目を 1 度読んでおけば 9 割の事故が防げます:

❌ 外挿の危険
学習範囲外で線形回帰は無限に伸び、 木モデルは端で止まる。 信頼性低し。
❌ 外れ値に弱い
MSE は二乗するため外れ値の影響大。 Huber 損失や MAE で頑健化。
❌ 目的変数の歪み
収入や売上は右に歪む。 対数変換で正規に近づける。
❌ 特徴量スケール
線形・NN ではスケール差で学習不安定。 StandardScaler などで揃える。
❌ R² だけで判断
R² は単純比較に良いが過学習に気づきにくい。 CV や Holdout で検証。
❌ 残差を見ない
残差プロットで非線形性・分散不均一性を確認。 GLM や非線形モデルへ切替。

⚠️ 実データで確かめる — 分け方ひとつで評価が変わる

回帰タスクの評価値は、 モデルだけでなく「どのデータをテストに回したか」で動く。 47 県しかない断面データと、 同じ県が 12 回出てくるパネルデータのそれぞれで確かめる。

🎯 このコードでやること:2023 年度の 47 県で、 総人口から出生数を当てる線形回帰を、 train_test_split の random_state だけ 0〜19 に変えて 20 回評価し、 テスト R² のばらつきと、 東京都がテスト側に入った回の R² を見る。

📥 入力例 SSDSE-B-2026 の 2023 年度 47 行 X: A1101(総人口, 万人に換算) y: A4101(出生数, 人) 訓練 37 県 / テスト 10 県
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d = df[df['SSDSE-B-2026'] == 2023]                 # 2023 年度の 47 都道府県
X = (d[['A1101']] / 1e4).values                     # 総人口(万人)
y = d['A4101'].values                               # 出生数(人)

scores = []
for seed in range(20):                              # 分け方だけを 20 通りに変える
    X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=seed)
    m = LinearRegression().fit(X_tr, y_tr)
    tokyo_in_test = (X_te.ravel() > 1000).any()     # 東京都(1,408.6 万人)がテスト側か
    scores.append((seed, r2_score(y_te, m.predict(X_te)), tokyo_in_test))

s = pd.DataFrame(scores, columns=['seed', 'R2', 'tokyo_in_test'])
print(s.sort_values('R2').head(3).to_string(index=False))
print(s.sort_values('R2').tail(3).to_string(index=False))
print(f"テスト R² の範囲: {s.R2.min():.3f} 〜 {s.R2.max():.3f}(中央値 {s.R2.median():.3f})")
print(s.groupby('tokyo_in_test').R2.agg(['count', 'median']).round(3))
📤 実行例(実測) seed R2 tokyo_in_test 6 0.815521 False 17 0.891311 False 8 0.954125 False seed R2 tokyo_in_test 18 0.995119 True 3 0.998671 True 19 0.999111 True テスト R² の範囲: 0.816 〜 0.999(中央値 0.989) count median tokyo_in_test False 16 0.984 True 4 0.997

💬 同じモデル・同じデータでも、 テスト R² は 0.816 から 0.999 まで動いた。 東京都がテスト側に入った 4 回は中央値 0.997 と高い。 東京都(出生数 86,348 人)が入るとテスト 10 県の出生数のばらつき(R² の分母)が大きくなり、 同じ程度の外れでも R² が 1 に近づくためである。 47 県で 1 回だけ分けた R² を「このモデルの性能」として報告せず、 交差検証や複数の分け方で幅を示す。

🎯 このコードでやること:年度で絞らない 564 行で、 総人口と高齢化率から合計特殊出生率を当てるランダムフォレストを、 行ごとに分ける KFold と、 県ごとにまとめて分ける GroupKFold で 5 分割評価する。

📥 入力例 SSDSE-B-2026 の 564 行(47 県 × 12 年度) X: A1101(総人口), A1303/A1101(高齢化率) y: A4103(合計特殊出生率) groups: Code(地域コード)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import KFold, GroupKFold, cross_val_score

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
# 年度で絞らず 564 行(47 県 × 12 年度)のまま、 総人口と高齢化率から合計特殊出生率を当てる
X = np.c_[df['A1101'], df['A1303'] / df['A1101']]
y = df['A4103'].values
g = df['Code'].values                                   # 県のコード(グループ)

rf = RandomForestRegressor(n_estimators=200, random_state=0)
r_kf = cross_val_score(rf, X, y, cv=KFold(5, shuffle=True, random_state=0), scoring='r2')
r_gk = cross_val_score(rf, X, y, cv=GroupKFold(5), groups=g, scoring='r2')
print('行数:', len(df), ' 県の数:', len(set(g)))
print(f'KFold(行をばらばらに分割)     R² = {r_kf.mean():.3f}  {np.round(r_kf, 3)}')
print(f'GroupKFold(県ごとまとめて分割) R² = {r_gk.mean():.3f}  {np.round(r_gk, 3)}')
📤 実行例(実測) 行数: 564 県の数: 47 KFold(行をばらばらに分割) R² = 0.605 [0.558 0.75 0.539 0.601 0.578] GroupKFold(県ごとまとめて分割) R² = -0.103 [ 0.124 0.332 -0.517 -0.682 0.226]

💬 KFold の R² は平均 0.605 なのに、 GroupKFold では −0.103(平均値で当てるより悪い)になった。 行ごとに分けると同じ県の別年度が訓練側に残り、 総人口の値から県を特定して「その県の出生率」を返すだけで当たってしまう。 新しい県に使えるかを確かめたいなら、 県を単位に分ける GroupKFold の値を報告する。

🧭 さらに深く — 直感・落とし穴・発展(追補)

本セクションは既出の解説を壊さずに、 回帰タスクの理解を一段深める追補です。 数値はすべて SSDSE-B-2026.csv(2023 年度・47 都道府県、 encoding='cp932'/skiprows=[1])から実測。 例として一貫して 総人口 A1101 → 出生数 A4101 の回帰を使います。 単回帰の全体像は 傾き ≈ 61 人/万人・切片 ≈ −677 人、 R² = 0.991、 MAE = 1,146 人、 RMSE = 1,622 人(47 都道府県・全データ当てはめ)です。

🎨 直感を深める — 「連続値を当てる」とは

回帰は数直線上の一点を指し当てる教師あり学習で、 分類(離散カテゴリの選択)と対をなします。 「予測がどれだけズレたか」を測る物差しが学習時の損失関数で、 主に MSE(二乗誤差)や MAE(絶対誤差)を最小化します。 学習後の成績表にあたるのが評価指標で、 RMSE(誤差の代表的な大きさ・単位が y と同じ)や R²(目的変数の分散の何割を説明できたか)を用います。

実測でつかむ:総人口 → 出生数では RMSE(1,622) が MAE(1,146) より約 4 割大きい(比 ≈ 1.42)。 これは一部に大きな残差があり、 二乗する RMSE がそれを強調するためです。 分類と違い誤差に「大小」があるので、 何人ズレたかをそのまま解釈できるのが回帰の強みです。 損失(学習の目的関数)と評価指標(人間が読む成績)は別物で、 MSE で学習しても評価は MAE で読む、 といった組合せが普通に起きます。

観点回帰タスク分類タスク
出力 $y$連続値(例:出生数 5,432 人)カテゴリ(例:過疎 1/非過疎 0)
代表的な損失MSE・MAE・Huber・分位点損失クロスエントロピー・ヒンジ
代表的な評価RMSE・MAE・R²正解率・F1・AUC
誤りの意味ズレの大きさ(連続)当たり/外れ(離散)

→ 分類との違い・境界は 分類タスク/分類(基礎)、 教師あり学習 を参照。

⚠️ 落とし穴を深める — 実測で見える 8 つの罠

既出の落とし穴を、 SSDSE-B の実測でさらに具体化します。 いずれも「表面の指標が良く見えても危ない」典型です。

❌ ① 外れ値で MSE が歪む
総人口 → 出生数の単回帰で、 残差最大の 北海道(残差 −5,976 人)1 点だけで全 SSE の 28.9%、 次点の沖縄県(+4,265 人)で 14.7% を占めます。 MSE/RMSE は二乗なので少数の外れ値に支配されがち。 MAE や後述の Huber 損失で頑健化するか、 残差診断(残差)で外れ値を特定します。
❌ ② 目的変数の分布の歪み
出生数 A4101 の歪度は 2.29(東京都 86,348 人が突出する右歪み)。 対数変換で歪度は 0.80 まで縮小し、 二乗誤差前提のモデルが扱いやすくなります。 収入・売上・人口系は右に歪みやすく、 対数変換や Box-Cox 変換が定石。 ただし変換後の予測は逆変換で戻す際にバイアスが出る点に注意。
❌ ③ 外挿(学習範囲外)の危険
同じデータで学習・評価しても、 2 次多項式回帰はテスト R² = 0.796(RMSE ≈ 6,853)と、 線形回帰の R² = 0.992(RMSE ≈ 1,336、 7:3 分割・seed 0)より大きく劣化します。 高次項は学習範囲の端で急激に伸び、 東京都のような大人口側で予測が暴走するため。 データ範囲外の外挿は原則避け、 使うなら不確実性を明示します。
❌ ④ 非線形関係を直線で無理に当てる
関係が曲がっているのに直線を当てると、 系統的な当てはめ残しが残ります。 まず残差プロットで曲率を確認し、 曲線が必要なら 木系アンサンブル・GAM・ニューラルネットなど非線形回帰に切り替えます(多項式は外挿に弱い点に注意)。
❌ ⑤ 評価指標の選択(R² の限界)
R² は特徴量を増やすほど必ず上がるため、 変数の数が違うモデルの比較には 自由度調整済み R² を使います。 また R² = 0.99 でも RMSE が業務許容を超えることはあり、 単位付きの誤差(RMSE・MAE)と併読が必須。 n=47 のような小標本では R² も大きくばらつくので、 交差検証で安定性を確認します。
❌ ⑥ 不均質分散(heteroscedasticity)
総人口 → 出生数では、 |残差| と総人口の相関が 0.44。 人口下位半分の平均 |残差| が 713 人なのに対し、 上位半分は 1,597 人(約 2.2 倍)と、 大きい県ほど誤差も大きい。 誤差分散が一定という前提が崩れると、 最小二乗の標準誤差・信頼区間が不正確になります。 対数変換や加重最小二乗、 分位点回帰で対処します。
❌ ⑦ 時系列リーク
SSDSE-B は同じ都道府県が 12 年分並ぶパネルです。 年で絞らず train_test_split のランダム分割をかけると、 同一県の未来年が学習側に混入して評価が過大に楽観化します(データリーク)。 時系列・パネルでは「過去で学習・未来で評価」の時系列分割を用い、 特徴量の作成も評価時点までの情報に限定します。
❌ ⑧ 分類問題を回帰で解く誤り
「過疎 1/非過疎 0」のような 2 値ラベルに線形回帰を当てると、 予測が 0〜1 の外にはみ出し、 確率として解釈できません。 目的変数が順序を持たないカテゴリなら 分類タスク(ロジスティック回帰など)へ。 逆に「1〜5 の満足度」のような順序尺度は、 回帰・順序回帰のどちらが適切か要検討です。

🚀 発展を深める — 手法・損失・変換・評価の引き出し

「線形回帰でとりあえず」から先へ進むための選択肢を、 用途とともに整理します。 本サイトに個別ページがあるものはリンク、 無いものは説明のみです。

カテゴリ選択肢いつ効くか
モデル線形/多項式/木系(GBR・XGBoost)/GAM/NN・MLP・深層解釈重視は線形/GAM、 非線形・表形式は木系、 大規模・複雑は NN
正則化正則化:Ridge(L2)/Lasso(L1)/ElasticNet特徴量が多い・多重共線性・過学習の抑制。 Lasso は特徴選択も
損失関数MSE/MAE/Huber/分位点(pinball)損失外れ値に頑健化したい→Huber・MAE、 上振れ/下振れの非対称コスト→分位点
目的変数変換対数/Box-Cox/Yeo-Johnson右歪み(出生数の歪度 2.29→log 0.80)・不均質分散の緩和。 予測は逆変換で戻す
区間・不確実性分位点回帰(分位点)/予測区間「点」でなく「幅」で答えたい・不均質分散下でも各分位を直接推定
評価RMSE/MAE/R²/調整済み R²/MAPE単位付き誤差で大きさを、 R² で説明力を、 変数数が違えば調整済み R² を
💡 損失と変換の直感
Huber 損失は残差が小さい領域では MSE(二乗)、 大きい領域では MAE(絶対値)のように振る舞い、 外れ値の影響を頭打ちにします。 分位点損失は上振れ・下振れを非対称に罰することで、 中央値(0.5 分位)や 90% 分位など「どのラインを当てたいか」を選べます。 対数変換は乗法的な誤差(〜%)を加法的に均し、 SSDSE の出生数のように桁が大きく違うデータで有効です。

→ 手法の全体像は 木系アンサンブル・ランダムフォレスト・正則化、 評価は 評価指標・MSE・RMSE・R² を参照。

🗺 概念マップ

下の図は中心に「回帰タスク」を置き、 周りに 6 つの要素を並べたもの。 目的変数(連続値) は回帰タスクであることを決める条件で、 同じ出生数でも「1 万人を超えるか」に変えると 対比:分類タスク になる。 モデルの側は、 このページの手計算で使った 線形回帰 / OLS、 係数を縮める Ridge / Lasso、 非線形を拾う 木系:XGBoost の 3 つ。 どれを選んでも最後は 評価:RMSE / MAE で比べる。 🧮 章の 6 県の例(MAE 1,910.5 人・RMSE 2,472.53 人)と 47 県の例(MAE 1,199 人・RMSE 1,769 人)は、 この「評価」の枝の具体例にあたる。

回帰タスク 目的変数 (連続値) 線形回帰 / OLS Ridge / Lasso 評価: RMSE / MAE 木系: XGBoost 対比: 分類タスク

🔗 隣接手法への橋渡し

「回帰タスク」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。

「出生数を予測する」「家賃を予測する」「商品売上を予測する」など、 連続値を当てる 問題は機械学習タスクの代表格であり、 線形〜深層モデルまで広範な手法が選べる。

🌳 手法選択フロー

「回帰タスク」を機械学習プロジェクトに位置づけるとき、 目的変数の性質と評価指標で判定する。

  1. 目的変数は連続値か離散値か? 売上額・気温・人口のような連続値 → 回帰タスク。 購入有無・カテゴリ → 分類タスク。 順序付きカテゴリ → 順序回帰
  2. 線形関係を仮定できるか? 散布図がほぼ直線 → 線形回帰 や Ridge。 非線形パターン → 決定木・Random Forest・XGBoost
  3. 誤差の大きさをどう測るか? 外れ値を強く罰したい → RMSE。 中央値的に評価したい → MAE。 相対誤差を見たい → MAPE。 説明力を見たい → R²

SSDSE-B-2026 で「都道府県別の出生数を予測する」は典型的な回帰タスク。 まず散布図で線形性を確認し、 線形回帰でベースラインを作ってから木系モデルで非線形を捉えるのが標準ワークフロー。