このページの主要な見どころ。 気になる項目から読み始めてください。
回帰分析は「応答変数 y を説明変数 X で表現する関数 f を、データから推定する」分析手法の総称。
y = β₀ + β₁x₁ + ⋯ + βₚxₚ + ε論文・実務レポート・公的統計の解説で、 こんな場面に出会ったはずです。
この「応答変数 = β₀ + β₁ × 説明変数₁ + … + ε」という形式と、 係数の符号・大きさ・有意性を読む文化が、 回帰分析の中核です。 ページでは「式」「推定」「解釈」「落とし穴」を順に整理します。
回帰分析の発想は 「散布図に線を引くと何が見えるか」 から始まります。 SSDSE-B 2023 の 47 都道府県データで、横軸=高齢化率、縦軸=人口千人あたり死亡率 を取ると、 点はほぼ右上がりの直線に並びます。 この「直線」を式で書いたものが回帰モデルです。
関数の形を 線形に限定すれば単回帰/重回帰、 リンク関数を介して非線形にすればロジスティック回帰などになります。 共通するのは「残差の二乗和 (またはマイナス対数尤度) を最小化して、最良の係数を見つける」最適化問題だという点です。
つまり回帰分析は 「データに最もよくフィットする関数を、ある族 (family) の中から選ぶ」 手続きであり、 関数族と誤差分布の選び方で多様な手法へ枝分かれします。
| 用途 | 目的 | SSDSE-B での例 |
|---|---|---|
| 予測 (prediction) | 新しい X から y を当てる | 高齢化率 40% の仮想県の死亡率を予測 |
| 説明 (inference) | X の効果を解釈 | 「高齢化率 1pp で死亡率は約 0.86 上昇」 |
| 因果 (causal) | X→y の因果効果 | ※ 観察データだけでは原則できない(IV・実験設計が必要) |
OLS では、 候補となる直線群のうち 残差の二乗和を最小化する ものを選びます。 残差とは「データ点と直線の縦方向の差」。 これを各点で計算し、 二乗して足し合わせ、 その合計を最小化する係数 $\hat{\beta}_0, \hat{\beta}_1$ を求めるのが OLS のすべてです。
「なぜ二乗?」 → 残差の符号を消すため、 かつ大きい残差をより重く罰するため。 「なぜ和?」 → 全データに均等に責任を持たせるため。 数理的にも閉形式解が得られて扱いやすい、 という工学的な利点もあります。
最も基本の 線形回帰モデル:
行列形式:
最小二乗推定量 (OLS):
一般化線形モデル (GLM) はリンク関数 $g$ を介して
と書ける拡張で、$g$=恒等→線形回帰、$g$=logit→ロジスティック回帰、$g$=log→ポアソン回帰となります。 当てはまりの指標は決定係数 $R^2$ と調整済み $R^2_{\text{adj}}$:
係数の標準誤差は
個別係数の t 統計量:$t_j = \hat{\beta}_j / \mathrm{SE}(\hat{\beta}_j)$、 これが自由度 $n - p - 1$ の t 分布に従うことを利用して、 仮説 $H_0: \beta_j = 0$ を検定します。
| 記号 | 意味 | SSDSE-B での例 |
|---|---|---|
| $y_i$ | 応答変数の i 番目の観測値 | i=秋田県 の死亡率 19.17 |
| $x_{ij}$ | 説明変数 j の i 番目の観測値 | i=秋田県, j=高齢化率 で 39.06 |
| $\beta_0$ | 切片。説明変数がすべて 0 のときの y の予測値 | 解釈に意味があるかは要注意(外挿) |
| $\beta_j$ | 偏回帰係数 | 高齢化率が 1pp 上がると死亡率は 0.86 上昇 |
| $\varepsilon_i$ | 誤差項 | 沖縄県のように特殊な県の残差は大きい |
| $\hat{y}_i$ | 予測値 | i=秋田 の予測死亡率は 19.99 |
| $r_i = y_i - \hat{y}_i$ | 残差 | 沖縄は予測より低めに出る |
| $R^2$ | 決定係数 | 高齢化率→死亡率では 0.944 |
| $\mathrm{SE}(\hat{\beta}_j)$ | 係数の標準誤差 | 不確実性の大きさ |
| $t_j$ | 係数の t 統計量 | OLS 出力の t-value 列 |
「係数の大小」と「有意性 (p 値)」と「当てはまりの良さ ($R^2$)」は別物。 すべてセットで報告するのが原則です。
「$\beta_j$ は、 他の説明変数を固定したまま $x_j$ を 1 単位増やしたときの、 y の予測値の変化量」が教科書的な定義。 「他の説明変数を固定」というのが重要で、 重回帰では別の変数を取り除いた残差の上で計算される値(Frisch–Waugh–Lovell の定理)と一致します。
たとえば SSDSE-B で 「高齢化率と消費支出」 が同時に説明変数のとき、 高齢化率の偏回帰係数は「消費支出が同じ県同士で比べたとき、 高齢化率が 1pp 違うと死亡率がいくつ違うか」を表します。 純粋な「高齢化率 vs 死亡率」の散布図の傾きとは数値が一致しません。
SSDSE-B 2023 の 47 都道府県で、応答変数 y = 死亡率(人口千人あたり)、説明変数 x = 高齢化率(%)の単回帰を実行すると:
| 項目 | 値 | 解釈 |
|---|---|---|
| $\hat{\beta}_0$ (切片) | −13.49 | 高齢化率 0% の架空県の死亡率(外挿で意味薄) |
| $\hat{\beta}_1$ (傾き) | +0.857 | 高齢化率が 1pp 上がると死亡率は 0.86 上昇 |
| 標準誤差 SE(β₁) | 0.0312 | 係数のばらつきの推定 |
| t 統計量 (β₁) | 27.45 | 圧倒的に大きい |
| p 値 (β₁) | < 0.001 | 「偶然 0」とは到底考えられない |
| $R^2$ | 0.944 | 死亡率の分散の 94.4% を説明 |
| 調整済み $R^2$ | 0.943 | 説明変数 1 個ではほぼ同じ |
| 相関 r | +0.972 | 非常に強い正の相関 |
「高齢化率 39.06% の秋田県」の死亡率予測値は $\hat{y} = -13.49 + 0.857 \times 39.06 \approx 19.99$ で、 実測 19.17 とほぼ一致。 残差は約 −0.82 と小さくなります。
| モデル | 説明変数 | $R^2$ | 調整済み $R^2$ |
|---|---|---|---|
| 単回帰 | 高齢化率のみ | 0.944 | 0.943 |
| 重回帰 A | 高齢化率 + 出生率 | 0.951 | 0.949 |
| 重回帰 B | 高齢化率 + 出生率 + 合計特殊出生率 | 0.952 | 0.948 |
| 重回帰 C(4 変数) | 高齢化率 + 出生率 + 合計特殊出生率 + 転入超過率 | 0.954 | 0.948 |
説明変数を増やしても $R^2$ はわずかしか伸びず、 調整済み $R^2$ はモデル B 以降でかえって伸び悩み・低下。 「説明変数を盛れば必ず良くなる」わけではないことが、 実データできちんと再現できます。
| 順位 | 都道府県 | 実測死亡率 | 予測死亡率 | 残差 |
|---|---|---|---|---|
| 1 | 沖縄県 | 9.45 | 11.81 | −2.36 |
| 2 | 愛知県 | 10.74 | 12.99 | −2.25 |
| 3 | 滋賀県 | 10.94 | 13.39 | −2.45 |
沖縄県の死亡率が「予測より低い」のは、 平均寿命の高さなど高齢化率では説明できない要因の存在を示唆しています。 これらの残差の県別パターンを見ることが、 次の研究テーマを発見する第一歩になります。
SSDSE-B 2023 データを使って単回帰と重回帰を実行:
import pandas as pd
# SSDSE-B-2026 を読み込み(年度別 47 都道府県、 最新は 2023 年度)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis', skiprows=1)
df.columns = [c.strip() for c in df.columns]
df = df[df['年度'] == 2023].reset_index(drop=True)
print(df.shape) # (47, 112)
print(df['都道府県'].nunique()) # 47
print(df.iloc[:3, :5])
応答変数と説明変数を作る:
# 主要指標を計算 df['死亡率'] = df['死亡数'] / df['総人口'] * 1000 # 人口千人あたり df['出生率'] = df['出生数'] / df['総人口'] * 1000 df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100 df['若年人口比率'] = df['15歳未満人口'] / df['総人口'] * 100 df['転入超過率'] = (df['転入者数(日本人移動者)'] - df['転出者数(日本人移動者)']) / df['総人口'] * 1000 print(df[['都道府県','高齢化率','出生率','死亡率','転入超過率']].head()) print(df[['高齢化率','出生率','死亡率']].describe().round(2))
単回帰(statsmodels で詳細な統計量を取得):
import statsmodels.api as sm X = sm.add_constant(df['高齢化率']) model = sm.OLS(df['死亡率'], X).fit() print(model.summary()) # Intercept = -13.49, 高齢化率の係数 = 0.857 # R-squared = 0.944, t-value ≈ 27.4, p < 0.001
重回帰と多重共線性チェック:
from statsmodels.stats.outliers_influence import variance_inflation_factor
X = df[['高齢化率', '出生率', '合計特殊出生率']]
X = sm.add_constant(X)
model = sm.OLS(df['死亡率'], X).fit()
print(model.summary())
# VIF(10 を超えると多重共線性の疑い)
for i, name in enumerate(X.columns):
print(name, round(variance_inflation_factor(X.values, i), 2))scikit-learn で予測・残差プロット:
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
X = df[['高齢化率']].values
y = df['死亡率'].values
reg = LinearRegression().fit(X, y)
y_pred = reg.predict(X)
resid = y - y_pred
print('intercept:', round(reg.intercept_, 3), 'coef:', round(reg.coef_[0], 3))
print('R^2:', round(reg.score(X, y), 4))
print('秋田県(39.06%) の予測:', round(reg.predict([[39.06]])[0], 2))
# 残差プロット
fig, ax = plt.subplots(figsize=(6,4))
ax.scatter(y_pred, resid)
ax.axhline(0, color='gray', linestyle='--')
ax.set_xlabel('予測死亡率'); ax.set_ylabel('残差')
ax.set_title('残差プロット(SSDSE-B 2023, n=47)')
plt.tight_layout()
plt.savefig('residual_plot.png', dpi=120)標準化偏回帰係数で「どの変数が効くか」を比較:
from sklearn.preprocessing import StandardScaler
X_raw = df[['高齢化率', '出生率', '合計特殊出生率']].values
y = df['死亡率'].values
scaler = StandardScaler()
X_std = scaler.fit_transform(X_raw)
reg_std = LinearRegression(fit_intercept=False).fit(X_std, (y - y.mean()) / y.std())
for name, coef in zip(['高齢化率','出生率','合計特殊出生率'], reg_std.coef_):
print(f'{name}: 標準化偏回帰係数 = {coef:+.3f}')
# 各係数の絶対値の大きさで「効きの強さ」を比較できる係数の信頼区間と予測区間:
X = sm.add_constant(df['高齢化率'])
model = sm.OLS(df['死亡率'], X).fit()
print('95% CI for coefficients:')
print(model.conf_int(0.05))
# 個別予測の 95% 区間
pred = model.get_prediction(X)
summary_frame = pred.summary_frame(alpha=0.05)
print(summary_frame.head())
# mean_ci_lower / upper: 回帰直線の信頼区間
# obs_ci_lower / upper: 個別観測の予測区間回帰分析 を SSDSE-B 都道府県データで実演するため、 まず基礎指標を作ります。 47 都道府県 × 年度別の家計・人口・教育・医療指標が 100+ 含まれる総合データセットです。
import pandas as pd
# SSDSE-B-2026 を読み込み(年度別 47 都道府県、 最新は 2023 年度)
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='shift_jis', skiprows=1)
df.columns = [c.strip() for c in df.columns]
df = df[df['年度'] == 2023].reset_index(drop=True)
print(df.shape) # (47, 112)
print(df['都道府県'].nunique()) # 47
print(df.iloc[:3, :5])
応答変数になりうる「人口千人あたり死亡率」「人口千人あたり出生率」「高齢化率」「若年比率」「転入超過率」などを派生:
# 主要指標を計算 df['死亡率'] = df['死亡数'] / df['総人口'] * 1000 # 人口千人あたり df['出生率'] = df['出生数'] / df['総人口'] * 1000 df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100 df['若年比率'] = df['15歳未満人口'] / df['総人口'] * 100 df['転入超過率'] = (df['転入者数(日本人移動者)'] - df['転出者数(日本人移動者)']) / df['総人口'] * 1000 print(df[['都道府県','高齢化率','出生率','死亡率','転入超過率']].head()) print(df[['高齢化率','出生率','死亡率']].describe().round(2))
続いて散布図で関係性の俯瞰:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(7,5))
ax.scatter(df['高齢化率'], df['死亡率'], s=40, alpha=0.7)
for _, row in df.iterrows():
ax.annotate(row['都道府県'], (row['高齢化率'], row['死亡率']),
fontsize=8, alpha=0.6)
ax.set_xlabel('高齢化率 (%)')
ax.set_ylabel('死亡率(人口千人あたり)')
ax.set_title('SSDSE-B 2023: 高齢化率 × 死亡率(47 都道府県)')
plt.tight_layout()
plt.savefig('aging_vs_mortality.png', dpi=120)
回帰分析 の結果を読み解く際は、 単純な散布図とヒストグラムを必ず添えるのが鉄則です。 47 都道府県のような小サンプルでは、 平均だけでなく 分布の形状・外れ値の位置 を見せることで、 議論の透明性が大きく上がります。
import seaborn as sns
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# 1) ヒストグラム
axes[0].hist(df['高齢化率'], bins=15, edgecolor='black')
axes[0].set_title('高齢化率の分布 (n=47)')
axes[0].set_xlabel('高齢化率 (%)')
# 2) 箱ひげ図
axes[1].boxplot([df['出生率'], df['死亡率']],
labels=['出生率', '死亡率'])
axes[1].set_title('出生率 vs 死亡率(人口千人)')
# 3) 散布図 + 回帰直線
sns.regplot(x='高齢化率', y='死亡率', data=df, ax=axes[2], ci=95)
axes[2].set_title('高齢化率 vs 死亡率(95% CI 付き)')
plt.tight_layout()
plt.savefig('eda_visuals.png', dpi=120)これらの図に都道府県名のラベルを少なくとも 5 件ほど添えることで、 「どの県が外れ値か」を読み手と共有できます。 SSDSE-B 解析では 沖縄県・東京都・秋田県 が外れ値になりやすいので、 これら 3 県を最低限ラベリングすると親切です。
encoding='shift_jis' を忘れずに。skiprows=1 で日本語列名行から読み込む。df['年度']==2023 で 47 行に絞る。pd.to_numeric(errors='coerce') で数値化前にチェック。論文・実務報告での書き方例:
テンプレに従って、 (1) データ・サンプル数、 (2) 推定値・不確実性、 (3) 解釈の限界、 を必ず記載することが、 査読・レビューで通る最低ラインです。
SSDSE-B 2023(47 都道府県、 112 列)を題材に、 回帰分析 の関連分析でしばしば登場する処理を一通り辿ります。 ここはデータ前処理の典型パターンを覚える目的でもあります。
SSDSE-B はパネルデータなので、 まず分析対象年度を絞ります。 多くの集計指標は実数(千人・件数)で記録されており、 比較のために 人口で割って比率 にすると、 県ごとの大小に左右されずに済みます。
# 年度別の行数と県数
print(df.groupby('年度').size())
print(df.groupby('年度')['都道府県'].nunique()) # 各年 47 のはず
# 2023 年に絞り、 比率系を作る
df = df[df['年度'] == 2023].reset_index(drop=True)
df['食料費比率'] = df['食料費(二人以上の世帯)'] / df['消費支出(二人以上の世帯)']
df['住居費比率'] = df['住居費(二人以上の世帯)'] / df['消費支出(二人以上の世帯)']
df['教育費比率'] = df['教育費(二人以上の世帯)'] / df['消費支出(二人以上の世帯)']
print(df[['都道府県','食料費比率','住居費比率','教育費比率']].head())# どの列に欠損があるか nulls = df.isnull().sum() print(nulls[nulls > 0]) # 数値列の型 print(df.select_dtypes(include='number').dtypes.head(10))
# 食料費比率の上位/下位 5 県 print(df.nlargest(5, '食料費比率')[['都道府県','食料費比率']]) print(df.nsmallest(5, '食料費比率')[['都道府県','食料費比率']]) # 標準化スコアで外れ値検出 df['food_z'] = (df['食料費比率'] - df['食料費比率'].mean()) / df['食料費比率'].std() print(df[df['food_z'].abs() > 2][['都道府県','食料費比率','food_z']])
vars_ = ['食料費比率','住居費比率','教育費比率','高齢化率','出生率','死亡率'] df['高齢化率'] = df['65歳以上人口'] / df['総人口'] * 100 df['出生率'] = df['出生数'] / df['総人口'] * 1000 df['死亡率'] = df['死亡数'] / df['総人口'] * 1000 print(df[vars_].corr().round(2)) # pairplot で散布図行列 import seaborn as sns sns.pairplot(df[vars_])
たとえば「食料費比率は高齢化率と正の相関がある」という仮説を、 ピアソン相関と簡単な回帰でチェックします:
from scipy import stats
r, p = stats.pearsonr(df['食料費比率'], df['高齢化率'])
print(f'食料費比率 vs 高齢化率: r = {r:.3f}, p = {p:.4f}')
import statsmodels.api as sm
X = sm.add_constant(df['高齢化率'])
mod = sm.OLS(df['食料費比率'], X).fit()
print(mod.summary().tables[1])このような一連の流れは、 ほぼ全ての SSDSE-B 分析で再利用できます。 回帰分析 を扱うときも、 この骨格に沿って準備を進めると安全です。
回帰分析 の発想や定式化は、 回帰モデル の枠を超えて、 多くの応用分野で形を変えて登場します。 ここでは代表的な対応関係を整理します。
| 分野 | 類似概念・対応する道具 | 例 |
|---|---|---|
| 経済学 | 需給・効用最大化・回帰モデル | 賃金関数・需要関数の推定 |
| 疫学・公衆衛生 | リスク比・オッズ比・コホート研究 | 喫煙と疾患リスクの関係 |
| 機械学習 | 教師あり学習・特徴量重要度 | 線形モデル・木モデル・NN |
| マーケティング | 顧客生涯価値・チャネル寄与度 | 広告効果のアトリビューション |
| 製造業 | SPC・ロバストデザイン | 歩留まり要因の特定 |
| 政策評価 | 因果推論・準実験 | SSDSE-B を使った県別効果推定 |
「回帰分析」は単独の手法ではなく、 多くの分析の 共通言語 として位置づけられます。 用語自体を覚えるよりも、 「どんな場面でこの考え方が顔を出すか」を蓄積していくと、 応用が利きやすくなります。
回帰分析 を扱う前後で確認すべきポイント:
| 分野 | 応答変数 y | 説明変数 X の例 |
|---|---|---|
| 経済・人口 | 地域の死亡率・出生率 | 高齢化率・所得・医療資源 |
| 教育 | 進学率 | 世帯所得・学校数・地域 |
| マーケティング | 購買金額 | 年齢・性別・過去履歴 |
| 製造業 | 歩留まり | 温度・圧力・原料 |
| 医療 | 血圧・血糖値 | 年齢・BMI・運動量 |
| SSDSE-B 都道府県分析 | 食料費比率 | 所得水準・気温・年齢構成 |
共通するのは 「ある結果指標を、 複数の説明変数で予測・解釈したい」 という発想。 回帰分析は科学・実務の最も基本的なデータ要約ツールであり、 機械学習へ進む前提でもあります。
回帰分析の起源は Francis Galton (1822–1911) による「親子の身長」研究 (1886) に遡ります。 Galton は「背の高い親の子は、 親より平均に近い背丈になる」現象を発見し、 これを "regression toward the mean"(平均への回帰)と呼びました。 これが "regression" という名称の起源です。
その後、 Karl Pearson による相関係数・R. A. Fisher による分散分析・最小二乗法の確立を経て、 20 世紀後半には Nelder & Wedderburn (1972) の一般化線形モデル (GLM) として拡張されました。 21 世紀のいまは、 機械学習の ペナルティ付き回帰 (Ridge, Lasso, Elastic Net)・ベイズ回帰・カーネル法 など、 多くの発展系を持っています。
SSDSE-B のような公的統計分析では、 古典的な OLS と GLM が引き続き主役。 過学習や多重共線性に注意しつつ、 解釈可能性を重視する文化が続いています。
| 段階 | 確認項目 |
|---|---|
| 事前 | 応答変数の尺度(量的か質的か)/ 欠損値の有無/ 外れ値の予備チェック |
| 事前 | 説明変数の単位の確認(標準化が必要か) |
| 事前 | サンプル数 n vs 説明変数 p の比(経験則: n ≥ 10p) |
| 推定後 | 係数の符号・大きさ・有意性 |
| 推定後 | R² と 調整済み R² の差(過学習の兆候) |
| 推定後 | 残差プロット(パターン・不均一分散) |
| 推定後 | VIF(多重共線性) |
| 推定後 | 残差の正規性(QQ プロット) |
| 解釈 | 因果ではなく条件付き相関の解釈に留める |
| 報告 | 係数・SE・p 値・R² ・サンプル数・前処理の方針 |