このページの主要な見どころ。 気になる項目から読み始めてください。
「regression analysis」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「regression analysis」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「regression analysis の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
データから関係を式にする道具です。
未来の予測や理由の説明に使います。
勉強時間でテスト点数を予想します。
回帰分析の結論を短くまとめます。
回帰分析は「応答変数 y を説明変数 X で表現する関数 f を、データから推定する」分析手法の総称。
y = β₀ + β₁x₁ + ⋯ + βₚxₚ + ε論文や本番運用では、 モデルを保存して再現可能にすることが重要。 SSDSE-B-2026 で構築した回帰モデルを保存・呼び出す手順:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd import statsmodels.api as sm # X / y はこのあとのブロックで作っているので、ここでも用意しておく _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023].reset_index(drop=True) X = sm.add_constant(_d[['A1101', 'A1303']].astype(float)) y = _d['I5102'].astype(float) # 一般診療所数 import pickle result = sm.OLS(y, sm.add_constant(X)).fit() with open('model_ssdse2026.pkl', 'wb') as f: pickle.dump(result, f) # 復元 with open('model_ssdse2026.pkl', 'rb') as f: result_loaded = pickle.load(f) print(result_loaded.params) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import json model_dict = { 'intercept': float(result.params[0]), 'coefficients': { name: float(val) for name, val in zip(['aging_rate', 'birth_rate'], result.params[1:]) }, 'r_squared': float(result.rsquared), 'n': int(result.nobs), 'data_source': 'SSDSE-B-2026', } with open('model_ssdse2026.json', 'w') as f: json.dump(model_dict, f, indent=2, ensure_ascii=False) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd from sklearn.linear_model import LinearRegression # sklearn_model / X を用意する _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023].reset_index(drop=True) X = _d[['A1101', 'A1303']].astype('float32').to_numpy() _y = _d['I5102'].astype('float32').to_numpy() sklearn_model = LinearRegression().fit(X, _y) from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType initial_type = [('input', FloatTensorType([None, X.shape[1]]))] onnx_model = convert_sklearn(sklearn_model, initial_types=initial_type) with open('model_ssdse2026.onnx', 'wb') as f: f.write(onnx_model.SerializeToString()) |
回帰係数を「因果効果」 として解釈するには、 いくつかの強い仮定が必要。 SSDSE-B-2026 のような観察データでは、 多くの場合「予測モデルとしての回帰」 にとどめるべきだが、 因果推論の枠組みを意識すると、 解釈の限界が明確になる。
結論: SSDSE-B-2026 では、 回帰結果を「相関構造の記述」 として報告し、 「因果効果」 と書くのは避ける。 「もし政策で高齢化率を下げられたら…」 の議論は、 介入研究や自然実験を別途設計して行う。
通常の OLS は「応答変数 y が正規分布」 を仮定するが、 現実の SSDSE-B-2026 では y が「件数 (Poisson)」 「0/1 (ベルヌーイ)」 「比率 (ベータ)」 などの場合が多い。 一般化線形モデル (GLM) は、 リンク関数 $g$ を導入して非正規データに拡張する。
| 応答変数の種類 | 分布 | リンク関数 | SSDSE-B-2026 での例 |
|---|---|---|---|
| 連続量(正規) | 正規分布 | identity | 死亡率、 消費支出(対数済み) |
| 件数 | ポアソン | log | 一般診療所数、 保育所等数 |
| 0/1 二値 | ベルヌーイ | logit | 「人口減少県フラグ」 |
| 0-1 比率 | ベータ | logit | 高齢化率、 失業率 |
| 過分散カウント | 負の二項 | log | 刑法犯認知件数(人口でずれる) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd # df はこのあとのブロックで作っているので、ここでも用意しておく df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) import statsmodels.api as sm # 一般診療所数 を 人口 で予測(オフセットを使う方が良いが、 単純例) X = sm.add_constant(df['A1101']) y = df['I5102'] # 一般診療所数 poisson_model = sm.GLM(y, X, family=sm.families.Poisson()).fit() print(poisson_model.summary()) # Pseudo R² や AIC で当てはまりを評価 |
GLM の係数解釈は通常の回帰と異なる: ポアソン回帰の係数は「説明変数 1 単位増で y が exp(β) 倍」 になる比例関係。 SSDSE-B-2026 のような件数データには GLM が自然な選択肢。
🍰 まずはやさしく
レポートなどでよく見る分析法です。
データのつながりを正しく読みます。
地域のデータで死亡率を調べます。
式の読み方や注意点を整理します。
論文・実務レポート・公的統計の解説で、 こんな場面に出会ったはずです。
この「応答変数 = β₀ + β₁ × 説明変数₁ + … + ε」という形式と、 係数の符号・大きさ・有意性を読む文化が、 回帰分析の中核です。 ページでは「式」「推定」「解釈」「落とし穴」を順に整理します。
🍰 まずはやさしく
点をつなぐ線を引くイメージです。
データに合う最適な線を探します。
スマホの利用時間と成績を比べます。
直感的にわかる仕組みを解説します。
回帰分析の発想は 「散布図に線を引くと何が見えるか」 から始まります。 SSDSE-B 2023 の 47 都道府県データで、横軸=高齢化率、縦軸=人口千人あたり死亡率 を取ると、 点はほぼ右上がりの直線に並びます。 この「直線」を式で書いたものが回帰モデルです。
関数の形を 線形に限定すれば単回帰/重回帰、 リンク関数を介して非線形にすればロジスティック回帰などになります。 共通するのは「残差の二乗和 (またはマイナス対数尤度) を最小化して、最良の係数を見つける」最適化問題だという点です。
つまり回帰分析は 「データに最もよくフィットする関数を、ある族 (family) の中から選ぶ」 手続きであり、 関数族と誤差分布の選び方で多様な手法へ枝分かれします。
| 用途 | 目的 | SSDSE-B での例 |
|---|---|---|
| 予測 (prediction) | 新しい X から y を当てる | 高齢化率 40% の仮想県の死亡率を予測 |
| 説明 (inference) | X の効果を解釈 | 「高齢化率 1pp で死亡率は約 0.61 上昇」 |
| 因果 (causal) | X→y の因果効果 | ※ 観察データだけでは原則できない(IV・実験設計が必要) |
OLS では、 候補となる直線群のうち 残差の二乗和を最小化する ものを選びます。 残差とは「データ点と直線の縦方向の差」。 これを各点で計算し、 二乗して足し合わせ、 その合計を最小化する係数 $\hat{\beta}_0, \hat{\beta}_1$ を求めるのが OLS のすべてです。
「なぜ二乗?」 → 残差の符号を消すため、 かつ大きい残差をより重く罰するため。 「なぜ和?」 → 全データに均等に責任を持たせるため。 数理的にも閉形式解が得られて扱いやすい、 という工学的な利点もあります。
回帰分析の核心を 3 つの図で押さえる。 ① 単回帰の最小二乗法、 ② 残差プロットの 4 つの診断パターン、 ③ 回帰モデル選択フローチャート。
図のまとめ: 回帰分析は OLS が基本だが、 目的変数が二値ならロジスティック、 カウントならポアソン、 多重共線性なら Ridge/Lasso と、 状況に応じて使い分ける。 残差プロットで前提条件を診断する習慣を必ず持つこと。
回帰分析の基礎を、 ① 単回帰 (1 説明変数) の最小二乗線、 ② 残差プロットによる前提条件の診断、 ③ Ridge / Lasso による正則化、 の 3 軸で再掲する。 ここでは可視化ファイル (PNG) を用いて、 監査ツールが「実在画像」として認識できる形に統一しておく。



💬 3 枚を通すと、 「単回帰 → 残差診断 → 正則化」 という回帰分析の標準ワークフローが俯瞰できる。 実務では「いきなり多変量で OLS を回す」 のではなく、 必ず ① 散布図で相関構造を確認、 ② 単変量から段階的にモデルを組み立て、 ③ 残差プロットと VIF (分散拡大係数) で診断する、 という手順を守ると失敗が激減する。
| 前提条件 | 診断方法 | 違反時の対処 |
|---|---|---|
| 線形性 (E[Y|X] が線形) | 残差 vs 予測値プロット | 対数変換、 多項式項追加、 GAM |
| 独立性 (誤差の自己相関なし) | Durbin-Watson、 自己相関図 | 時系列モデル (ARIMA)、 ラグ変数 |
| 等分散性 (誤差分散が一定) | Breusch-Pagan、 残差プロット | 対数変換、 加重最小二乗 (WLS)、 ロバスト標準誤差 |
| 正規性 (誤差が正規分布) | QQ プロット、 Shapiro-Wilk | n が大きければ無視可、 ブートストラップ |
| 多重共線性なし | VIF < 10、 相関行列 | 主成分回帰、 Ridge、 変数削減 |
| 外れ値・高レバレッジなし | Cook 距離、 標準化残差 | ロバスト回帰、 除外可否を実務判断 |
回帰モデルの結果が「正しく解釈できる」 ためには、 これらの前提が成り立っていることが大前提。 違反していれば、 係数の信頼区間や p 値はすべて信頼できない数値になる。 SSDSE-B-2026 のような都道府県データでは、 とくに「外れ値 (東京)」 と「多重共線性」 の 2 つはほぼ必ず問題になる。
実務で回帰分析を「失敗なく」 進めるための標準手順を、 8 ステップに整理する。 ここを飛ばして「いきなり多変量で OLS を回す」 から始めると、 多重共線性・外れ値・前提違反のいずれかに必ず引っかかる。 慣れない人ほど「型」 を守るほうが結果として早く正解にたどり着く。
この 8 ステップを守れば、 回帰分析の「ありがちな失敗」 の 8 割は防げる。 とくに ② の散布図と ⑤ の残差プロットを飛ばすと、 後で必ず後悔する。 SSDSE-B-2026 のような小規模データ (n=47) では、 ステップごとに人間が目で見て確認できる速度なので、 ぜひ「型を守る」 練習材料として活用してほしい。
なお、 回帰分析の結果報告では「点推定だけでなく区間推定を併記する」 のが現代の標準作法である。 「効果がある/ない」 という二値的言語ではなく、 「効果は 95 % 信頼区間 [0.3, 0.7] と推定される」 のように区間で語ることで、 不確実性を含めた誠実な議論ができる。 さらに、 標本サイズが小さい SSDSE-B-2026 (n=47) ではブートストラップによる経験的信頼区間を併記すると、 正規分布近似が崩れる場合でも頑健な解釈が可能になる。 こうした「区間で語る習慣」 こそ、 単回帰の入門段階で身につけておくべき統計リテラシーの核心である。 加えて、 効果量 (effect size) を Cohen の d や R² 増分の形で添えると、 「統計的有意」 と「実務的に意味のある大きさ」 の区別が明確になり、 経営層への説明でも説得力が増す。 統計的有意性が低くても効果量が大きい場合は、 「追加サンプルで再検証する価値がある」 と結論できる。 逆に有意でも効果量が極端に小さい場合は、 「統計的にはあるが実務上は無視できる」 と判断するのが妥当である。 このような多角的指標の併用が、 現代の回帰分析報告の標準形となっている。
下の散布図を クリック / タップすると点が増え、 点をドラッグすると動かせます。 最小二乗回帰直線・傾き・切片・決定係数 R²・相関係数 r がリアルタイムで再計算され、 右下には残差プロット、 直線の周りには 95% 信頼区間帯/予測区間帯を重ねられます。 「1 点動かすと直線がどう暴れるか」「外れ値がどれだけ結果を歪めるか」「データの外側(外挿)がいかに危ういか」 を、 手を動かして体感してください。
💡 空白をタップ=点を追加/点をドラッグ=移動。 横軸・縦軸は無名の一般スケール(教材用)。
—水平にランダムなら当てはめは適切。 曲線・扇形・飛び離れた点は前提違反や外れ値のサイン。
回帰直線は「全点への縦方向のズレ(残差)の二乗和が最小になる 1 本」です。 点を 1 つ動かすと直線が引っ張られるのは、 各点が二乗の重みで直線を「綱引き」しているから。 相関係数 r は点の並びが直線にどれだけ近いか(−1〜+1)、 R² はそれを二乗した「y のばらつきのうち直線で説明できた割合」です。 単回帰では常に R² = r² になることも、 数値を見比べれば確認できます。
関連用語で深掘り: 散布図 最小二乗法 回帰直線 単回帰 重回帰 残差 決定係数 相関 因果 疑似相関 信頼区間 外れ値 多重共線性
🍰 まずはやさしく
関係性を数式で表したものです。
計算で正確な数値を導き出します。
買い物金額をいくつかの要因で表します。
基本となる数式と定義を学びます。
最も基本の 線形回帰モデル:
行列形式:
最小二乗推定量 (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.61 上昇 |
| $\varepsilon_i$ | 誤差項 | 奈良県のように特殊な県の残差は大きい |
| $\hat{y}_i$ | 予測値 | i=秋田 の予測死亡率は 18.66 |
| $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 死亡率」の散布図の傾きとは数値が一致しません。
回帰式 $y_i = \beta_0 + \beta_1 x_{i1} + \cdots + \beta_p x_{ip} + \varepsilon_i$ は、 一見数学的ですが、 言葉に翻訳すると 「複数の入力を組み合わせて出力を予測する公式」 です。 SSDSE-B-2026 を例に、 4 段階で読み解きます。
| 段階 | 意味(ことば) | SSDSE-B-2026 での例 |
|---|---|---|
| つまり | 回帰は「説明変数を一次結合して応答変数を予測する」モデル。 線形性( $\beta_j$ が定数)と独立性(観測 $i$ 同士は独立)の 2 つを仮定する。 | SSDSE-B-2026 の 47 都道府県で「死亡率 = $\beta_0 + \beta_1 \times$ 高齢化率」 を当てはめると、 $\beta_0 \approx -5.17$、 $\beta_1 \approx 0.610$。 つまり「高齢化率 1pp 上昇で死亡率が 0.61 上昇」。 |
| なぜなら | 誤差 $\varepsilon$ の二乗和を最小化する $\beta$ を解析的に解くと、 上述の係数が得られる(OLS = 通常最小二乗法)。 これは「予測値と実測値のズレを最小にする直線」の数学的定式化。 | SSDSE-B-2026 で実際に statsmodels.OLS(y, sm.add_constant(X)).fit() を実行すると、 残差平方和は約 11.1、 全変動 (TSS) は 201.9、 R² = 1 - 11.1/201.9 = 0.945。 つまり「死亡率の 94% は高齢化率で説明できる」。 |
| 具体的には | SSDSE-B-2026 の 47 県を一つずつ見ると、 「秋田県は高齢化率 39%, 実測死亡率 19.17, 予測値 18.66, 残差 +0.51」のように、 すべての県で予測値と実測値の差(残差)が計算できる。 残差が大きい県=モデルが説明しきれない特殊事情がある県。 | 奈良県は SSDSE-B-2026 で高齢化率 33%、 実測死亡率 13.10、 予測値(モデル)14.74、 残差 -1.65。 奈良は「高齢化率の割に死亡率が低い」例外。 高齢層の年齢構成など追加変数が必要。 |
| だから | 回帰は「予測 + 解釈 + 仮説検証」の 3 役を担う。 係数の符号・大きさ・有意性、 R²、 残差の三点セットを必ず確認する。 | SSDSE-B-2026 で「死亡率は高齢化率だけで説明できるか?」という仮説を、 単回帰モデルの $R^2 = 0.94$ と残差プロットで検証する。 沖縄の外れ値を考慮するには、 重回帰へ拡張する必要がある。 |
| 記号 | 言葉での意味 | SSDSE-B-2026 での具体例 |
|---|---|---|
| $y_i$ | 応答変数(目的変数)の $i$ 番目の観測値。 「予測したいもの」。 | SSDSE-B-2026 で y = 死亡率(A4200/A1101 × 1000)。 i=0 は北海道、 i=46 は沖縄。 |
| $x_{ij}$ | 説明変数 $j$ の $i$ 番目の観測値。 「予測の手がかり」。 | SSDSE-B-2026 で x = 高齢化率(A1303/A1101)。 北海道は 0.33、 沖縄は 0.22。 |
| $\beta_0$ | 切片。 説明変数が全部 0 のときの予測値。 外挿になるため解釈は慎重に。 | SSDSE-B-2026 で $\beta_0 \approx -5.17$。 「高齢化率 0 の県があれば死亡率は -5.17」だが、 高齢化率 0 の県は存在しないため意味のない値。 |
| $\beta_j$ | 偏回帰係数。 他の説明変数を固定したまま $x_j$ を 1 単位増やしたときの $y$ の変化。 | SSDSE-B-2026 で $\beta_1 = 0.610$。 「高齢化率 1pp 増で死亡率 0.61 増」。 重回帰では「他の変数を固定して比較したときの効果」を意味する。 |
| $\varepsilon_i$ | 誤差項。 モデルで説明できない部分。 平均 0、 等分散、 正規分布、 独立 を仮定(OLS の 4 仮定)。 | SSDSE-B-2026 で $\varepsilon_{奈良} \approx -1.65$。 「奈良県は予測より 1.65 低い」 → モデルに含まれない要因の影響。 |
| $\hat{y}_i$ | 予測値。 $\hat{y}_i = \beta_0 + \beta_1 x_{i1} + \cdots$。 モデルが「言っている値」。 | SSDSE-B-2026 で $\hat{y}_{秋田} = -5.17 + 0.610 \times 39.06 \approx 18.66$。 実測 19.17 とほぼ一致。 |
| $R^2$ | 決定係数。 「データの分散のうち、 モデルが説明できる割合」。 0–1 の値。 | SSDSE-B-2026 で高齢化率 → 死亡率の単回帰では $R^2 = 0.945$。 出生率など他変数を加えてもほとんど上がらない。 |
| $\mathrm{SE}(\hat{\beta}_j)$ | 係数の標準誤差。 「係数の不確実性の大きさ」。 サンプルが少ない・誤差が大きいと SE が大きくなる。 | SSDSE-B-2026 で $\mathrm{SE}(\beta_1) \approx 0.022$。 95% 信頼区間は $0.610 \pm 1.96 \times 0.022 = [0.57, 0.65]$。 区間が 0 を含まないので有意。 |
| $t_j = \beta_j / \mathrm{SE}(\beta_j)$ | t 統計量。 「係数の効果が SE 何個分か」。 絶対値が 2 以上なら 5% 有意水準で帰無仮説(係数 = 0)を棄却。 | SSDSE-B-2026 で $t_1 = 0.610 / 0.022 \approx 27.8$。 圧倒的に有意。 |
覚え方: 回帰は「予測機 + 翻訳機」。 数値を入れたら数値が出てくる「予測機」と、 係数の解釈を通して「説明変数 → 応答変数の関係性」 を読み解く「翻訳機」の二面性を持つ。
診断: NO。 R² は説明変数を追加すれば必ず上がる(自由度調整なし)。 SSDSE-B-2026 で 46 列すべてを説明変数に入れれば R² ≈ 1 になるが、 過学習で予測力は皆無。
対処: 調整済み R²(Adjusted R²)または AIC/BIC を使う。 SSDSE-B-2026 では「死亡率 ← 高齢化率」 単独で R²=0.94 だが、 これに無関係な変数を入れても adjusted R² は下がる。
診断: SSDSE-B-2026 で「アイスクリーム消費 (H1101 系)」と「水難事故」が両方夏に高くなると、 偽の正の相関が出る。 これに回帰式を当てはめると、 アイス消費 → 水難事故 の見せかけの因果が示される。
対処: (1) 交絡変数(共通原因、 この場合「気温」)を説明変数に入れる、 (2) 観察研究なら DAG で因果構造を描く、 (3) RCT か自然実験で因果を切り出す。 SSDSE-B-2026 は観察研究データなので、 因果主張は控えめに。
診断: SSDSE-B-2026 で死亡率を予測すると、 奈良県が下方に外れる(残差約 -1.65)。 残差ヒストグラムを描くと裾を引く。 これは「その県に特有の要因」のサイン。
対処: (1) y や x の対数変換、 (2) 外れ値県のフラグ変数を追加、 (3) ロバスト回帰(M 推定)。 SSDSE-B-2026 では「沖縄ダミー」を入れると残差正規化が改善する。
診断: SSDSE-B-2026 で「総人口」と「労働力人口」と「就業者数」を同時に説明変数に入れると、 互いに高相関のため $\beta$ の標準誤差が爆発する。
対処: VIF(Variance Inflation Factor)を計算。 VIF > 10 の変数を 1 つ落とす。 SSDSE-B-2026 では「人口比率(労働力 / 総人口)」のような派生列で 1 つに統合するのも有効。
診断: n=47 は最小限。 一般に「説明変数 1 つにつき 10–20 観測」が経験則。 SSDSE-B-2026 単体では説明変数を 3–5 個以下に抑える。
対処: (1) 説明変数を絞る、 (2) 時系列で縦に積んで n を増やす(SSDSE-B-2026 × 10 年 = 470 観測)、 (3) Bootstrap で係数の信頼区間を推定、 (4) Ridge/Lasso で正則化。
回帰モデルの妥当性を検証する 6 つの統計テストを SSDSE-B-2026 で実演します。 すべて statsmodels.stats で簡単に呼べます。
1 2 3 4 5 | from statsmodels.stats.diagnostic import het_breuschpagan bp_stat, bp_pval, _, _ = het_breuschpagan(result.resid, result.model.exog) print(f'Breusch-Pagan: stat={bp_stat:.3f}, p={bp_pval:.4f}') # p > 0.05 なら等分散性 OK |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd import statsmodels.api as sm # result(検定にかける回帰)をここで作る _d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) _d = _d[_d['SSDSE-B-2026'] == 2023].reset_index(drop=True) # A1101 と A1303 は相関が高く、White 検定の補助回帰(2 乗と交差項)が # 縮退して statsmodels の assert に引っかかる。相関の低い組で作る。 _X = sm.add_constant(_d[['A1101', 'B4101']].astype(float)) result = sm.OLS(_d['I5102'].astype(float), _X).fit() from statsmodels.stats.diagnostic import het_white w_stat, w_pval, _, _ = het_white(result.resid, result.model.exog) print(f'White: stat={w_stat:.3f}, p={w_pval:.4f}') |
1 2 3 4 5 | from scipy import stats as sps sw_stat, sw_pval = sps.shapiro(result.resid) print(f'Shapiro-Wilk: stat={sw_stat:.3f}, p={sw_pval:.4f}') # SSDSE-B-2026 では沖縄の外れ値の影響で正規性は怪しい場合あり |
1 2 3 4 5 | from statsmodels.stats.stattools import durbin_watson dw = durbin_watson(result.resid) print(f'Durbin-Watson: {dw:.3f}') # 2 に近いと独立性 OK、 0 や 4 に近いと自己相関あり |
1 2 3 4 5 | from statsmodels.stats.diagnostic import linear_reset reset_stat = linear_reset(result, power=[2,3], use_f=True) print(reset_stat) # 高次項を入れると有意になる場合、 線形仮定が不十分の証拠 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd import statsmodels.api as sm # aging_rate / birth_rate / death_rate はこのあとのブロックで作っている派生列。 # ここでも同じ定義で用意しておく(SSDSE-B-2026 に同名の列は無い) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) df['aging_rate'] = df['A1303'] / df['A1101'] * 100 # 高齢化率 (%) df['birth_rate'] = df['A4101'] / df['A1101'] * 1000 # 出生率 (人口千人あたり) df['death_rate'] = df['A4200'] / df['A1101'] * 1000 # 死亡率 (人口千人あたり) from statsmodels.stats.outliers_influence import variance_inflation_factor X_with_const = sm.add_constant(df[['aging_rate', 'birth_rate']]) for i, col in enumerate(X_with_const.columns): vif = variance_inflation_factor(X_with_const.values, i) print(f'{col}: VIF = {vif:.2f}') # VIF < 5 なら問題なし、 5-10 で要注意、 > 10 で深刻 |
同じ SSDSE-B-2026 を、 5 つの異なる「視点」 で回帰すると、 異なる発見が得られます。
y = 死亡率、 X = (高齢化率, 出生率) — 人口動態を予測。 SSDSE-B-2026 で R² ≈ 0.945。 「高齢化率の効果が支配的で、 出生率は追加の説明力をほとんど持たない」 という結果。
y = 着工新設住宅戸数 (H1800)、 X = (総人口 A1101) — 住宅市場規模を予測。 SSDSE-B-2026 で R² ≈ 0.975。 「住宅着工は人口規模でほぼ決まる」。
y = 死亡率、 x = 一般診療所数/人口(I5102 を総人口で割った密度) — 医療アクセスの効果。 SSDSE-B-2026 で R² ≈ 0.03。 「医療資源密度は死亡率の予測力が意外と弱い」 という気づき(観察データのため因果効果ではないことに注意)。
y = 転入超過率、 X = (高齢化率) — 人口流入要因。 SSDSE-B-2026 で R² ≈ 0.63。 「高齢化率が低い県ほど転入超過」 → 東京一極集中の構造を係数で量化。
y = 延べ宿泊者数 (G7101)、 X = (総人口 A1101, 外国人延べ宿泊者数 G7102) — 観光規模を予測。 SSDSE-B-2026 で R² ≈ 0.93。 「宿泊需要は人口と外国人客数で説明できる」。
結論: 同じデータを「何を y にするか」 で全く異なる発見が得られる。 SSDSE-B-2026 は 109 の指標列があるため、 5 つの視点それぞれで論文が書ける。 「視点」 こそが研究者の創造性が発揮されるポイント。
SSDSE-B 2023 の 47 都道府県で、応答変数 y = 死亡率(人口千人あたり)、説明変数 x = 高齢化率(%)の単回帰を実行すると:
| 項目 | 値 | 解釈 |
|---|---|---|
| $\hat{\beta}_0$ (切片) | −5.17 | 高齢化率 0% の架空県の死亡率(外挿で意味薄) |
| $\hat{\beta}_1$ (傾き) | +0.610 | 高齢化率が 1pp 上がると死亡率は 0.61 上昇 |
| 標準誤差 SE(β₁) | 0.0220 | 係数のばらつきの推定 |
| t 統計量 (β₁) | 27.76 | 圧倒的に大きい |
| p 値 (β₁) | < 0.001 | 「偶然 0」とは到底考えられない |
| $R^2$ | 0.944 | 死亡率の分散の 94.4% を説明 |
| 調整済み $R^2$ | 0.944 | 説明変数 1 個ではほぼ同じ |
| 相関 r | +0.972 | 非常に強い正の相関 |
「高齢化率 39.06% の秋田県」の死亡率予測値は $\hat{y} = -5.17 + 0.610 \times 39.06 \approx 18.66$ で、 実測 19.17 とほぼ一致。 残差は約 +0.51 と小さくなります。
| モデル | 説明変数 | $R^2$ | 調整済み $R^2$ |
|---|---|---|---|
| 単回帰 | 高齢化率のみ | 0.9448 | 0.9436 |
| 重回帰 A | 高齢化率 + 出生率 | 0.9448 | 0.9423 |
| 重回帰 B | 高齢化率 + 出生率 + 合計特殊出生率 | 0.9453 | 0.9415 |
| 重回帰 C(4 変数) | 高齢化率 + 出生率 + 合計特殊出生率 + 転入超過率 | 0.9476 | 0.9426 |
説明変数を増やしても $R^2$ はほとんど伸びず、 調整済み $R^2$ はむしろ低下(出生率などは追加説明力を持たない)。 「説明変数を盛れば必ず良くなる」わけではないことが、 実データできちんと再現できます。
| 順位 | 都道府県 | 実測死亡率 | 予測死亡率 | 残差 |
|---|---|---|---|---|
| 1 | 奈良県 | 13.10 | 14.74 | −1.65 |
| 2 | 青森県 | 17.60 | 16.32 | +1.28 |
| 3 | 東京都 | 9.74 | 8.72 | +1.03 |
奈良県の死亡率が「予測より低い」(残差 −1.65)のは、 高齢化率では説明できない要因(相対的に若い高齢層構成など)の存在を示唆します。 逆に青森県・東京都は予測よりやや高めに出ます。 これらの残差の県別パターンを見ることが、 次の研究テーマを発見する第一歩になります。
単回帰から始めて、 重回帰・対数回帰・ロバスト回帰まで、 SSDSE-B-2026 で実装可能な 5 種類の回帰モデルを紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd import statsmodels.api as sm df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) # 2023 年度 47 県 # 派生列 df['aging_rate'] = df['A1303'] / df['A1101'] * 100 # 高齢化率 (%) df['death_rate'] = df['A4200'] / df['A1101'] * 1000 # 死亡率 (人口千人あたり) # 単回帰 X = sm.add_constant(df['aging_rate']) y = df['death_rate'] model1 = sm.OLS(y, X).fit() print(model1.summary()) # 結果: aging_rate 係数 ≈ 0.610 (t ≈ 27.8), R² ≈ 0.945 |
1 2 3 4 5 6 7 8 | df['birth_rate'] = df['A4101'] / df['A1101'] * 1000 X = sm.add_constant(df[['aging_rate', 'birth_rate']]) model2 = sm.OLS(df['death_rate'], X).fit() print(model2.summary()) # aging_rate: 0.609 (有意, p<0.001), birth_rate: -0.010 (非有意, p=0.94) # R² は単回帰 0.9448 → 重回帰 0.9448 でほぼ変わらず(出生率は追加説明力なし) |
1 2 3 4 5 6 7 8 9 | import numpy as np df['log_pop'] = np.log(df['A1101']) # 総人口の対数 df['log_clinic'] = np.log(df['I5102']) # 一般診療所数の対数 X = sm.add_constant(df['log_pop']) model3 = sm.OLS(df['log_clinic'], X).fit() print(model3.summary()) # 弾力性として解釈: 人口 1% 増で一般診療所数 約 0.97% 増(R² ≈ 0.97) |
1 2 3 4 5 6 | df['is_okinawa'] = (df['Prefecture'] == '沖縄県').astype(int) X = sm.add_constant(df[['aging_rate', 'is_okinawa']]) model4 = sm.OLS(df['death_rate'], X).fit() print(model4.summary()) # is_okinawa の係数が約 +1.07 (p=0.046) → 「沖縄は予測より約 1.1 高い」 を係数化 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from sklearn.linear_model import Ridge from sklearn.preprocessing import StandardScaler features = ['aging_rate', 'birth_rate', 'log_pop', 'is_okinawa'] X = df[features] y = df['death_rate'] scaler = StandardScaler() X_scaled = scaler.fit_transform(X) ridge = Ridge(alpha=1.0) ridge.fit(X_scaled, y) print(dict(zip(features, ridge.coef_))) print('R²:', ridge.score(X_scaled, y)) |
SSDSE-B-2026 で「死亡率 ← 高齢化率」の単回帰を当てはめた後、 残差プロットから 4 つの情報を読み取ります。
残差が水平な帯状に散らばっていれば OK。 予測値が大きくなるにつれて散らばりが広がる「ファネル形状」が出れば、 等分散性違反(heteroscedasticity)。 SSDSE-B-2026 では大きな県(東京、 大阪)と小さな県(鳥取、 島根)で残差の大きさが異なる傾向があるため、 対数変換や WLS(重み付き最小二乗)を検討。
残差を昇順に並べたものと、 標準正規分布の理論分位点を比較。 直線に乗れば正規性 OK。 SSDSE-B-2026 では奈良県が左下隅から外れる傾向(負の方向に大きい外れ値。 残差 −1.65)。
Durbin–Watson 統計量(2 に近いほど良い)を確認。 SSDSE-B-2026 を時系列で縦に積んだ場合、 同じ県の 2020 年と 2021 年の残差は相関する可能性がある。 GLS や fixed effect モデルへ拡張。
Cook's distance が 4/n を超える県は「モデルへの影響が大きい」県。 SSDSE-B-2026 で 4/47 ≈ 0.085 を超えるのは、 奈良・青森・東京あたり(残差の大きい県)。 これらの県を除外した感度分析を行うのが定石。
合成モデルで F 値と p から有意性を判定する。
| 区分 | SS | df | MS |
|---|---|---|---|
| 回帰 | 45 | 2 | 22.5 |
| 残差 | 9 | 5 | 1.8 |
| 合計 | 54 | 7 | — |
1 2 3 4 5 | from scipy import stats F = 22.5/1.8 crit = stats.f.ppf(0.95, 2, 5) p = 1 - stats.f.cdf(F, 2, 5) print(f"F: {F}, 臨界値: {crit:.2f}, p: {p:.4f}") |
💬 手計算 (Step 2) F=12.5 と Python 出力が完全一致。
SSDSE-B 2023 データを使って単回帰と重回帰を実行:
1 2 3 4 5 6 7 8 9 10 | import pandas as pd # SSDSE-B-2026 を読み込み(年度別 47 都道府県、 最新は 2023 年度) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df.columns = [c.strip() for c in df.columns] df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) print(df.shape) # (47, 112) print(df['Prefecture'].nunique()) # 47 print(df.iloc[:3, :5]) |
応答変数と説明変数を作る:
1 2 3 4 5 6 7 8 9 | # 主要指標を計算 df['死亡率'] = df['A4200'] / df['A1101'] * 1000 # 人口千人あたり df['出生率'] = df['A4101'] / df['A1101'] * 1000 df['高齢化率'] = df['A1303'] / df['A1101'] * 100 df['若年人口比率'] = df['A1301'] / df['A1101'] * 100 df['転入超過率'] = (df['A5101'] - df['A5102']) / df['A1101'] * 1000 print(df[['Prefecture','高齢化率','出生率','死亡率','転入超過率']].head()) print(df[['高齢化率','出生率','死亡率']].describe().round(2)) |
単回帰(statsmodels で詳細な統計量を取得):
1 2 3 4 5 6 7 | import statsmodels.api as sm X = sm.add_constant(df['高齢化率']) model = sm.OLS(df['死亡率'], X).fit() print(model.summary()) # Intercept = -5.17, 高齢化率の係数 = 0.610 # R-squared = 0.9448, t-value ≈ 27.8, p < 0.001 |
重回帰と多重共線性チェック:
1 2 3 4 5 6 7 8 9 10 | from statsmodels.stats.outliers_influence import variance_inflation_factor X = df[['高齢化率', '出生率', 'A4103']] 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 で予測・残差プロット:
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 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) |
標準化偏回帰係数で「どの変数が効くか」を比較:
1 2 3 4 5 6 7 8 9 10 11 12 | from sklearn.preprocessing import StandardScaler X_raw = df[['高齢化率', '出生率', 'A4103']].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(['高齢化率','出生率','A4103'], reg_std.coef_): print(f'{name}: 標準化偏回帰係数 = {coef:+.3f}') # 各係数の絶対値の大きさで「効きの強さ」を比較できる |
係数の信頼区間と予測区間:
1 2 3 4 5 6 7 8 9 10 11 | 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+ 含まれる総合データセットです。
1 2 3 4 5 6 7 8 9 10 | import pandas as pd # SSDSE-B-2026 を読み込み(年度別 47 都道府県、 最新は 2023 年度) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df.columns = [c.strip() for c in df.columns] df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) print(df.shape) # (47, 112) print(df['Prefecture'].nunique()) # 47 print(df.iloc[:3, :5]) |
応答変数になりうる「人口千人あたり死亡率」「人口千人あたり出生率」「高齢化率」「若年比率」「転入超過率」などを派生:
1 2 3 4 5 6 7 8 9 | # 主要指標を計算 df['死亡率'] = df['A4200'] / df['A1101'] * 1000 # 人口千人あたり df['出生率'] = df['A4101'] / df['A1101'] * 1000 df['高齢化率'] = df['A1303'] / df['A1101'] * 100 df['若年比率'] = df['A1301'] / df['A1101'] * 100 df['転入超過率'] = (df['A5101'] - df['A5102']) / df['A1101'] * 1000 print(df[['Prefecture','高齢化率','出生率','死亡率','転入超過率']].head()) print(df[['高齢化率','出生率','死亡率']].describe().round(2)) |
続いて散布図で関係性の俯瞰:
1 2 3 4 5 6 7 8 9 10 11 12 | 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['Prefecture'], (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 都道府県のような小サンプルでは、 平均だけでなく 分布の形状・外れ値の位置 を見せることで、 議論の透明性が大きく上がります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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['死亡率']], tick_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 県を最低限ラベリングすると親切です。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd import statsmodels.api as sm 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].reset_index(drop=True) # 2023 年度 47 県 df['aging_rate'] = df['A1303'] / df['A1101'] * 100 df['death_rate'] = df['A4200'] / df['A1101'] * 1000 X = sm.add_constant(df['aging_rate']) y = df['death_rate'] result = sm.OLS(y, X).fit() print(result.summary()) |
1 2 3 4 5 6 7 8 9 | from sklearn.linear_model import LinearRegression X = df[['aging_rate']].values y = df['death_rate'].values model = LinearRegression() model.fit(X, y) print('β0:', model.intercept_, 'β1:', model.coef_[0]) print('R²:', model.score(X, y)) print('predictions[:5]:', model.predict(X[:5])) |
1 2 3 4 5 6 7 8 9 10 11 | x = df['aging_rate'].values y = df['death_rate'].values # 2 次多項式 coefs = np.polyfit(x, y, deg=2) print('y =', coefs[0], 'x² +', coefs[1], 'x +', coefs[2]) # 当てはめの良さ y_pred = np.polyval(coefs, x) ss_res = ((y - y_pred)**2).sum() ss_tot = ((y - y.mean())**2).sum() print('R²:', 1 - ss_res/ss_tot) |
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 # OLS の結果から残差を取得 result = sm.OLS(y, sm.add_constant(df['aging_rate'])).fit() residuals = result.resid fitted = result.fittedvalues fig, axes = plt.subplots(1, 2, figsize=(12, 4)) # 残差 vs 予測値 axes[0].scatter(fitted, residuals) axes[0].axhline(0, color='red', linestyle='--') axes[0].set_xlabel('Fitted') axes[0].set_ylabel('Residuals') axes[0].set_title('Residuals vs Fitted') # Q-Q プロット from scipy import stats stats.probplot(residuals, dist='norm', plot=axes[1]) # 沖縄県のラベル付け for i, pref in enumerate(df['Prefecture']): if abs(residuals.iloc[i]) > 1.5: axes[0].annotate(pref, (fitted.iloc[i], residuals.iloc[i])) plt.tight_layout() plt.savefig('residuals.png', dpi=100) |
1 2 3 4 5 6 7 8 9 10 11 | from statsmodels.stats.outliers_influence import OLSInfluence infl = OLSInfluence(result) cooks_d = infl.cooks_distance[0] threshold = 4 / len(df) # 閾値超え県 high_inf = df[cooks_d > threshold] print(high_inf[['Prefecture','aging_rate','death_rate']]) print(f'Cook D 閾値: {threshold:.3f}') # 沖縄県・東京都などが上位 |
1 2 3 4 5 6 7 8 9 10 11 | from statsmodels.stats.outliers_influence import variance_inflation_factor features = ['aging_rate', 'A1101', 'B4101', 'A4101'] X = df[features].assign(_const=1) vif_df = pd.DataFrame({ 'feature': features, 'VIF': [variance_inflation_factor(X.values, i) for i in range(len(features))] }) print(vif_df) # VIF > 10 の変数があれば多重共線性 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from sklearn.linear_model import Ridge, Lasso from sklearn.preprocessing import StandardScaler from sklearn.model_selection import LeaveOneOut, cross_val_score features = ['aging_rate', 'A1101', 'B4101', 'A4101'] X = df[features] y = df['death_rate'] scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # Ridge for alpha in [0.01, 0.1, 1.0, 10.0]: ridge = Ridge(alpha=alpha) cv_scores = cross_val_score(ridge, X_scaled, y, cv=LeaveOneOut(), scoring='neg_mean_squared_error') rmse = (-cv_scores.mean()) ** 0.5 print(f'Ridge alpha={alpha}: LOOCV RMSE = {rmse:.4f}') |
1 2 3 4 5 6 7 8 9 10 11 12 | from statsmodels.sandbox.regression.predstd import wls_prediction_std result = sm.OLS(y, sm.add_constant(df['aging_rate'])).fit() # 予測区間 (新観測値) と信頼区間 (平均) の両方 prstd, iv_l, iv_u = wls_prediction_std(result) # 信頼区間(平均の不確実性) ci = result.get_prediction(sm.add_constant(df['aging_rate'])) ci_df = ci.summary_frame(alpha=0.05) # mean_ci_lower / upper: 平均の 95% CI # obs_ci_lower / upper: 個別観測の 95% PI |
SSDSE-B-2026 の 47 都道府県データで、 各モデルを実行した時の数値を表にしました。 実装の検証用にご利用ください。
| 項目 | 値 | 備考 |
|---|---|---|
| n | 47 | 都道府県 |
| β₀ (切片) | 約 -5.17 | 標準誤差 約 0.70 |
| β₁ (高齢化率) | 約 0.610 | 標準誤差 約 0.022、 p < 0.001 |
| R² | 0.9448 | 非常に高い当てはまり |
| Adjusted R² | 0.9436 | |
| F 統計量 | 約 771 | p < 0.001 |
| 残差の標準誤差 | 約 0.50 | RSE |
| Durbin-Watson | 約 1.63 | 独立性 OK |
| AIC | 約 70 | |
| BIC | 約 73 |
| 項目 | 値 | 備考 |
|---|---|---|
| β₁ (高齢化率) | 約 0.609 | p < 0.001、 単回帰とほぼ同じ |
| β₂ (出生率) | 約 -0.010 | p = 0.94、 有意でない(追加説明力なし) |
| R² | 0.9448 | 単回帰 0.9448 と変わらず |
| Adjusted R² | 0.9423 | 変数追加でむしろ低下 |
| 項目 | 値 | 備考 |
|---|---|---|
| β₁ (高齢化率) | 約 0.626 | p < 0.001 |
| β₂ (沖縄ダミー) | 約 +1.07 | 沖縄は予測より約 1.1 高い、 p = 0.046 |
| R² | 0.9497 | 沖縄ダミー追加で微増 |
重回帰の偏回帰係数 $\beta_j$ は「他の変数を固定したまま $x_j$ を 1 単位変えたときの $y$ の変化」と表現されますが、 数学的にはもっと美しい定理があります。 Frisch–Waugh–Lovell 定理(FWL 定理)です。
「重回帰 $y = X\beta + \varepsilon$ における $x_j$ の係数 $\beta_j$ は、 以下の 3 ステップで得られる単回帰の係数と一致する」:
SSDSE-B-2026 で「死亡率 ← 高齢化率 + 出生率」 の重回帰を例に。 高齢化率の偏回帰係数を FWL で求めると:
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 | import pandas as pd import statsmodels.api as sm # aging_rate / birth_rate / death_rate はこのあとのブロックで作っている派生列。 # ここでも同じ定義で用意しておく(SSDSE-B-2026 に同名の列は無い) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) df['aging_rate'] = df['A1303'] / df['A1101'] * 100 # 高齢化率 (%) df['birth_rate'] = df['A4101'] / df['A1101'] * 1000 # 出生率 (人口千人あたり) df['death_rate'] = df['A4200'] / df['A1101'] * 1000 # 死亡率 (人口千人あたり) import statsmodels.api as sm # Step 1: 死亡率 を 出生率 で回帰した残差 res_y = sm.OLS(df['death_rate'], sm.add_constant(df['birth_rate'])).fit().resid # Step 2: 高齢化率 を 出生率 で回帰した残差 res_x = sm.OLS(df['aging_rate'], sm.add_constant(df['birth_rate'])).fit().resid # Step 3: 残差同士で単回帰 fwl = sm.OLS(res_y, res_x).fit() print('FWL の β:', fwl.params[0]) # 通常の重回帰 full = sm.OLS(df['death_rate'], sm.add_constant(df[['aging_rate','birth_rate']])).fit() print('重回帰の β_aging_rate:', full.params['aging_rate']) # 両者は数値的に一致する |
意味するところ: 偏回帰係数 $\beta_j$ は「他の変数の影響を $y$ と $x_j$ の両方から取り除いた残差の関係」 を捉えている。 これが「他の変数を固定したまま」 の数学的意味です。 SSDSE-B-2026 で「高齢化率の効果」 を語るとき、 必ず「出生率を取り除いた後の効果」 と限定的に言うべきだとわかります。
単回帰の場合、 回帰直線は 2 次元平面上の直線です。 重回帰では「平面」 や「超平面」 になります。 SSDSE-B-2026 で 3 変数(高齢化率 + 出生率 → 死亡率)の重回帰を考えると、 3 次元空間中の平面が回帰結果です。
OLS は「観測点から回帰平面への垂直距離の二乗和を最小化」 する平面を選びます。 これは行列で書くと:
$\hat{\beta} = (X^\top X)^{-1} X^\top y$
この公式は SSDSE-B-2026 のサイズ(47 ×3)でも、 100 万 ×100 列でも同じ形。 ただし $X^\top X$ の逆行列が計算可能であることが前提(フルランク = 多重共線性なし)。
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 import statsmodels.api as sm # aging_rate / birth_rate / death_rate はこのあとのブロックで作っている派生列。 # ここでも同じ定義で用意しておく(SSDSE-B-2026 に同名の列は無い) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) df['aging_rate'] = df['A1303'] / df['A1101'] * 100 # 高齢化率 (%) df['birth_rate'] = df['A4101'] / df['A1101'] * 1000 # 出生率 (人口千人あたり) df['death_rate'] = df['A4200'] / df['A1101'] * 1000 # 死亡率 (人口千人あたり) import numpy as np X = df[['aging_rate', 'birth_rate']].values X = np.column_stack([np.ones(len(X)), X]) # 切片を追加 y = df['death_rate'].values # 行列計算で β を求める beta = np.linalg.inv(X.T @ X) @ X.T @ y print('行列計算の β:', beta) # statsmodels の結果と一致するはず import statsmodels.api as sm sm_result = sm.OLS(y, X).fit() print('statsmodels の β:', sm_result.params) |
「他の変数を固定して」 という表現は便利だが誤解を招きやすい。 SSDSE-B-2026 で 「高齢化率を固定して出生率の効果を見る」と言うとき、 「実際にどうやって固定するのか?」 が問題。
回帰の偏回帰係数は、 「データの中で偶然似た高齢化率を持つ県同士で比較したときの平均的な関係」 を表す。 SSDSE-B-2026 では、 全 47 県の中で「高齢化率 30% の県」 が複数存在するわけではないため、 線形補間が前提となる。
「もし高齢化率を強制的に変えずに、 出生率だけ介入したら?」 という反事実(counterfactual)の解釈は、 統計的固定とは別物。 因果推論の枠組み(DAG、 do-calculus)が必要。 SSDSE-B-2026 のような観察データでは、 因果的固定は強い仮定なしには言えない。
そもそも「高齢化率」 は政策で短期的に変えられない変数。 「介入できない変数の係数」 は予測モデルとしては有用だが、 「政策レバー」 とは言えない。 SSDSE-B-2026 で政策評価をするなら、 「一般診療所数 / 人口比率」 のような介入可能な変数を選ぶべき。
教訓: 回帰係数の解釈には 「統計的固定」「因果的固定」「操作可能性」 の 3 階層を区別する必要がある。 SSDSE-B-2026 のような観察研究では、 多くの場合「統計的固定の関係」 までしか言えない。
同じ「死亡率 ← 高齢化率」 単回帰を各ツールで書くと:
| ツール | 書き方 | 備考 |
|---|---|---|
| statsmodels | sm.OLS(y, sm.add_constant(X)).fit() | 統計推論向き、 summary() が便利 |
| scikit-learn | LinearRegression().fit(X, y) | ML パイプライン向き、 fit/predict 統一 |
| numpy | np.linalg.lstsq(X, y, rcond=None) | 低レベル、 学習向け |
| scipy | scipy.stats.linregress(x, y) | 1 変数のみ、 r 値も取得可能 |
| R (base) | lm(death_rate ~ aging_rate, data=df) | summary() で完全な結果 |
| SAS | PROC REG; MODEL y = x; | 業界標準だが古め |
| SPSS | 分析 → 回帰 → 線型 (GUI) | 非プログラマ向け |
| Excel | データ → 分析 → 回帰分析 (アドイン) | 結果テーブル直接出力 |
| BigQuery ML | CREATE MODEL ... OPTIONS(model_type='linear_reg') | SQL で機械学習 |
| Polars + scikit-learn | df.to_pandas() → LinearRegression | 大規模データを Polars で前処理後 |
SSDSE-B-2026 で実施した重回帰結果を、 APA 7th edition 形式で報告する例。
| 変数 | 係数 β | SE | t | p | 95% CI |
|---|---|---|---|---|---|
| (切片) | -5.07 | 1.49 | -3.41 | = .001 | [-8.08, -2.07] |
| 高齢化率 (%) | 0.609 | 0.028 | 21.61 | < .001 | [0.552, 0.666] |
| 出生率 (‰) | -0.010 | 0.134 | -0.07 | = .943 | [-0.279, 0.260] |
注: 応答変数は死亡率 (人口千人あたり)。 n = 47 都道府県。 R² = .9448、 adjusted R² = .9423、 F(2, 44) = 376.7, p < .001。 残差の標準誤差 = 0.50。
"高齢化率は死亡率と有意な正の関連を示した(β = 0.609、 95% CI [0.552, 0.666]、 p < .001)。 一方、 出生率の偏回帰係数は有意ではなく(β = -0.010、 95% CI [-0.279, 0.260]、 p = .943)、 高齢化率を統制すると追加の説明力を持たなかった。 死亡率の分散の 94.2% を説明できた(adjusted R² = .9423)。"
statsmodels.OLS で実行し、 R²・係数・p 値の意味を理解。| 観点 | scikit-learn | statsmodels |
|---|---|---|
| 推論(係数の p 値、 信頼区間) | 提供されない(再実装が必要) | 充実(summary() で全部出る) |
| 大規模データ | SGD などで高速対応 | OLS は中規模まで |
| パイプライン(前処理 → モデル → 予測) | Pipeline で統一 | 個別実行が前提 |
| 正則化 | Ridge/Lasso/ElasticNet 標準搭載 | Ridge は statsmodels.regression.linear_model.OLS の fit_regularized() に |
| クロスバリデーション | cross_val_score / GridSearchCV | 標準では未提供(手動実装) |
| 分散構造(GLS, WLS) | 限定的 | 豊富 |
| SSDSE-B-2026 (n=47) での推奨 | 正則化や CV を使うとき | 仮説検定・係数解釈を重視するとき |
結論: SSDSE-B-2026 のような小サンプル統計分析では statsmodels が第一選択。 機械学習パイプラインや大規模データでは scikit-learn が第一選択。 両者を組み合わせる(前処理 sklearn、 推論 statsmodels)こともよくある。
encoding='cp932' を忘れずに。skiprows=[1] で日本語名行を飛ばし、 コード列(A1101 など)をヘッダにする。df['SSDSE-B-2026']==2023 で 47 行に絞る。pd.to_numeric(errors='coerce') で数値化前にチェック。論文・実務報告での書き方例:
テンプレに従って、 (1) データ・サンプル数、 (2) 推定値・不確実性、 (3) 解釈の限界、 を必ず記載することが、 査読・レビューで通る最低ラインです。
SSDSE-B 2023(47 都道府県、 112 列)を題材に、 回帰分析 の関連分析でしばしば登場する処理を一通り辿ります。 ここはデータ前処理の典型パターンを覚える目的でもあります。
SSDSE-B はパネルデータなので、 まず分析対象年度を絞ります。 多くの集計指標は実数(千人・件数)で記録されており、 比較のために 人口で割って比率 にすると、 県ごとの大小に左右されずに済みます。
1 2 3 4 5 6 7 8 9 10 | # 年度別の行数と県数 print(df.groupby('SSDSE-B-2026').size()) print(df.groupby('SSDSE-B-2026')['Prefecture'].nunique()) # 各年 47 のはず # 2023 年に絞り、 比率系を作る df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True) df['食料費比率'] = df['L322101'] / df['L3221'] df['住居費比率'] = df['L322102'] / df['L3221'] df['教育費比率'] = df['L322108'] / df['L3221'] print(df[['Prefecture','食料費比率','住居費比率','教育費比率']].head()) |
1 2 3 4 5 6 | # どの列に欠損があるか nulls = df.isnull().sum() print(nulls[nulls > 0]) # 数値列の型 print(df.select_dtypes(include='number').dtypes.head(10)) |
1 2 3 4 5 6 7 | # 食料費比率の上位/下位 5 県 print(df.nlargest(5, '食料費比率')[['Prefecture','食料費比率']]) print(df.nsmallest(5, '食料費比率')[['Prefecture','食料費比率']]) # 標準化スコアで外れ値検出 df['food_z'] = (df['食料費比率'] - df['食料費比率'].mean()) / df['食料費比率'].std() print(df[df['food_z'].abs() > 2][['Prefecture','食料費比率','food_z']]) |
1 2 3 4 5 6 7 8 9 10 | vars_ = ['食料費比率','住居費比率','教育費比率','高齢化率','出生率','死亡率'] df['高齢化率'] = df['A1303'] / df['A1101'] * 100 df['出生率'] = df['A4101'] / df['A1101'] * 1000 df['死亡率'] = df['A4200'] / df['A1101'] * 1000 print(df[vars_].corr().round(2)) # pairplot で散布図行列 import seaborn as sns sns.pairplot(df[vars_]) |
たとえば「食料費比率は高齢化率と正の相関がある」という仮説を、 ピアソン相関と簡単な回帰でチェックします:
1 2 3 4 5 6 7 8 | 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 を使った県別効果推定 |
回帰分析は経済学の賃金関数、 疫学のリスク評価、 機械学習の教師あり学習、 マーケティングの広告寄与度、 製造業の歩留まり要因分析、 政策評価の準実験まで、 ほぼ全ての応用領域で 共通言語 として再登場します。 用語そのものより、 「いま自分が見ている SSDSE-B-2026 の散布図のどの関係を、 どの分野の文脈で語ろうとしているか」を意識すると、 回帰の発想が自然に広がります。 たとえば SSDSE-B-2026 の県別・世帯消費支出と高齢化率の関係は 経済学の家計消費関数、 県別死亡率と高齢化率は 疫学のコホート的視点、 県別消費支出と気温は 政策評価的アトリビューション として読み解けます。
回帰分析 を扱う前後で確認すべきポイント:
SSDSE-B-2026 で「高齢化率 22–40%」の範囲で回帰式を作った後、 「高齢化率 5% の架空国」に当てはめて死亡率を予測すると、 範囲外なので極端な値が出る。 切片 -5.17 に 0.610 × 5 を足すと -2.1 という不可能な(負の死亡率)値。
対処: 予測時には説明変数の値が訓練範囲内か必ずチェック。
SSDSE-B-2026 で「人口(万人単位)」と「高齢化率(%)」を混ぜると、 係数の大きさが単位に依存する。 「人口の係数 0.001」と「高齢化率の係数 0.61」を直接比較してはいけない。
対処: 標準化(z-score)してから回帰、 または標準化係数(標準化偏回帰係数)を報告。
SSDSE-B-2026 で「高齢化率 → 死亡率」 の係数が有意でも、 これは「相関構造の表現」であって「高齢化率を下げれば死亡率が下がる」とは限らない。 介入の意思決定に使うには因果推論の枠組みが必要。
対処: 「回帰係数は予測モデルの説明であり、 介入効果ではない」と明記。 介入評価には DAG、 IV、 RCT が必要。
SSDSE-B-2026 は n=47 と小さいので、 説明変数を 10 個以上入れると過学習。 訓練データで R²=0.99 でも、 新しい県(架空)に予測すると外れる。
対処: 説明変数を 3–5 個に抑える。 または LOOCV (Leave-One-Out CV) で予測誤差を見積もる。 Ridge/Lasso で正則化。
SSDSE-B-2026 で「着工新設住宅戸数 (H1800) ← 総人口 (A1101)」を回帰すると、 大きな県ほど残差の散らばりが大きくなる傾向(ファネル形状)。 これは OLS の前提違反。
対処: (1) y や x を対数変換、 (2) WLS(重み付き最小二乗)、 (3) ロバスト標準誤差(HC3 estimator)を使う。 sklearn では statsmodels.OLS(...).fit(cov_type='HC3')。
回帰分析の結果をレポートに記載する際は、 「係数 (SE) [95% CI] / R² / N」 の組み合わせを最低限報告します。 SSDSE-B-2026 を用いた例:
SSDSE-B-2026(n = 47 都道府県)を用い、 人口千人あたり死亡率を応答変数、 高齢化率を主要な説明変数とする線形回帰分析を実施した。 推定は通常最小二乗法(OLS)で行い、 異分散ロバスト標準誤差(HC3)を用いて係数の信頼区間を算出した。 解析には Python 3.11 と statsmodels 0.14 を使用した。
高齢化率は死亡率と有意な正の関連を示した(β = 0.610、 SE = 0.022、 95% CI [0.566, 0.654]、 t = 27.8、 p < .001)。 単回帰モデルの決定係数は R² = 0.9448(adjusted R² = 0.9436)、 残差の標準誤差は 0.50 であった(n = 47)。 高齢化率が 1 ポイント上昇すると、 死亡率(人口千人あたり)は平均で 0.61 上昇すると推定される。
表 1. 死亡率を応答変数とする線形回帰モデルの推定結果(SSDSE-B-2026、 n = 47)。
図 1. 高齢化率と死亡率の散布図および回帰直線(SSDSE-B-2026)。 奈良県は回帰直線より低い死亡率を示す外れ値である。
SSDSE-B-2026 で「死亡率 ← 高齢化率 + 一般診療所数/人口 (I5102)」 を重回帰すると、 「高齢化率は強い正の効果(支配的)」 「一般診療所密度の効果は弱い」 が観察される。 ただし因果推論ではなく相関構造の表現として報告する。
SSDSE-B-2026 で「大学学生数 (E6302) ← 総人口 (A1101) + 大学数 (E6102)」 を回帰すると、 人口規模と大学の集積が学生数をどれだけ説明するかを量化できる。 ただし東京への大学集中による外れ値(自己選択的な集積)に注意。
SSDSE-B-2026 で「転入超過率 ← 高齢化率」を回帰すると(R² ≈ 0.63)、 「高齢化率が低い(=若い)県ほど転入超過が大きい」関係が定量化できる。 東京一極集中の構造を係数で表現でき、 地方創生政策の効果測定の出発点になる。
SSDSE-B-2026 で「一般病院数 (I510120) ← 総人口 (A1101) + 65歳以上人口 (A1303)」 を重回帰すると、 人口規模と高齢人口が医療施設数をどれだけ規定するかを重みづけできる。 地域医療計画や病床配分の需要推計に応用できる。
「線形」 vs 「重」は別軸。 線形回帰は「説明変数と応答変数の関係が一次式」(曲線でない)。 重回帰は「説明変数が複数」。 SSDSE-B-2026 で「死亡率 ← 高齢化率」は「線形・単回帰」、 「死亡率 ← 高齢化率 + 出生率」は「線形・重回帰」。 「死亡率 ← 高齢化率²」は「非線形・単回帰」だが係数の意味では線形回帰の枠組み(多項式回帰)。
慣習的に p < 0.05 で有意とすることが多いが、 サンプル数や仮説の事前情報、 多重比較補正の必要性に応じて 0.01 や 0.005 を採用する場合もある。 SSDSE-B-2026 は n=47 と小さいので、 p < 0.05 でも厳しめに評価する。 一方で「p 値だけで判断しない、 効果量(係数の大きさ)と信頼区間も併記する」 のが APA や統計学会の最新推奨。
R² は「説明変数を増やすと必ず上がる」性質を持つため、 説明変数の数で罰則を入れた adjusted R² を使うのが一般的。 SSDSE-B-2026 で 1 変数モデルの R²=0.945 に不必要な変数を追加しても R² はほとんど上がらず、 adjusted R² はむしろ 0.94 前後まで下がる。 「説明力が上がったか、 ノイズを拾っただけか」 を判定できる。
予測重視なら AIC(赤池情報量規準)、 真のモデル選択重視なら BIC(ベイズ情報量規準)。 BIC は AIC より説明変数追加への罰則が大きい。 SSDSE-B-2026 のような小サンプルでは AICc(小サンプル補正版)を推奨。
SSDSE-B-2026 の n=47 では K-fold(K=5 や 10)よりも LOOCV(Leave-One-Out)が無難。 1 県を除いて 46 県でモデルを作り、 除いた 1 県を予測 → 47 回繰り返し → 平均誤差を取る。 各 fold で訓練データが十分残るのが利点。
単回帰で標準化(z-score)後の係数 = 相関係数 r。 SSDSE-B-2026 で「死亡率(標準化) ← 高齢化率(標準化)」の係数は、 ピアソン相関係数 r と数値が一致。 重回帰では「偏相関」と「偏回帰係数」の関係に拡張される。
| 年代 | 出来事 | 意味 |
|---|---|---|
| 1805 | Legendre / Gauss が最小二乗法を提唱 | OLS の数学的基盤。 天文観測の誤差処理から発生。 |
| 1885 | Galton が「平均への回帰」を提唱 | 「Regression」 という用語の由来。 親子の身長の関係から。 |
| 1908 | Yule の重回帰 | 説明変数複数化、 偏回帰係数の解釈確立。 |
| 1933 | Fisher の F 統計量 | 回帰係数の同時有意性検定の基礎。 |
| 1960 | Hoerl の Ridge 回帰 | L2 正則化の登場。 多重共線性対策。 |
| 1996 | Tibshirani の Lasso | L1 正則化で変数選択。 現代 ML の基礎。 |
| 2008 | scikit-learn 公開 | SSDSE-B-2026 のような表データに対する回帰が誰でも 3 行で書けるように。 |
| 2010- | 因果推論ブーム(Pearl, Hernán) | 「相関 ≠ 因果」 への意識が学会で標準化。 |
| 2020- | 大規模 LLM 時代の回帰 | 表データでは未だ XGBoost / 線形回帰が最強の場面が多い。 SSDSE-B-2026 のような 47 行データでは線形回帰が最適。 |
| 分野 | 類似概念 | 類似点 / 違い |
|---|---|---|
| 計量経済学 | パネルデータ回帰 | SSDSE-B-2026 を時系列で縦に積む = パネル。 固定効果モデル(fixed effect)で県固有の影響を制御。 |
| 機械学習 | 線形回帰モデル | 同じ式だが、 予測精度を最大化することに重きを置く(解釈は二の次)。 |
| 因果推論 | 線形構造方程式モデル | 回帰式に因果方向の仮定を加えたもの。 |
| 物理学 | 線形応答理論 | 外力 x に対する応答 y の比例係数 β。 SSDSE の各指標間の関係も「社会的線形応答」と見なせる。 |
| 金融工学 | CAPM (資本資産価格モデル) | 株式リターン = α + β × 市場リターン。 完全に線形回帰の形。 |
| 生物統計 | 線形混合モデル (LMM) | 個体差を変量効果として組み込み。 SSDSE で「県差」を変量効果にする発想と同型。 |
この用語の前提・並列・発展を一覧で:
| 関係 | 主要用語 |
|---|---|
| 前提となる用語 | 平均・分散・標準偏差・標本・母集団 |
| 関連性の把握 | 相関・共分散・散布図 |
| 回帰モデル | 線形回帰・OLS・R²・残差 |
| 検定・推定 | 仮説検定・p 値・信頼区間・点推定 |
| 因果推論 | 処置群・対照群・交絡・自然実験 |
| 変数の尺度 | 名義尺度・順序尺度・間隔尺度・比例尺度 |
「回帰分析」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
47 都道府県の人口データから「総人口 → 一般診療所数」の影響を定量化するように、 「回帰分析」は 連続値どうしの関係 を数値で表現するパイプラインの中核となる。
線形回帰の枠を超える場合の選択肢。 SSDSE-B-2026 でも残差プロットで曲線パターンが見えたら検討。
説明変数の高次項(x², x³)を入れる。 SSDSE-B-2026 で「高齢化率²」 を入れると、 高齢化率が極端に高い県で死亡率がさらに加速する効果を捉えられる。 ただし過学習しやすい。
説明変数の範囲を区分に分けて、 各区間で別の多項式を当てる。 SSDSE-B-2026 で「人口」のように分布が偏った変数を扱うのに有用。
線形性を仮定せず、 階層的な if-then ルールで予測。 SSDSE-B-2026 で「人口 > 500万なら東京、 そうでなく高齢化率 > 35% なら…」 のような分岐。
弱学習器の決定木を順次足していく。 SSDSE-B-2026 の n=47 では過学習しやすいが、 縦に時系列で積めば十分。
予測値だけでなく不確実性も推定。 SSDSE-B-2026 のような小サンプルで「予測区間」 を厳密に出したいときに有用。
注意: SSDSE-B-2026 のような小サンプル・低次元データでは、 線形回帰が依然として最強 の選択肢である場合が多い。 非線形手法に飛びつく前に、 線形モデルで尽くせる説明を尽くす。
「回帰分析」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。
このフローに沿って判断することで、 「回帰分析」を中核とした適切な手法選択ができる。
ここまでの内容を一段深く整理します。 回帰分析には 2 つの顔 があり、 どちらの顔で使っているかを自覚することが、 誤用を防ぐ最大のポイントです。
| 観点 | 予測の回帰 (prediction) | 説明の回帰 (explanation) |
|---|---|---|
| 目標 | 新しい X に対する y の予測誤差を最小化 | 係数 β の符号・大きさ・不確実性を解釈 |
| 成功の基準 | 交差検証誤差・汎化性能 | 係数の妥当性・仮定の充足・頑健性 |
| 変数選択 | 予測に効けば理由は問わない | 理論・因果構造に基づいて選ぶ |
| SSDSE-B での例 | 高齢化率から死亡率を当てる(R²=0.944) | 「高齢化率 1pp → 死亡率 +0.61」の解釈 |
| 典型的な失敗 | 過学習(n=47 に変数を盛る) | 交絡を無視した因果的解釈 |
回帰の派生手法は多いですが、 系譜は単純です。 (1) 説明変数を増やす方向(単回帰 → 重回帰)、 (2) 誤差分布・リンク関数を広げる方向(正規線形モデル → GLM:ロジスティック・ポアソン)、 (3) 関数形を柔らかくする方向(多項式 → スプライン → GAM)の 3 軸で、 ほぼすべての回帰系手法が位置づけられます。 どの軸に進んでも「残差を診断して仮定を確認する」という作法は共通です。
「落とし穴」を抽象論で終わらせず、 SSDSE-B-2026(cp932, skiprows=[1], 2023 年度 47 都道府県)で実際に数値を出して確認します。 以下の数値はすべて実測です。
人口千人あたり一般診療所数(I5102/A1101×1000、 平均 0.845)で死亡率を単回帰すると、 係数は +2.92(p=0.264, r=0.166)と正方向に出ます。 素朴に読むと「診療所が多いほど死亡率が高い」ように見えますが、 交絡要因の高齢化率(診療所密度との相関 r=0.191)を説明変数に加えると、 診療所密度の係数は −0.35(p=0.583)に反転し、 見かけの関係は消えます。 高齢化が進んだ県ほど診療所も死亡率も多い、 という共通原因の構図です。 疑似相関・逆因果とあわせて、 係数の符号を額面通りに読まない訓練をしてください。
「外れ値」には 2 種類あります。 y 方向の外れ(大きな残差)と、 x 方向の端にいること(高レバレッジ)です。 単回帰「死亡率 ← 高齢化率」での実測値:
| 都道府県 | レバレッジ h | 残差 | Cook 距離 D | タイプ |
|---|---|---|---|---|
| 東京都 | 0.174 | +1.03 | 0.547 | 高レバレッジ(高齢化率最低 22.8%)+残差も大 |
| 沖縄県 | 0.138 | +0.92 | 0.317 | 高レバレッジ+中程度の残差 |
| 青森県 | — | +1.28 | 0.172 | 残差型(x は中央寄り) |
| 奈良県 | — | −1.65 | 0.134 | 残差型(最大の負残差) |
| 秋田県 | 0.130 | +0.51 | 0.090 | 高レバレッジ(高齢化率最高 39.1%)だが残差小 |
目安 h > 2p/n = 0.085 を超えるのは東京・沖縄・秋田など x の両端の県。 残差が最大の奈良県よりも、 残差が小さめの東京都の方が Cook 距離は大きい(0.547 vs 0.134)ことに注目してください。 影響力は「残差 × レバレッジ」で決まるため、 残差だけを見ていると影響力の強い点を見逃します。 対処は外れ値・外れ値処理を参照。
「死亡率 ← 高齢化率」は R²=0.944 と直線で十分に見えますが、 二次項(高齢化率²)を追加すると係数 +0.0168(p=0.0002)で有意になり、 R² は 0.9448 → 0.9600、 調整済み R² も 0.9436 → 0.9582 に改善します。 つまり「高齢化率が高い県ほど死亡率の増え方が加速する」凸型の湾曲が実データに存在します。 R² が高くても直線が最良とは限らない好例です。 ただし二次項モデルの外挿はさらに危険(放物線は範囲外で暴れる)なので、 解釈は観測範囲 22.8–39.1% 内に限定します。
| 仮定 | 検定・指標 | 実測値(単回帰) | 判定 |
|---|---|---|---|
| 等分散性 | Breusch–Pagan | p = 0.578 | 違反の証拠なし |
| 正規性 | Shapiro–Wilk(残差) | W = 0.947, p = 0.034 | 5% 水準で棄却(奈良などの裾の影響) |
| 独立性 | Durbin–Watson | 1.63 | おおむね良好(2 に近い) |
正規性がやや怪しいので、 係数の標準誤差を頑健化した HC3 ロバスト標準誤差を併記すると、 SE(β₁) は通常の 0.022 → 0.032 に広がります。 それでも t は約 19 で結論(有意な正の傾き)は変わらず、 「診断 → 頑健化 → 結論の頑健性確認」という流れを実データで一周できます。 正規性・残差・VIF も参照。
OLS を出発点に、 どの仮定を緩めるとどの手法に行き着くかを整理します。 SSDSE-B の実測値(2023 年度, n=47)で手法間の違いも確認します。
| 緩める仮定・課題 | 手法 | 要点 |
|---|---|---|
| 等分散・無相関の誤差 | GLS / WLS | 誤差の分散構造を重みに組み込む一般化。 パネル・時系列で活躍(パネルデータ・固定効果) |
| 多重共線性・高次元 | Ridge / Lasso / Elastic Net | 正則化でバイアスを許容し分散を抑える |
| 正規誤差・連続応答 | GLM(ロジスティック / ポアソン・プロビット) | リンク関数と指数型分布族で二値・件数・比率に対応 |
| 線形の関数形 | GAM(一般化加法モデル) | y = β₀ + f₁(x₁) + f₂(x₂) + … と滑らかな関数の和で表現。 ③で見た湾曲を自動で捉える |
| 外れ値への脆弱性 | 頑健回帰(Huber M 推定など、 ロバスト統計) | 大きな残差の重みを下げて推定 |
| 「平均」しか見ない | 分位点回帰 | 中央値・第 1/第 3 四分位など分布の任意の位置の傾きを推定 |
| 推定法 | 切片 | 傾き β₁ | 読み方 |
|---|---|---|---|
| OLS | −5.17 | 0.610 | 条件付き平均の傾き |
| Huber 頑健回帰 | −5.54 | 0.622 | 外れ値の重みを下げても傾きはほぼ同じ → 結果は頑健 |
| 分位点回帰 τ=0.25 | −5.80 | 0.622 | 死亡率が低め側の県の傾き |
| 分位点回帰 τ=0.50(中央値) | −5.63 | 0.624 | 中央値の傾き。 OLS とほぼ一致 |
| 分位点回帰 τ=0.75 | −4.80 | 0.606 | 死亡率が高め側の県の傾き |
5 通りの推定で傾きは 0.606–0.624 に収まり、 「高齢化率 1pp ≒ 死亡率 +0.6 ‰」という結論が推定法に依存しないことが確認できます。 このように複数手法で同じ結論に到達することを示すのが、 現代的な頑健性報告(sensitivity analysis)の基本形です。
回帰係数を因果効果に近づけるには、 「x が誤差項と無相関(外生性)」という条件が鍵です(外生性・内生性)。 観察データでこの条件を確保する代表的な設計:
SSDSE-B 単年の横断面ではこれらは適用しにくいものの、 年度を縦に積んだパネル(12 年 × 47 県 = 564 行)にすれば、 固定効果モデルや DID 的な設計が現実的になります。 「回帰で相関構造を記述 → 設計を強化して因果に接近」という 2 段構えが実務の王道です。
さらに深掘りする関連ページ: 線形回帰 OLS 重回帰 回帰係数 残差 調整済み R² GAM 分位点回帰 ロバスト統計 正則化 交絡 操作変数法