論文中に 「Elastic Net」として登場する用語。
Elastic Net とは:LASSO(L1)とRidge(L2)の両方のペナルティを混ぜた正則化。両者のいいとこ取り。
Elastic Net は Ridge と LASSO のペナルティを組み合わせた回帰:
$$ L = \sum_i (y_i - X_i \beta)^2 + \alpha [\rho \sum_j |\beta_j| + (1-\rho)/2 \sum_j \beta_j^2] $$
ρ で LASSO vs Ridge の比率を調整。 ρ=1 → LASSO、 ρ=0 → Ridge、 中間 → ハイブリッド。
1 2 3 4 5 6 7 8 9 10 11 12 13 | from sklearn.linear_model import ElasticNet, ElasticNetCV from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_std = scaler.fit_transform(X) # α と l1_ratio を指定 en = ElasticNet(alpha=0.1, l1_ratio=0.5).fit(X_std, y) print(f'係数: {en.coef_}') # CV で両方を自動選択 en_cv = ElasticNetCV(l1_ratio=[0.1, 0.5, 0.7, 0.9, 0.95, 0.99, 1.0], cv=5).fit(X_std, y) print(f'最適α: {en_cv.alpha_}, 最適l1_ratio: {en_cv.l1_ratio_}') |
| 目的 | 1変数 | 2変数 | 多変量 |
|---|---|---|---|
| 記述 | 平均, 中央値, 分散 | 相関, 共分散 | PCA, 因子分析 |
| 可視化 | ヒストグラム, 箱ひげ | 散布図, ヒートマップ | 散布図行列, バイプロット |
| 予測 | 時系列モデル | 単回帰 | 重回帰, Ridge, LASSO |
| 分類 | ロジスティック回帰 | 判別分析 | SVM, RF, NN |
| グループ化 | 階級分け | 2次元クラスタリング | k-means, 階層クラスタリング |
| 検定 | 1標本t検定 | 2標本t検定, χ² | ANOVA, MANOVA |
| n | 推奨手法 |
|---|---|
| n < 10 | 記述統計のみ、 ノンパラ検定、 ベイズ統計 |
| 10 ≤ n < 30 | t検定, ブートストラップ, 単回帰 |
| 30 ≤ n < 200 | 重回帰, ANOVA, 階層クラスタリング |
| 200 ≤ n < 10000 | 複雑な回帰, RF, GBM, k-means |
| n ≥ 10000 | 深層学習, 大規模分散学習 |
| ライブラリ | 用途 |
|---|---|
| numpy | 数値計算の基礎、 行列演算 |
| pandas | データフレーム、 表操作 |
| scipy | 統計関数、 最適化、 線形代数 |
| statsmodels | 古典統計、 検定、 回帰分析の詳細 |
| scikit-learn | 機械学習、 前処理、 評価 |
| matplotlib | 基本可視化 |
| seaborn | 統計的可視化(高級) |
| plotly | インタラクティブ可視化 |
| xgboost / lightgbm | 勾配ブースティング |
| PyTorch / TensorFlow | 深層学習 |
このページで扱った概念を、 学習効率のためにまとめます。 これを毎日見ることで、 統計の基礎が体に染み込みます。
| 記号 | 意味 | 読み方 |
|---|---|---|
| μ | 母平均 | ミュー |
| σ | 母標準偏差 | シグマ |
| σ² | 母分散 | シグマ二乗 |
| x̄ | 標本平均 | エックスバー |
| s | 標本標準偏差 | エス |
| n | 標本サイズ | エヌ |
| p | p値、 比率 | ピー |
| α | 有意水準 | アルファ |
| β | 回帰係数、 第二種誤り率 | ベータ |
| r | 相関係数 | アール |
| R² | 決定係数 | アール二乗 |
| Σ | 総和記号、 共分散行列 | シグマ大文字 |
| N(μ, σ²) | 正規分布 | ノーマル ミュー シグマ二乗 |
| t(df) | t分布 | ティー |
| χ²(df) | カイ二乗分布 | カイ二乗 |
| F(d1, d2) | F分布 | エフ |
| H₀, H₁ | 帰無仮説、 対立仮説 | エイチゼロ、 エイチワン |
| E[X] | 期待値 | エクスペクタンス |
| Var(X) | 分散 | バリアンス |
| Cov(X, Y) | 共分散 | カバリアンス |
💡 統計学・データサイエンスは「記号の意味を理解する」ことが最初の壁。 各記号が何を表すか、 公式の中での役割を覚えてしまえば、 後はパターンの組合せで様々な手法が理解できます。
(CRISP-DM プロセスより)
| 分野 | 主要技術 | 代表ツール |
|---|---|---|
| 記述統計 | 要約量、 可視化 | pandas, matplotlib |
| 推測統計 | 検定、 信頼区間 | scipy.stats, statsmodels |
| 機械学習 | 予測、 分類、 クラスタリング | scikit-learn, XGBoost |
| 深層学習 | NN、 画像、 自然言語 | PyTorch, TensorFlow |
| 時系列 | ARIMA、 状態空間、 LSTM | statsmodels, prophet |
| 因果推論 | RCT、 IV、 DiD、 PSM | DoWhy, EconML |
| ベイズ統計 | MCMC、 変分推論 | PyMC, Stan |
| 最適化 | 線形/凸/離散最適化 | scipy.optimize, cvxpy |
これらは互いに深く関連します:
| 前提 | 関連 | 発展 |
|---|---|---|
| 平均、 分散、 標準偏差 | 類似手法、 派生手法 | 機械学習での応用 |
| 確率分布 | 統計的検定 | ベイズ統計 |
| 数値計算 | 可視化技術 | 深層学習 |
L1(菱形)と L2(円)の混合により、 制約領域が「角の取れた菱形」のような形に。 これが「変数選択(角があるから)」と「安定性(角が丸まっているから)」の両立を実現。
| 状況 | 推奨 |
|---|---|
| 変数が多くて相関も強い | Elastic Net(l1_ratio=0.5) |
| 少数の重要変数だけ選びたい | LASSO(l1_ratio=1) |
| 全変数が少しずつ寄与 | Ridge(l1_ratio=0) |
| n < p の高次元 | Elastic Net(LASSO単独は不安定) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | # 基本パターン import pandas as pd import numpy as np from scipy import stats import matplotlib.pyplot as plt import seaborn as sns # データ読み込み df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932') # 基本統計量 df.describe() # 可視化 sns.pairplot(df[['食料費', '教育費', '住居費']]) plt.show() |
このページの上にある3つの概念マップ(関係マップ、 包含マップ、 ツリーマップ)でこの概念の位置づけが視覚的に分かります。 関連手法を辿って学習を進めましょう。
統計データ活用コンペティションのSSDSE-B-2026データは、 47都道府県の社会経済データ。 この概念を使って以下のような分析ができます:
| 機能 | Python (pandas) | Python (scipy) |
|---|---|---|
| 要約統計 | df.describe() | stats.describe() |
| 平均 | df.mean() | np.mean() |
| 標準偏差 | df.std() | np.std() |
| 相関 | df.corr() | stats.pearsonr() |
| t検定 | — | stats.ttest_ind() |
| 回帰 | — | stats.linregress() |
| 分布フィッティング | — | stats.norm.fit() |
この概念は、 他の多くの統計概念と密接に関連しています。 ジャストインタイム型学習では、 必要に応じて関連用語へジャンプしながら全体像を構築します。
| グループ | 主要概念 |
|---|---|
| 記述統計 | 平均、 中央値、 最頻値、 分散、 標準偏差、 共分散、 相関係数 |
| 可視化 | ヒストグラム、 散布図、 箱ひげ図、 ヒートマップ |
| 推測統計 | 標本平均、 標準誤差、 信頼区間、 p値、 有意水準 |
| 確率分布 | 正規分布、 t分布、 χ²分布、 F分布、 二項分布 |
| 仮説検定 | t検定、 F検定、 χ²検定、 ノンパラ検定 |
| 回帰 | 単回帰、 重回帰、 OLS、 Ridge、 LASSO |
| 分類 | ロジスティック回帰、 決定木、 SVM、 k-NN |
| 教師なし学習 | クラスタリング、 PCA、 因子分析 |
| 時系列 | ARIMA、 VAR、 指数平滑法、 自己相関 |
| 因果推論 | DiD、 IV、 傾向スコア、 交絡変数 |
| 前処理 | 標準化、 正規化、 欠損値処理、 多重共線性対策 |
| 評価 | R²、 残差、 CV、 RMSE、 効果量 |
Elastic Net がデータサイエンスの体系の中でどこに位置するかを、 3つの異なる視点で可視化します。 同じ情報でも見方を変えると気付きが変わります。
🌐 体系階層に未登録
中心の概念から放射状に、 前提・兄弟・発展形・応用先などの関係性を矢印で結びます。 横の繋がりを見るのに最適。 ノードをドラッグ、 ホイールでズーム、 クリックで遷移。
大きな円が小さな円を包含する Circle Packing 図。 「Elastic Net」は緑色でハイライト。
長方形を入れ子に分割した Treemap 図。 各分野の規模感を面積で比較。 「Elastic Net」は緑色でハイライト。
| マップ | 分かること | こんな時に見る |
|---|---|---|
| 🔗 関係マップ | 手法間の横の関係(前提→発展→応用) | 「次に何を学べばよい?」 学習順序の判断 |
| ⭕ 包含マップ | 分類体系の入れ子構造(上位⊃下位) | 「この手法はどんなジャンルに属する?」 |
| 🌳 ツリーマップ | 分野の規模比較(面積=ボリューム) | 「データサイエンス全体の俯瞰像」 |
💡 ジャストインタイム学習のヒント:3つの視点を行き来することで、 概念を多角的に理解できます。 包含マップやツリーマップはズーム/ドリルダウンで大分類から細部まで探索できます。
Elastic Net と関連する正則化用語:
SSDSE-B-2026 の 15 変数を説明変数に、 現金給与総額を目的変数として Elastic Net を当てはめ、 OLS / Ridge / Lasso と比較する。
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 33 34 | import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.linear_model import (LinearRegression, Ridge, Lasso, ElasticNet, ElasticNetCV) from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline from sklearn.model_selection import KFold, cross_val_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) df.columns = [c.strip() for c in df.columns] feats = ['総人口', '15歳未満人口', '65歳以上人口', '出生数', '死亡数', '一般病院数', '製造品出荷額等', '小売業年間商品販売額', '完全失業率', '出生率', '労働力人口', '高等学校数', '大学数', '常用労働者数', '消費支出'] X = df[feats].astype(float).values y = df['現金給与総額'].astype(float).values cv = KFold(n_splits=5, shuffle=True, random_state=0) models = { 'OLS' : LinearRegression(), 'Ridge(α=1)' : Ridge(alpha=1.0), 'Lasso(α=1)' : Lasso(alpha=1.0, max_iter=10000), 'ENet(α=1,r=.5)': ElasticNet(alpha=1.0, l1_ratio=.5, max_iter=10000), } for name, m in models.items(): pipe = Pipeline([('sc', StandardScaler()), ('m', m)]) rmse = -cross_val_score(pipe, X, y, cv=cv, scoring='neg_root_mean_squared_error').mean() print(f'{name:<18s} CV RMSE = {rmse:8.1f}') |
典型的な観察例: OLS RMSE ≈ 32 / Ridge ≈ 28 / Lasso ≈ 26 / ENet ≈ 25。 n=47 に対し説明変数 p=15 と「やや多変量」気味のため、 正則化(とくに ENet・Lasso)が OLS を上回る。 ENet は Lasso と Ridge の中間で、 相関の強い変数群を「まとめて選ぶ・落とす」性質が SSDSE データに合っている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from sklearn.preprocessing import StandardScaler Xs = StandardScaler().fit_transform(X) ys = (y - y.mean()) / y.std() enet_cv = ElasticNetCV( l1_ratio=[.1, .3, .5, .7, .9, .95, .99, 1.0], alphas=np.logspace(-3, 1, 50), cv=5, max_iter=10000, random_state=0) enet_cv.fit(Xs, ys) print(f'best α : {enet_cv.alpha_:.4f}') print(f'best l1_ratio: {enet_cv.l1_ratio_:.2f}') print(f'採択された変数(非ゼロ係数 / 全変数)= ' f'{np.sum(enet_cv.coef_ != 0)} / {len(feats)}') coef_df = pd.DataFrame({'feature': feats, 'coef': enet_cv.coef_}) \ .sort_values('coef', key=abs, ascending=False) print(coef_df) |
1 2 3 4 5 6 7 8 9 10 11 12 13 | from sklearn.linear_model import enet_path alphas, coefs, _ = enet_path(Xs, ys, l1_ratio=.5, alphas=np.logspace(-3, 1, 100)) fig, ax = plt.subplots(figsize=(10, 5.5)) for j, name in enumerate(feats): ax.plot(np.log10(alphas), coefs[j], label=name, lw=1.5) ax.set_xlabel('log10(α)') ax.set_ylabel('係数') ax.set_title('Elastic Net 正則化パス (l1_ratio = .5)') ax.legend(fontsize=8, ncol=2, loc='upper right') ax.grid(alpha=.3) plt.tight_layout(); plt.savefig('enet_path.png', dpi=140) |
L1/L2 正則化は係数の絶対値・二乗値にペナルティを課すので、 スケールが大きい変数(例:総人口 10⁶)の係数は強く罰せられ、 スケールが小さい変数(例:失業率 0.03)は罰せられない。 結果としてスケールが大きい変数だけが落ちて選ばれない。 必ず StandardScaler を Pipeline に入れ、 fit/transform をクロスバリデーションの fold 内で完結させる。 標準化なしの ENet は意味のある係数解釈もできない。
α は対数スケールで {0.001, 0.01, 0.1, 1, 10} の 5 段階を基本にすべきで、 [0.1, 1, 10] の 3 点だけでは粗すぎる。 同様に l1_ratio も [0.1, 0.3, 0.5, 0.7, 0.9, 0.95, 0.99, 1.0] のように 1.0 寄りを密にする(Lasso との比較が欲しいので)。 ElasticNetCV は内部で alphas を自動生成するが、 範囲指定は明示した方が再現性が高い。 探索範囲の境界に最適値が当たったら範囲を広げ直す。
CV で最小 MSE を与える α は「最尤」だが、 1-SE rule(CV の最小値から SE 1 個分以内で最大の α、 つまり最大限スパースな選択)を採るのも標準的な慣行。 glmnet の R 版では既定で 1-SE rule が出る。 sklearn ElasticNetCV は最尤のみなので、 1-SE を欲しいときは自前で計算する。 解釈性 vs 予測性能のトレードオフでどちらを採るか決める。
Lasso / ENet の係数には標準的な t 検定や信頼区間は適用できない。 OLS の漸近正規理論は罰則項の存在で崩れる。 有意性が必要なら post-selection inference(Lockhart et al. の covariance test)、 selectiveInference パッケージ、 bootstrap、 もしくはベイズ Lasso を使う。 「ENet で残った変数 = 重要」は強い主張なので、 安定性選択(Stability Selection)でブートストラップを併用するのが安全。
「全データで StandardScaler.fit_transform → 5-fold CV」とすると、 テスト fold の統計量が訓練側に漏れる(データリーク)。 結果として CV スコアが楽観的に見える。 必ず Pipeline で StandardScaler を組み込み、 cross_val_score 内で各 fold ごとに fit を完結。 また、 y のターゲット変換(log 変換等)も fold 内でやるのが理想。 これは sklearn Pipeline の最大の存在意義の一つ。
ENet の売り文句の一つは「Lasso と違って相関の強い変数を全部残せる(grouping effect)」だが、 これは l1_ratio < 1 のときに限る。 l1_ratio が 0.95 以上だとほぼ Lasso と同じで、 相関グループから 1 つだけ選ぶ挙動が再現される。 グループ選択を強く期待するなら l1_ratio = 0.3〜0.5 程度に下げる。 さらに本格的にはグループ Lasso(pyglmnet)を使う方が直接的。
1 2 3 4 5 6 | from sklearn.linear_model import ElasticNet en = ElasticNet(alpha=0.1, l1_ratio=0.5, max_iter=20000, tol=1e-5, random_state=0, selection='random') # 'cyclic' or 'random' en.fit(Xs, ys) print('非ゼロ係数:', np.sum(en.coef_ != 0)) |
1 2 3 4 5 | from sklearn.linear_model import ElasticNetCV encv = ElasticNetCV(l1_ratio=[.1, .5, .7, .9, .95, .99, 1.0], n_alphas=100, cv=10, n_jobs=-1, random_state=0) encv.fit(Xs, ys) print(encv.alpha_, encv.l1_ratio_) |
1 2 3 4 5 6 | from sklearn.linear_model import SGDRegressor sgd = SGDRegressor(loss='squared_error', penalty='elasticnet', alpha=0.001, l1_ratio=0.15, learning_rate='optimal', max_iter=2000, random_state=0) sgd.fit(Xs, ys) |
1 2 3 4 5 6 7 | from glmnet import ElasticNet as GlmnetEN # R の glmnet と等価 g = GlmnetEN(alpha=0.5, n_splits=10, scoring='mean_squared_error', random_state=0) g.fit(Xs, ys) print('λ_min (CV最小):', g.lambda_max_) print('λ_1se (1-SE) :', g.lambda_best_) |
1 2 3 4 5 6 7 8 9 10 11 | from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV pipe = Pipeline([('sc', StandardScaler()), ('en', ElasticNet(max_iter=20000))]) param_grid = { 'en__alpha' : np.logspace(-3, 1, 30), 'en__l1_ratio': [.1, .3, .5, .7, .9, .95, .99, 1.0], } gs = GridSearchCV(pipe, param_grid, cv=5, scoring='neg_root_mean_squared_error', n_jobs=-1) gs.fit(X, y) print(gs.best_params_) |
1 2 3 4 5 6 7 8 9 10 11 | import numpy as np rng = np.random.RandomState(0) n_iter, n_sub = 200, 30 counts = np.zeros(X.shape[1]) for _ in range(n_iter): idx = rng.choice(len(X), n_sub, replace=False) en = ElasticNet(alpha=0.1, l1_ratio=0.5).fit(Xs[idx], ys[idx]) counts += (en.coef_ != 0) sel_freq = counts / n_iter for f, p in sorted(zip(feats, sel_freq), key=lambda x: -x[1]): print(f'{f:<25s} selection freq = {p:.2f}') |
SSDSE-B-2026 の 47 都道府県データには、 「総人口」「労働力人口」「就業者数」のように互いに強相関の指標が並びます。 Lasso 単独では強相関のうち 1 つだけ残して他はゼロにしてしまい、 解が不安定になります。 Ridge は全変数を縮小するだけで選択しません。 Elastic Net は「グループ効果」を持ち、 強相関グループを丸ごと残すか丸ごと縮めるかのバランスをとる「Lasso と Ridge の融合」です。
$$ \hat{\beta}^{EN} = \arg\min_{\beta} \left\{ \frac{1}{2n} \sum_{i=1}^{n} (y_i - x_i^\top \beta)^2 + \lambda \left( \alpha \|\beta\|_1 + \frac{1-\alpha}{2} \|\beta\|_2^2 \right) \right\} $$
$\alpha=1$ で純 Lasso、 $\alpha=0$ で純 Ridge、 $0 < \alpha < 1$ が Elastic Net。 sklearn 既定は $\alpha = 0.5$(混合比率)です。