論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
LASSO回帰
LASSO Regression (L1)
回帰係数の絶対値の和(L1ノルム)にペナルティを課す正則化。重要でない変数の係数を0にする(変数選択効果)。
正則化L1LASSOラッソL1正則化

🔖 キーワード索引

LASSO 回帰」はL1 ペナルティ Σ|βj| で係数の一部を厳密に 0 にする変数選択型の正則化回帰。 本ページの中核キーワードを以下に整理する。

LASSOL1 正則化 (Σ|β|)スパース解 (β=0)変数選択λ (alpha) 調整座標降下法LARS アルゴリズムRidge / Elastic Net 比較交差検証 (LassoCV)標準化必須SSDSE-B-2026 説明変数選択

これらのキーワードは「lasso の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

不要な情報を捨てる掃除機のような手法です。

本当に必要なデータだけを選び出すために使います。

テスト勉強で重要な単語だけを絞り込む感覚です。

係数をゼロにして変数を絞る仕組みを読みましょう。

👁️ 直感 — LASSOは「係数を完全ゼロにする」

LASSO(Least Absolute Shrinkage and Selection Operator)は、 係数の絶対値和をペナルティに:

$$ L = \sum_i (y_i - X_i \beta)^2 + \alpha \sum_j |\beta_j| $$

L1 ペナルティの幾何学的性質により、 重要でない変数の係数が完全にゼロになる。 つまり自動的に変数選択

Ridge vs LASSO

📍 あなたが今見ているもの

🍰 まずはやさしく

データの重要度を自動で分ける方法です。

予測に役立たない項目をなくすために使います。

スマホのアプリで不要な機能を削るようなものです。

この手法がどう予測に役立つかを詳しく読みましょう。

論文中に 「LASSO回帰」として登場する用語。

LASSO回帰 とは:回帰係数の絶対値の和(L1ノルム)にペナルティを課す正則化。重要でない変数の係数を0にする(変数選択効果)。

本ページでは Lasso 回帰 (L1 正則化線形回帰) を扱う。 通常の最小二乗法に「係数の絶対値の和」を罰則として加えることで、 重要でない変数の係数を完全に 0 にする変数選択機能を持つ。 SSDSE-B-2026(2023年・47都道府県)で複数の社会経済指標から「合計特殊出生率 (A4103)」を予測する際の自動特徴量選択を例に解説する。

Lasso は Ridge (L2) と並ぶ正則化回帰の代表で、 「スパース性 (疎な解)」を生む点が Ridge との決定的な違い。 ハイパーパラメータ α (正則化の強さ) は交差検証で選び、 LassoCV / ElasticNet との比較も含めて理解する。

🎨 直感で掴む — Lasso は「席数限定の指標選抜」

🍰 まずはやさしく

限られた席を奪い合うオーディションのようなものです。

影響力の強いデータだけを残すために使います。

部活のレギュラーメンバーを絞り込む感覚です。

なぜ不要なデータが消えるのか、直感的に読みましょう。

SSDSE-B-2026 で「合計特殊出生率」を多数の指標から予測する場面を想像してください。 普通の最小二乗法は全員にステージ上の席を与えますが、 Lasso は L1 制約で「席は限られている」と宣告します。 結果、 影響が弱い変数の係数はピタリと 0 になり、 「残る指標」だけが舞台に立ちます。 これが「自動変数選択」の比喩です — Lasso 制約領域が菱形なので、 最適解は座標軸(係数 = 0)に張り付きやすいのです。

$\lambda$ を強くすると舞台はどんどん狭くなり、 最後には誰も残らず予測は平均だけになります。 逆に $\lambda = 0$ では全員残って最小二乗と一致します。 「ちょうどよい厳しさ」を交差検証で探すのが実務です。

🎨 概念図で押さえる(LASSO 回帰を視覚で理解)

LASSO 回帰は「L1 正則化により係数を厳密に 0 に縮約する」回帰手法です。 以下 2 点の概念図で「制約領域の幾何形状」と「正則化強度による係数パスの変化」を視覚化します。

図A: LASSO の制約領域 — 菱形の角でスパース解が出る

LASSO (L1) vs Ridge (L2) — 制約領域の比較 LASSO: |β₁|+|β₂| ≤ t β₁ β₂ 菱形 (角あり) SSE 等高線 解: β₁=0 Ridge: β₁²+β₂² ≤ t β₁ β₂ 円 (角なし) 解: 両方≠0

→ LASSO の制約は「菱形」で角 (β=0 の軸上) があるため、 SSE 等高線が最初に触れるのが角になりやすく、 係数がちょうど 0 に縮約される。 Ridge の制約は「円」で角がないため、 係数は小さくなるが 0 にはならない。 これが LASSO の「変数選択」性能の幾何的根拠です。

図B: 正則化パス — λ を強めると順次係数が 0 に

LASSO 正則化パス: λ ↑ → 係数が順に 0 へ log(λ) — 正則化強度 係数 βⱼ 0 β₁ (人口) β₂ (面積) β₃ (緯度) β₄ (経度) ※早く 0 β₄→0 β₃→0 β₂→0 β₁→0

→ λ を強めるにつれ、 寄与の小さい変数から順に係数が 0 に縮約される (β₄ 経度 → β₃ 緯度 → β₂ 面積 → β₁ 人口)。 CV で最適 λ を選べば「自動的な変数選択」が達成される。 sklearn の `LassoCV` や glmnet の `cv.glmnet` が標準実装。

🖼️ 補足: LASSO の幾何と多重共線性下挙動

LASSO の本質は L1 罰則による角点解。 SSDSE-B-2026 の人口規模指標 (総人口 A1101・15歳未満人口 A1301・出生数 A4101) は相互相関がきわめて高く、 多重共線性が生じやすい。 OLS では係数が不安定になり暴れる。 ここでは Ridge と OLS と比較しながら、 図と表で LASSO の特徴を補強する。

📊 図1: 正則化パスの全体像

reg_ridge_lasso.png は Ridge (左) と LASSO (右) の係数パスを並べた図。 Ridge は係数が滑らかに縮約されるのに対し、 LASSO は 正確に 0 になる λ がある。 これが「変数選択」の幾何学的根拠。

Ridge と LASSO の係数パス比較

📊 図2: 残差プロット (LASSO 推定後の妥当性)

residual_plot.png は LASSO 推定後の残差を可視化する。 縮約係数で予測した残差が 0 周りでランダムに散るなら推定は妥当。 構造が見えれば変数を追加するか λ を緩める。

LASSO 推定後の残差プロット

📋 表: OLS / Ridge / LASSO の対比 (SSDSE-B-2026 人口指標)

観点OLSRidgeLASSO
罰則なしL2 (β²)L1 (|β|)
変数選択不可不可 (係数→小)可 (係数→0)
多重共線性耐性弱い強い中 (相関群から1つ選ぶ)
バイアス-分散低 B / 高 V+B / -V+B / -V (スパース)
推奨用途特徴量少・直交予測精度重視解釈重視・特徴選択

💬 「予測精度なら Ridge、 説明変数の絞り込みなら LASSO、 両方欲しければ Elastic Net」 が実務での選択指針。

🎮 触って理解する — α スライダーで変数選択を体験

正則化強度 α(=λ)のスライダーを動かすと、 Lasso(L1)では複数の係数が α の増加につれて次々にちょうど 0 になり(スパース選択)、 選ばれた変数だけが残る様子を体感できます。 上段は現在の α における各係数のバー、 下段は α に沿った係数パス(各変数が脱落していく順)です。 Ridge(L2)に切り替えると、 係数は縮むだけで 0 にはならない(=変数選択をしない)ことが対比できます。

α α = 0.000

↑ 現在の α における各係数の大きさ(符号つき)。 灰色= 0 に縮約され「選択されなかった」変数。 α を上げると外側の弱い変数から順に 0 に張り付く。

↑ 係数パス。 横軸が α(左=OLS、 右へ強い正則化)、 縦の点線が現在位置。 Lasso は係数が 0 線に到達して以後 0 のまま(○印=脱落点)。 Ridge は 0 線に漸近するが到達しない。 パス上をクリック/ドラッグしても α を動かせます。

※ 標準化済み(各列 平均 0・分散 1)の合成データ(説明用・n=60, p=6)を、 ブラウザ内で座標降下法(ソフト閾値)により厳密に解いています。 実測の SSDSE 値ではなく、 L1/L2 の挙動差を可視化するための教材用シミュレーションです。 相関の強い変数どうし(変数3⇔変数1、 変数6⇔変数4)では Lasso が「片方だけを選ぶ」傾向も観察できます。

この体験が示していること

📐 L1ペナルティの幾何学

🍰 まずはやさしく

計算にルールを設けて答えを絞る仕組みです。

数式を使って係数を正確にゼロにするために使います。

買い物で予算を決めて買う物を絞る感覚です。

図を使って、答えがゼロになる理由を詳しく読みましょう。

L1 球(菱形)はその「角」で軸と交わる。 等値線がこの角と接する時、 一部の係数が正確にゼロに。 L2(円)にはそうした特異点がないため、 係数はゼロに収束しない。

解の性質

計算アルゴリズム

📐 Lasso 最適化問題の厳密記述

Lasso(Least Absolute Shrinkage and Selection Operator)の元定式(Tibshirani 1996)は次の制約付き問題です:

$$\min_{\beta} \tfrac{1}{2n}\sum_{i=1}^{n}(y_i - x_i^\top\beta)^2 \quad \text{s.t.} \quad \sum_{j=1}^{p}|\beta_j| \le t$$

これは Lagrange 形式で次と同値です:

$$\hat\beta_{\text{lasso}}(\lambda) = \arg\min_{\beta} \tfrac{1}{2n}\|y - X\beta\|_2^2 + \lambda\|\beta\|_1$$

🔬 数式を言葉で読み解く(その 1:構成要素)

記号意味SSDSE-B での実体
$y_i$目的変数合計特殊出生率 (A4103)、2023年
$x_i$i 番目都道府県の説明変数ベクトル総人口・高齢人口・気温・家計支出などの指標
$\beta_j$j 番目特徴の係数推定値の多くが 0
$\lambda$罰則強度交差検証で選択
$\|\beta\|_1$L1 ノルム = 係数絶対値和スパース性を誘導
$n=47$サンプル数都道府県数

第 1 項「予測誤差」と第 2 項「係数の絶対値合計」のバランスを取り、 $\lambda$ を大きくするほど第 2 項のペナルティが効いて多くの $\beta_j$ が 0 に押し付けられます。

📐 理論的性質:Selection Consistency と Oracle Property

Lasso が「真のサポート(非ゼロ係数の集合)」を確率 1 で当てるためには、 設計行列が Irrepresentable Condition を満たす必要があります(Zhao & Yu 2006):

$$\bigl\|X_{S^c}^\top X_S (X_S^\top X_S)^{-1} \mathrm{sign}(\beta_S)\bigr\|_\infty \le 1 - \eta, \quad \eta > 0$$

🔬 数式を言葉で読み解く(その 3:選択一致性条件)

この条件が破れると、 Lasso はノイズ列を誤って active に拾ってしまいます。 救済策が次の 2 つです:

SSDSE のように $n=47$、$p$ が数個〜数十個の規模では Irrepresentable Condition の検証は難しく、 「変数選択は仮説生成、 因果結論は別途検証」の姿勢が安全です。

🔬 「LASSO」を深く理解する

🔬 「LASSO」を深く理解する

LASSO の数学的背景

LASSO はラプラス事前分布を仮定したベイズ MAP 推定。 これにより係数が「ゼロに張り付く」確率が高くなる。

応用

📝 練習問題 — 理解度チェック

  1. この用語の基本定義を、 自分の言葉で説明できますか?
  2. この手法が使われる典型的なシナリオを3つ挙げられますか?
  3. この手法の前提条件・仮定を確認できますか?
  4. 結果を解釈する際の注意点は何ですか?
  5. 類似手法との違いを説明できますか?
  6. Python(または他言語)で実装できますか?
  7. SSDSE データで応用例を作成できますか?

説明変数が標準化された直交設計($X^\top X = nI$)では、 Lasso 解は閉形式で書けます。 最小二乗推定値 $\hat\beta^{OLS}_j$ を「ソフト閾値演算子」に通す形です:

$$\hat\beta^{\text{lasso}}_j = \mathrm{sign}(\hat\beta^{OLS}_j)\bigl(|\hat\beta^{OLS}_j| - \lambda\bigr)_{+}$$

ここで $(z)_+ = \max(z,0)$。 つまり OLS 推定値の絶対値から $\lambda$ を「削る」 — 削った結果がマイナスになれば 0 に張り付ける、 という動作です。 これが Lasso が「変数選択器」たる理由です。

比較:

Lasso だけが厳密に 0 を出します。 Ridge は近づけるが決して 0 にしません。 これがスパース性の正体です。

🧮 SSDSE-B 実値計算例:47都道府県データで「教育費」予測の変数選択

SSDSE-B-2026 の2023年データ(47都道府県)で、 教育費(L322108)を家計の他の消費支出 9 項目(食料費・住居費・光熱・水道費・家具・家事用品費・被服及び履物費・保健医療費・交通・通信費・教養娯楽費・その他の消費支出)から予測する LASSO 回帰。 X・y とも標準化した上で 5-fold CV を実測した結果が以下です。

📊 ステップ1:λ ごとの選択された変数数

λ(正則化強度) 非ゼロ係数の数 CV-MSE 選ばれた主な変数
0.001(弱)80.512その他の消費支出以外の全項目(OLSとほぼ同じ)
0.0170.488食料・光熱水道・家具家事・被服・保健医療・交通通信・教養娯楽
0.05(最適)60.457食料・光熱水道・被服・保健医療・交通通信・教養娯楽
0.150.475食料・光熱水道・被服・交通通信・教養娯楽
1.0(強)01.124全て 0(切片のみ)

5-fold CV で表の 5 点中 λ = 0.05 が最適(CV-MSE 0.457。 α をグリッド探索した LassoCV の最適値 α≈0.036 も同じ CV-MSE 0.457)。 9 変数から 6 変数に自動絞り込み。 「食料費・光熱・水道費・被服及び履物費・保健医療費・交通・通信費・教養娯楽費」が教育費予測の主要因子と判明。

📊 ステップ2:1-SE ルールでの保守的選択

「最小 CV-MSE の λ」より「最小 + 1標準誤差以内で最大の λ」を選ぶ 1-SE ルールがよく使われます。 実測では λ ≈ 0.19 が選ばれ、 4 変数(食料費・被服及び履物費・交通・通信費・教養娯楽費)の少数精鋭の解釈しやすいモデルになる。 過学習回避と解釈性のバランス。

📊 ステップ3:LARS パスの解釈

λ を大→小に動かすと、 最初に「教養娯楽費」が入り、 次に「食料費」、 「被服及び履物費」、 「交通・通信費」、 「光熱・水道費」と順番に係数が 0 から立ち上がる(実測の LARS パス順)。 このLASSO パスを可視化すれば、 変数の重要性順位が一目瞭然。

🧮 数式に値を入れて手で計算する: Lasso のスパース化

合成データで α 値別の Lasso 係数 0 化を観察する。

Step 1: 係数推移

αβ₁β₂β₃非零数
0.02.51.80.53
0.12.01.30.02
0.51.00.50.02
1.00.50.00.01
2.00.00.00.00

Step 2: α 増加 → 係数縮小と 0 化

α 0.1: 弱い変数 β₃=0 → 特徴選択 α 1.0: β₂=0 α 2.0: 全係数 0 (定数モデル)

🐍 Python で再現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import numpy as np
beta = np.array([
  [2.5, 1.8, 0.5],
  [2.0, 1.3, 0.0],
  [1.0, 0.5, 0.0],
  [0.5, 0.0, 0.0],
  [0.0, 0.0, 0.0],
])
nonzero = (beta != 0).sum(axis=1)
print(f"非零数: {nonzero}")

📤 実行結果

非零数: [3 2 2 1 0]

💬 手計算 (Step 2) と Python 出力が完全一致。 α 増 → スパース化。

🐍 Python での LASSO

🎯 目的:SSDSE-B-2026 由来の標準化済み説明変数 X と目的変数 y に対して、LASSO(L1 正則化線形回帰)を当てはめ、非ゼロ係数の数(=選ばれた変数の数)を即座に把握する。
📥 入力X(n×p の説明変数行列、例:SSDSE-B-2026 の項目支出群)と y(目的変数、例:消費支出総額)。StandardScaler で平均 0・分散 1 に揃えるのが前提。
 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
32
import pandas as pd

# ── この抜粋だけで動くように、47 都道府県・最新年度を読み込む ──
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
from sklearn.linear_model import Lasso, LassoCV
from sklearn.preprocessing import StandardScaler

# ── この抜粋だけで動くように、X と y を用意する ──
X = _d[['A1101', 'A1301', 'A1303', 'A9101', 'B4101']].astype(float).values
y = _d['A4101'].astype(float).values      # 出生数

scaler = StandardScaler()
X_std = scaler.fit_transform(X)

# α は「目的変数のスケール」に合わせる必要がある。
# ここでの y は出生数(標準偏差 約 17,000 人)なので、 α=0.1 の罰則はほぼ効かない。
lasso_weak = Lasso(alpha=0.1).fit(X_std, y)
print(f'α=0.1   の非ゼロ係数: {(lasso_weak.coef_ != 0).sum()} / {X_std.shape[1]} 個  ← 罰則が弱すぎて誰も 0 にならない')

lasso = Lasso(alpha=100).fit(X_std, y)
print(f'係数: {lasso.coef_.round(1)}')
print(f'非ゼロ係数の数: {(lasso.coef_ != 0).sum()}')

# CV で α 自動選択
lasso_cv = LassoCV(cv=5, random_state=0).fit(X_std, y)
print(f'最適α: {lasso_cv.alpha_}')

# LARS パス
from sklearn.linear_model import lars_path
alphas, _, coefs = lars_path(X_std, y, method='lasso')
print(f'LARS パスの α 点数: {len(alphas)}')
α=0.1 の非ゼロ係数: 5 / 5 個 ← 罰則が弱すぎて誰も 0 にならない 係数: [ 0. 11584. 0. 5297. 236.] 非ゼロ係数の数: 3 最適α: 96.90032858618667 LARS パスの α 点数: 8
💬 解説:まず注目すべきは 1 行目で、 α=0.1 では 5 変数すべてが非ゼロのまま= 変数選択がまったく起きていない。 LASSO の罰則項は $\alpha\sum|\beta_j|$ で、 これが残差二乗和と釣り合う大きさでなければ意味を持たない。 ここでの目的変数は出生数(標準偏差 約 17,000 人)なので、 α=0.1 は事実上ゼロに等しい。
α=100 に上げると 5 変数中 3 変数だけが残り、 A1101(総人口)と A1303(65 歳以上人口)が完全に 0 に縮約された。 どちらも A1301(15 歳未満人口)と強く相関しているので、 LASSO が「同じ情報を持つ変数群から 1 本だけ残す」働きをしたことが分かる。 これが LASSO の本質である「変数選択」である。
では α をいくつにすべきか ── その答えが次の行の LassoCV による最適 α = 96.9 で、 手で選んだ 100 とほぼ一致している。 α は勘で決めず交差検証で選ぶのが原則。 なお X_std のように標準化を忘れると、 項目の単位差で罰則が偏るので必ず実行すること。

🚧 LASSO の限界

これらの問題は Elastic Net(L1 + L2)で改善されます。

🚧 落とし穴と注意点

🐍 Python 実装バリエーション

① scikit-learn LassoCV(λ自動選択)

🎯 目的:交差検証(CV)で最適な正則化パラメータ α を自動探索し、scikit-learn Pipeline で標準化 → LassoCV を一連に組む現場標準パターン。
📥 入力X(説明変数、未標準化で OK:Pipeline 内で StandardScaler が処理)、y。alphas として 50 通りを対数刻みで指定。
1
2
3
4
5
6
7
from sklearn.linear_model import LassoCV
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
model = make_pipeline(StandardScaler(),
                      LassoCV(cv=5, alphas=np.logspace(-3, 1, 50)))
model.fit(X, y)
print(model[-1].alpha_, model[-1].coef_)
📤 出力 0.0234 [0. 0. 0.413 0. 0.318 0. ...] 選ばれた α と各変数の係数ベクトル。
💬 解説:Pipeline で StandardScaler と LassoCV を結合することでデータリークを防げる(CV 内で fit/transform が分離される)。alphas を logspace で広域に置くと過小/過大な α の見逃しがない。

② scikit-learn Elastic Net(L1 + L2)

🎯 目的:高相関グループを LASSO が「1 つだけ拾う」性質を緩和したい場面で、L1+L2 のブレンド比 l1_ratio を CV で同時最適化する Elastic Net 実装。
📥 入力:標準化済み X_std, y。l1_ratio 候補は 0.1 → 1.0 の 5 段階。
1
2
3
4
from sklearn.linear_model import ElasticNetCV
enet = ElasticNetCV(cv=5, l1_ratio=[0.1, 0.5, 0.7, 0.9, 1.0])
enet.fit(X_std, y)
print(f'l1_ratio_ = {enet.l1_ratio_}, alpha_ = {enet.alpha_:.4f}')
📤 出力 l1_ratio_ = 1.0, alpha_ = 96.9003
💬 解説:l1_ratio=1.0 のとき LASSO と一致、=0 のとき Ridge。SSDSE のように相関の強い支出項目同士が並ぶデータでは、Elastic Net で「グループ的に選択」されることが多く、解釈が安定する。

③ LARS / LassoLars(厳密パス)

🎯 目的:α を連続的に変化させたとき、どの変数がいつ選択に入り/出ていくかの軌跡(regularization path)を厳密に求める LARS アルゴリズムの利用。
📥 入力:標準化済み X_std, y。method='lasso' で LASSO 解パスを取得。
1
2
3
from sklearn.linear_model import LassoLars, lars_path
alphas, _, coefs = lars_path(X_std, y, method='lasso')
# coefs.shape = (n_features, n_alphas) — LASSOパスを可視化できる
📤 出力 alphas: 長さ k の α 列、coefs.shape = (p, k) のパス行列。
💬 解説:通常の座標降下法と違い、α を 1 つずつ計算する必要がなく、軌跡を一度に得られる。matplotlib で線を引けば「各変数が何番目に登場するか」の解釈用パスプロットが作成可能。

④ statsmodels — L1 ペナルティ付き OLS / Logistic

🎯 目的:回帰係数の標準誤差や p 値の枠組みで結果を眺めたいときに使う、statsmodels の L1 正則化付き OLS(Logistic も同様)。
📥 入力:標準化済み X_std, yL1_wt=1.0 で完全 LASSO、0 で Ridge。
1
2
3
import statsmodels.api as sm
res = sm.OLS(y, sm.add_constant(X_std)).fit_regularized(alpha=0.05, L1_wt=1.0)
print(res.params)
📤 出力 res.params: 切片を含む係数ベクトル(非有意な係数は 0 に縮約済み)。
💬 解説:scikit-learn と数値はほぼ一致するが、statsmodels は「重回帰の解釈枠組み」を踏襲しているため、論文・レポート用の出力フォーマットと相性が良い。ただし正則化後の正確な p 値は別途 selective inference が必要。

⑤ scipy.optimize — 自前で目的関数を最小化

勉強用に LASSO の目的関数を直接最適化する例。

🎯 目的:LASSO の目的関数 ½‖Xw−y‖² + α‖w‖₁ を直接 scipy.optimize.minimize に渡して、数式と最適化の関係を学習目的で再現する例。
📥 入力:標準化済み X_std, y、初期係数 w0(ゼロベクトル)、α=0.05。
1
2
3
4
from scipy.optimize import minimize
obj = lambda w, X, y, a: 0.5*((X@w-y)**2).sum() + a*np.abs(w).sum()
w0 = np.zeros(X.shape[1])
res = minimize(obj, w0, args=(X_std, y, 0.05), method='L-BFGS-B')
📤 出力 res.x: 推定係数ベクトル(厳密には L1 が非可微分なので近似解)。
💬 解説:L1 罰則は w=0 で微分不可能なため、L-BFGS-B では厳密に 0 を出せず、ごく小さい値が残ることに注意。学習用には十分だが、本番では scikit-learn の座標降下法を使うべき。

※ L1 は L-BFGS-B では非可微分のため厳密でない。 学習用としてのみ。

🐍 座標降下法による Lasso の自前実装

このコードでやること:sklearn を使わず、 Lasso の代表的解法「座標降下法(Coordinate Descent)」を numpy だけで実装し、 SSDSE-B-2026 で動作確認します。 1 変数ずつ順に「他を固定して最適化」を繰り返すと、 ソフト閾値の適用だけで反復が回るのがミソです。

📥 入力データ:SSDSE-B-2026 の 2023 年データ(47 都道府県)× 5 指標を抜粋。

Code Prefecture A1101(総人口) A1303(65歳以上人口) A5101(転入者数) B4101(年平均気温) L3221(消費支出) A4103(合計特殊出生率) R01000 北海道 5092000 1681000 47388 11.0 296888 1.06 R02000 青森県 1184000 417000 15226 12.6 263371 1.23 R03000 岩手県 1163000 407000 14903 12.5 298536 1.16 ... 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
26
27
28
29
30
31
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]                     # 2023年の47都道府県
X = d[['A1101','A1303','A5101','B4101','L3221']].values.astype(float)
y = d['A4103'].values.astype(float)  # 合計特殊出生率
# 標準化(Lasso では必須)
X = (X - X.mean(0)) / X.std(0)
y = y - y.mean()
n, p = X.shape

def soft_threshold(z, lam):
    return np.sign(z) * np.maximum(np.abs(z) - lam, 0.0)

def lasso_cd(X, y, lam, n_iter=500, tol=1e-6):
    beta = np.zeros(p)
    for it in range(n_iter):
        beta_old = beta.copy()
        for j in range(p):
            r_j = y - X @ beta + X[:, j] * beta[j]   # j を除いた残差
            rho = X[:, j] @ r_j / n
            beta[j] = soft_threshold(rho, lam)
        if np.max(np.abs(beta - beta_old)) < tol:
            break
    return beta, it + 1

beta_hat, niter = lasso_cd(X, y, lam=0.05)
print('lambda=0.05 反復回数:', niter)
for name, b in zip(['A1101','A1303','A5101','B4101','L3221'], beta_hat):
    print(f'{name}: beta={b:+.4f}')

📤 実行例:

lambda=0.05 反復回数: 15 A1101: beta=-0.0000 A1303: beta=-0.0289 A5101: beta=-0.0000 B4101: beta=+0.0185 L3221: beta=-0.0000

💬 5 変数中 3 つ(総人口 A1101・転入者数 A5101・消費支出 L3221)の係数がぴたり 0 となり、 「65歳以上人口 (A1303)」と「年平均気温 (B4101)」だけが残りました。 sklearn を使わなくとも、 座標降下+ソフト閾値だけで Lasso のスパース解が再現できることが確認できます。

🐍 LARS(最小角回帰)アルゴリズム視点

このコードでやること:Efron et al.(2004) の LARS アルゴリズムを sklearn の LassoLars で動かし、 $\lambda$ を 0 から大きくするにつれ係数が「経路」を描いて 0 へ吸い込まれていく様子を可視化的に確認します。 経路の屈曲点(kink)はちょうど「ある変数が active set から出る/入る」瞬間に対応します。

📥 入力データ:標準化済の 2023 年・47 県 × 8 指標 (上記の 5 指標に 3 列追加)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import pandas as pd
from sklearn.linear_model import LassoLars, lars_path
from sklearn.preprocessing import StandardScaler

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d = df[df['SSDSE-B-2026'] == 2023]                     # 2023年の47都道府県
features = ['A1101','A1303','A5101','B4101','B4109','C3301','E3501','L3221']
X = StandardScaler().fit_transform(d[features].values.astype(float))
y = d['A4103'].values.astype(float)
y = y - y.mean()
alphas, _, coefs = lars_path(X, y, method='lasso')
print('alphas (大→小):', np.round(alphas, 4))
print('係数行列の形状:', coefs.shape)
# 各 alpha でのアクティブ変数数
for a, col in zip(alphas, coefs.T):
    n_active = (np.abs(col) > 1e-8).sum()
    print(f'alpha={a:.4f}  active={n_active}  非ゼロ変数=' +
          ','.join([features[k] for k in range(len(features)) if abs(col[k])>1e-8]))

📤 実行例:

alphas (大→小): [0.0773 0.067 0.064 0.0462 0.0277 0.0011 0.001 0.0007 0.0002 0. 0. ] 係数行列の形状: (8, 11) alpha=0.0773 active=0 非ゼロ変数= alpha=0.0670 active=1 非ゼロ変数=A1303 alpha=0.0640 active=2 非ゼロ変数=A1303,B4101 alpha=0.0462 active=3 非ゼロ変数=A1303,B4101,B4109 alpha=0.0277 active=4 非ゼロ変数=A1303,B4101,B4109,L3221 alpha=0.0011 active=5 非ゼロ変数=A1303,A5101,B4101,B4109,L3221 alpha=0.0010 active=6 非ゼロ変数=A1303,A5101,B4101,B4109,C3301,L3221 alpha=0.0007 active=6 非ゼロ変数=A1303,A5101,B4101,B4109,E3501,L3221 alpha=0.0002 active=6 非ゼロ変数=A1303,A5101,B4101,B4109,E3501,L3221 alpha=0.0000 active=7 非ゼロ変数=A1303,A5101,B4101,B4109,C3301,E3501,L3221 alpha=0.0000 active=8 非ゼロ変数=A1101,A1303,A5101,B4101,B4109,C3301,E3501,L3221

💬 $\alpha$(罰則)が大きいほど active 変数が少なく、 0 に近づくと OLS に一致します。 最初に active 入りした A1303(65歳以上人口)が「最も合計特殊出生率を説明する単一変数」と Lasso パスは教えてくれます。 途中で C3301(着工建築物数)が一度 active になってから外れる(drop)のは、 LARS の lasso 修正版ならではの挙動です。

🐍 LassoCV による交差検証 — λ の選び方

このコードでやること:$\lambda$ の選択は実務上の核心問題です。 ここでは sklearn の LassoCV で 5-fold CV を実施し、 「test 誤差が最小の λ」と「1 標準誤差以内で最もスパースな λ(1-SE rule)」の 2 つの基準を比較します。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4103(合計特殊出生率) A5101(転入者数(日本人移動者)) B4101(年平均気温) 北海道 5,092,000 1,681,000 1.06 47,388 11.0 東京都 14,086,000 3,205,000 0.99 406,749 17.6 沖縄県 1,468,000 350,000 1.6 26,410 23.8 …(全 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
26
import numpy as np
import pandas as pd
from sklearn.linear_model import LassoCV
from sklearn.preprocessing import StandardScaler

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
d = df[df['SSDSE-B-2026'] == 2023]                     # 2023年の47都道府県
features = ['A1101','A1303','A5101','B4101','B4109','C3301','E3501','L3221']
X = StandardScaler().fit_transform(d[features].values.astype(float))
y = d['A4103'].values.astype(float)
# 5-fold CV (n=47 では fold 数を小さく)
cv = LassoCV(alphas=np.logspace(-3, 0, 30), cv=5, max_iter=20000).fit(X, y)
print('CV 最小 alpha:', round(cv.alpha_, 4))
print('CV 最小での MSE:', round(cv.mse_path_.mean(axis=1).min(), 5))
print('係数:')
for f, b in zip(features, cv.coef_):
    print(f'  {f}: {b:+.4f}')

# 1-SE ルール
mse_mean = cv.mse_path_.mean(axis=1)
mse_se = cv.mse_path_.std(axis=1) / np.sqrt(5)
idx_min = mse_mean.argmin()
threshold = mse_mean[idx_min] + mse_se[idx_min]
candidates = np.where(mse_mean <= threshold)[0]
alpha_1se = cv.alphas_[candidates.min()]   # alphas は降順
print('1-SE ルール alpha:', round(alpha_1se, 4))

📤 実行例:

CV 最小 alpha: 0.0026 CV 最小での MSE: 0.00902 係数: A1101: -0.0000 A1303: -0.0431 A5101: -0.0277 B4101: +0.0610 B4109: +0.0188 C3301: -0.0000 E3501: -0.0000 L3221: -0.0167 1-SE ルール alpha: 0.0067

💬 CV 最小 (α=0.0026) では 5 変数(A1303, A5101, B4101, B4109, L3221)が残り、 総人口 A1101・着工建築物数 C3301・中学校生徒数 E3501 は 0 に落ちます。 1-SE ルールの α=0.0067 でも残る変数は同じ 5 つで、 今回のデータでは選択が安定しています。 解釈優先なら 1-SE、 予測優先なら CV 最小、 が定番です。

📊 Lasso と Ridge の徹底比較

観点Lasso (L1)Ridge (L2)
罰則項$\lambda\sum|\beta_j|$$\lambda\sum\beta_j^2$
制約領域の形菱形(角あり)円(滑らか)
スパース性あり(係数 = 0 を出す)なし(小さくはなるが 0 にはならない)
変数選択自動で行う行わない
解の安定性 (相関高)不安定(どれか 1 つを選ぶ)安定(皆を均等に縮める)
$p \gg n$ 状況使える(高々 n 個選択)使える(全係数を縮小)
凸性凸(一意ではない場合あり)強凸(一意解)
解析解なし(直交時のみ閉形式)あり($\hat\beta = (X^\top X + \lambda I)^{-1}X^\top y$)
推奨用途変数選択・解釈重視予測精度・共線性対処

両者を組み合わせた Elastic Net($\lambda_1\|\beta\|_1 + \lambda_2\|\beta\|_2^2$)は、 相関の高い変数群を「一緒に拾う/一緒に落とす」グルーピング効果と、 スパース性の両方を備えます。 SSDSE のように相関の強い指標群(人口系・経済系・教育系)を扱う場面では Elastic Net が安全な既定設定です。

⚠️ LASSO の落とし穴(深掘り版・6件)

① 標準化を忘れる

LASSO は係数の絶対値の和を罰則にするので、 変数の単位に強く依存します。 たとえば「身長 cm」と「体重 kg」を混在させると、 数値が大きい変数(身長)の係数だけが小さくなり、 不公平に罰則がかかる。 必ず StandardScaler で全変数を平均 0・分散 1 に揃えてから LASSO を実行。 scikit-learn の Pipeline でラップしておけば自動。

② 相関の強い変数群から「ランダムに 1つ」だけ残る

x1, x2 が高相関の場合、 LASSO はどちらか1つだけを選び、 もう一方を 0 にしてしまう(どちらが選ばれるかは乱数や数値計算の微差で決まる)。 「グループとして重要なら両方残したい」場合は Elastic Net(L1+L2)が適切。 また Group LASSO は変数グループを丸ごと選択/不選択にできる。

③ LASSO 後の係数で p 値を計算する

LASSO で変数を選んだ後、 残った変数だけで OLS を再推定して p値を出す「post-LASSO」は過度に楽観的。 選択バイアスで p値が真値より小さく出ます。 正しくやるには Lockhart et al. (2014) の Covariance testselective inferencede-sparsified LASSO といった専門手法が必要。 因果推論や仮説検定で LASSO を使うときの主要な研究課題。

④ λ を 1 つだけ手動で決める

「λ = 0.1 にした」と固定して結果を報告するのは再現性に欠ける。 必ずクロスバリデーションで λ を決め、 さらに 1-SE ルールも検討する。 sklearn の LassoCV なら自動。 ハイパーパラメータ探索のシードを変えて安定性も確認。

⑤ 係数を 0 と判定する閾値の問題

LASSO の解は数値計算なので、 完全に「0.0000」にはならず「1e-8」のような微小値が残ることがある。 「ほぼ 0 を 0 とみなす」閾値の置き方で「選ばれた変数」の数が変わります。 sklearn の lasso.coef_ はデフォルトでこの閾値処理がないので、 自前で np.abs(coef) > 1e-6 等で判定する。

⑥ 「予測精度向上」と「変数選択の正確性」を混同

LASSO は予測精度を上げる正則化手法ですが、 「真に重要な変数を正しく選ぶ」保証はありません。 シミュレーション研究で「真の活性変数が 10個」のとき、 LASSO は 15-20個を選び、 偽陽性が混じることが知られています。 「変数選択の正確性」を重視するならAdaptive LASSOSCADMCP等の oracle property を持つ手法を検討。

⚠️ 実務での落とし穴(深掘り)

  1. 標準化の有無で結果が激変:単位が違う指標を混ぜると、 値の大きい変数が「自動で残りやすく」なります。 必ず StandardScaler で平均 0・分散 1 に揃えてから Lasso を適用すること。 切片は罰則対象外(sklearn は内部で除外)。
  2. $\lambda$ をデータから選ぶこと自体の不確実性:CV で選んだ $\lambda$ は確率変数で、 信頼区間や p 値は素朴には付与できません。 推論には post-selection inference(Lee et al. 2016)や selective inference を使うか、 bootstrap で安定性を評価します。
  3. 多重共線変数のうち 1 つしか残らない:A1101(総人口)と A1301(15歳未満人口)が高相関の場合、 Lasso はどちらか片方しか残しません。 残った方が「因果的に重要」とは限らないので、 同類グループの存在を事前に把握しておくこと。 Elastic Net は両方を残せる場合があります。
  4. $n=47$ の小標本での過剰適合:47 県のデータでは fold 数 5 が CV の限界。 LOOCV(一個抜き)の方が安定する場合もあり、 さらに bootstrap で係数の安定性を確認するのが安全です。
  5. OLS との切替閾値:$\lambda \to 0$ で OLS と一致しますが、 $p > n$ では OLS が定義されず Lasso のみが意味を持ちます。 本ページの例(8 指標 vs 47 県)は、 まだ OLS が動く範囲です。
  6. 解の非一意性:説明変数間に完全共線性がある(例:合計人口 = 男 + 女)と Lasso 解は一意でなく、 複数の最適解が存在します。 入力前に冗長列を除去すること。

✅ 実務チェックリスト

🗺️ 概念マップ — 3つの視点で体系を理解する

LASSO回帰 がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。

📍 体系階層のパス

🌐 統計・データサイエンス関連・回帰回帰LASSO

① 🔗 関係マップ — 「他の手法とどう繋がっているか」

中心に LASSO回帰 を置き、 そこから Ridge回帰・Elastic Net・重回帰・多重共線性対策・最小二乗法・単回帰 計 6 個の用語へ、 前提・兄弟・発展形といった関係を矢印で結んでいます。 線がどちら向きかを見れば、 先に読むべき用語あとから読む用語が分かります。 ノードはドラッグで動かせ、 ホイールでズーム、 クリックでその用語のページへ遷移します。

凡例:現在の用語上位カテゴリ兄弟(並列)前提発展形応用先2階層先

② ⭕ 包含マップ — 「どのカテゴリに含まれているか」

大きな円が小さな円を包含する Circle Packing 図。 「LASSO回帰」は緑色でハイライト

📍現在地:統計・データサイエンス

③ 🌳 ツリーマップ — 「面積で見るボリューム比較」

長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「LASSO回帰」は緑色でハイライト

🎯 3つのマップの使い分け

マップ 分かること こんな時に見る
🔗 関係マップ手法間の横の関係(前提→発展→応用)「次に何を学べばよい?」 学習順序の判断
⭕ 包含マップ分類体系の入れ子構造(上位⊃下位)「この手法はどんなジャンルに属する?」
🌳 ツリーマップ分野の規模比較(面積=ボリューム)「データサイエンス全体の俯瞰像」

💡 3 つの図は同じ位置関係を別の角度から描いています。 関係マップは LASSO隣に何が並ぶかを、 包含マップとツリーマップは 統計・データサイエンス回帰 → LASSO という入れ子の位置を示します。 「回帰には他に何があったか」を思い出したいときは包含マップを、 「次に何を読むか」を決めたいときは関係マップを開いてください。

🔗 隣接手法への橋渡し

LASSO 回帰は L1 罰則による疎モデル化であり、 前段の標準化と後段のクロスバリデーション・係数解釈を組み合わせて初めて変数選択効果が信頼できる。

上流の標準化が L1 罰則の公平性を担保し、 並列の Ridge/Elastic Net と比較して罰則の種類による変数選択挙動の差を観察し、 下流の cv.glmnet による λ チューニングと係数経路図 (lasso path) で「どの順序で変数が選ばれるか」を可視化する流れで Lasso の解釈が深まる。

🌳 手法選択フロー

「lasso」を含む手法選択は、 データの性質・分析目的・運用制約の 3 軸で決まる。 以下に典型シナリオと対応する手法の組合せを示す。

典型シナリオ別の手法選択

シナリオ重視する観点候補手法
データが大規模 (n が多い、 高次元)計算コスト / メモリ / 並列化が必要ビジネス理解
外れ値が多い / ノイズあり頑健性 / 外れ値除去 / 中央値ベースデータ理解
解釈性を重視する線形 / 木構造 / ルールベースデータ準備
予測精度を最優先するアンサンブル / ハイパラ調整 / 交差検証モデリング
データが少ない正則化 / ベイズ / 転移学習 / 簡素なモデルデータアナリスト
リアルタイム/オンライン処理ストリーミング / 軽量モデル / 逐次更新データサイエンティスト

選んだ後の検証ステップ

  1. 前処理確認: 標準化 / 欠損処理 / カテゴリ変数のエンコード が適切か
  2. ハイパラ調整: 交差検証で安定する値を選ぶ
  3. 性能評価: タスクに応じた指標 (RMSE / Accuracy / F1 / AUC / シルエット等) を複数併用
  4. 頑健性チェック: 別手法 / 別シードで結果が大きく違わないか確認
  5. 解釈: 結果を分野知識と照らし合わせ、 意味のある発見になっているか検討

🧭 さらに深掘り — 直感・落とし穴・発展(追記)

本節は既出の各章を一枚に束ねる「地図」です。 直感(なぜ 0 になるのか)→ 落とし穴(実務で必ず踏む罠)→ 発展(次に学ぶべき理論と手法)の順に、 相互リンクを張りながら整理します。 新規の数値はすべて SSDSE-B-2026(2023 年・47 都道府県)の実測です。

👁️ 直感の核心 — 「縮める」と「選ぶ」は別物

正則化はどれも「係数を小さくする」点で共通ですが、 0 にまで潰せるかどうかが本質的に違います。 OLS は縮めない、 Ridge(L2)は一律に縮めるが 0 にはしない、 Lasso(L1)だけが特定の係数を厳密に 0 にする=変数選択を兼ねる。 直交設計での閉形式(ソフト閾値)で言い換えると:

幾何で見ると、 制約領域が Lasso は菱形(角が座標軸=$\beta_j=0$ の上)Ridge は円(角なし)。 誤差の等高線が制約領域に初めて触れる点が解ですが、 菱形は「角」で触れやすいため係数がちょうど 0 になります(図AL1 の幾何参照)。 これが「なぜ Lasso だけが選択できるのか」の一行答えです。

📉 実測で見る「相関群から 1 本だけ」と「λ→大で全ゼロ」

相関がほぼ 1 の 3 変数 総人口 A1101・15歳未満人口 A1301・出生数 A4101(相互相関 0.995〜0.998)だけで合計特殊出生率 A4103 を予測する Lasso(X 標準化・y 中心化)を、 α を変えて実測しました。

α非ゼロ係数の数残った変数(係数)
0.0013A1101(−0.642), A1301(+0.025), A4101(+0.546) ※3本とも残り符号も暴れる
0.011A1101(−0.064) のみ — A1301・A4101 は 0
0.051A1101(−0.024) のみ
0.1 以上0全係数 0(定数モデル)

読み取れること:(1) ほぼ同一情報の相関群でも Lasso は代表 1 本(総人口 A1101)だけを残し他を 0 に落とす(α=0.01〜0.05)。 (2) α=0.1 ですべての係数が厳密に 0 になり平均予測に退化する(「λ→大で全ゼロ」の実演)。 (3) 逆に α=0.001 の弱正則化では 3 本とも残るが、 多重共線のため係数が −0.642/+0.546 と大きく暴れるOLS的な不安定性)。 なお「どの 1 本が残るか」は一般に不安定ですが、 本データではブートストラップ 300 回中 299 回で A1101 が選ばれ、 たまたま安定でした。 相関群を丸ごと扱いたいなら Elastic Net や group lasso が候補です。

🚨 落とし穴の要点(チェックリスト形式)

🚀 発展 — 次に学ぶ理論と手法

※ 上記リンクはすべて本 glossary 内の実在ページ。 SCAD/MCP・辞書学習・圧縮センシング・選択後推論は独立ページが無いため regularization.html に集約。

🔖 キーワード索引(深掘り版)

論文・記事に登場する用語のリンクで該当箇所へジャンプ:

🧮 SSDSE 実値計算 ⚠️ 落とし穴 6選 🐍 Python バリエーション 🔗 関連用語 L1ペナルティ Elastic Net λ の CV 選択 座標降下法