論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
特徴量エンジニアリング
Feature Engineering
ML基礎
別称: 特徴量設計

🔖 キーワード索引

特徴量エンジニアリング 特徴量設計 派生特徴 Binning OneHot Target Encoding 対数変換 比率特徴 時刻特徴 ラグ特徴 fourier PCA Polynomial ドメイン知識

💡 30秒で分かる結論

🍰 まずはやさしく

データの料理のような作業です。

予測の精度を上げるために使います。

テストの点数を分析する時に役立ちます。

結論と使いどころについて読みましょう。

特徴量エンジニアリング(Feature Engineering):予測に有用な特徴量を設計・抽出する作業。 ML の精度を最も左右する

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

🍰 まずはやさしく

この用語の解説ページです。

機械学習の基礎を学ぶために使います。

都道府県のデータを使って練習します。

おすすめの読み方について説明します。

このページは「特徴量エンジニアリング(Feature Engineering)」の用語解説です。 機械学習の基礎カテゴリにおける重要概念で、 機械学習の基礎 グループ教材の中で繰り返し登場します。 数式・実コード・落とし穴を 1 ページに集約し、 SSDSE-B-2026 都道府県データ(47 件 × 112 列)を題材に 手を動かしながら理解できるよう構成しています。

別称:特徴量設計。 まず 💡 30秒結論 で全体像を、 次に 🎨 直感📐 数式🧮 実値🐍 Python の順で読むのがおすすめ。

🎨 直感で掴む

🍰 まずはやさしく

データの形を整える作業です。

AIが学びやすくするために使います。

スマホの利用時間を整理する時に似ています。

具体的なやり方と考え方を読みましょう。

特徴量エンジニアリングは、 「与えられた生データから、 ML が学びやすい形へ作り直す」工程です。 業界の常識(ドメイン知識)と統計の知識を組み合わせる、 もっとも クリエイティブで効果の大きい 工程です。

代表的な手法:(1) 対数変換(裾の長い分布を圧縮)、 (2) 比率・差分(人口あたり、 前年比)、 (3) Binning(連続値を区分)、 (4) カテゴリエンコーディング(OneHot, Target)、 (5) 時系列ラグ。 「kaggle の上位は 90% が特徴量勝負」とよく言われます。

🎨 直感の深掘り — もう一段の理解

特徴量エンジニアリングを 30 秒で言えば「生データから「学習に使いやすい特徴量」を設計・抽出する作業。 モデル性能の半分以上はここで決まる。」ですが、 実務で迷わないためにはもう一段深い理解が必要です。 ここでは「何が分かれば自信を持って使えるか」を、 3 つの観点で整理します。

観点問い答え方の指針
定義の根拠なぜこの式・この定義になったのか?「何を最小化/最大化したいか」から逆算する
境界条件いつ使える/使えないのか?「データの形」「分布の前提」を確認する
他との関係隣接概念とは何が違うのか?「共通点」と「分かれ目」を 1 つずつ挙げる

💡 暗黙の前提:特徴量エンジニアリング が「うまく機能する」には、 データに対する暗黙の仮定(独立同分布、 適切な前処理、 十分なサンプル数)があります。 これを言語化できるかどうかで、 失敗時のデバッグ力が大きく変わります。

身近な例え:料理の下ごしらえ

特徴量エンジニアリングは「料理の下ごしらえ」と同じ。 同じレシピ(ML モデル)でも、 玉ねぎを「みじん切り」にするか「輪切り」にするかで味は劇的に変わる。 生データを「モデルが食べやすい形」に切り直すのが特徴量エンジニアリングだ。 もし君がプロのシェフなら、 まな板に乗った素材をそのまま炒めるだろうか? まず洗い、 皮をむき、 サイズを揃え、 必要なら下茹で・マリネする。 ML も全く同じで、 「生 CSV をそのまま fit」は素人の調理だ。

SSDSE-B-2026 で「出生率予測」の特徴量設計例

生データそのまま使う特徴量エンジニアリング後
総人口(百万)0.54〜14.1 (分散大)log(人口): -0.62〜2.65 (圧縮)
20-34歳女性人口絶対数女性比率 = 20-34歳女性 / 総人口
保育所定員(絶対数)東京偏重定員 / 0-5歳児 (人口あたり)
平均通勤時間連続値Bin: <30/30-50/50-70/>70分
都道府県(47カテゴリ)OneHot 47 列 or Target Encoding

右列の特徴量を使うと、 同じ線形回帰モデルでも R² が 0.62 → 0.81 に跳ね上がる経験は珍しくない。 モデルを変える前に「特徴量を見直す」が鉄則。

特徴量エンジニアリングの 3 つの罠

📐 数式または定義

🍰 まずはやさしく

データの作り直しを式にしたものです。

計算のルールを決めるために使います。

部活の記録を数値に変える時に似ています。

数式の意味と読み方を詳しく読みましょう。

本概念は次のように記述されます(KaTeX で描画)。

$$x_{\text{new}}^{(j)} = \phi_j(x), \qquad X' = [\phi_1(X), \phi_2(X), \dots, \phi_m(X)] \in \mathbb{R}^{n\times m}$$

英語名 Feature Engineering。 別称:特徴量設計。

📐 数式を 3 段階で読み直す

数式 $x' = \phi(x_{raw}), \quad \hat y = f(x')$ を「ぼんやり眺める」から「自分の言葉で説明できる」レベルに引き上げます。

$$x' = \phi(x_{raw}), \quad \hat y = f(x')$$

① 形を見る

左辺は何か(スカラー?関数?)、 右辺は和・積・最大化のどれが主役か。 ここで「式の文型」が見えます。

② 各記号に意味を持たせる

記号それぞれに「データ/パラメータ/確率/集合」のラベルを貼り、 「これは固定」「これは動かす」を区別します。

③ 極端なケースで確かめる

サンプルが 1 個、 すべて同じ値、 完全にランダム、 などの極端なケースで式がどう振る舞うか確認すると、 数式が「ただの記号」から「動く道具」になります。

📐 特徴量変換の数式カタログ

変換数式目的
標準化 (z-score)$z = (x-\mu)/\sigma$スケール統一
Min-Max$x' = (x - x_{\min})/(x_{\max}-x_{\min})$0-1 範囲化
ロバストスケーリング$x' = (x - \mathrm{median})/\mathrm{IQR}$外れ値耐性
対数変換$x' = \log(x + 1)$右裾の重い分布を正規化
Box-Cox$x'=(x^\lambda-1)/\lambda$最適 λ で正規近似
Yeo-JohnsonBox-Cox の負値拡張負値含む変数
多項式$x, x^2, x^3, x_1 x_2$非線形効果
ビニング$x \mapsto \mathbb 1\{x\in B_k\}$区間効果
One-hot$c \mapsto e_c \in \{0,1\}^K$カテゴリ → 数値
Target encoding$\hat y_c = \frac{n_c\bar y_c + m\bar y}{n_c+m}$高カーディナリティ

数式を言葉で読み解く: target encoding の平滑化

カテゴリ $c$ にラベル平均 $\bar y_c$ をそのまま当てると、 サンプル数 $n_c$ が少ないカテゴリで分散が爆発し過学習する。 そこで全体平均 $\bar y$ への シュリンク を入れたのが上記の式:

$$ \hat y_c = \frac{n_c\bar y_c + m\bar y}{n_c + m} $$

$m$ は「事前重み」で、 $n_c \gg m$ なら $\hat y_c \approx \bar y_c$(局所平均)、 $n_c \ll m$ なら $\hat y_c \approx \bar y$(全体平均)に縮む。 これは経験ベイズ的解釈ができ、 「データが少ないカテゴリは全体平均寄り、 多いカテゴリは局所平均寄り」という直感を数式化したもの。

🔬 数式を言葉で読み解く

記号と意味を逐一突き合わせて読みます。 慣れないうちは式を「日本語で読む」ことが理解の近道です。

🧮 SSDSE-B 実値で計算してみる

SSDSE-B から 派生特徴を 4 つ作り、 元の列だけ使った場合と R² を比較して効果を確認します。

データ出典:SSDSE-B-2026(独立行政法人統計センター)。 47 都道府県 × 複数年(最新 2023)の社会統計データ。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1301(15歳未満人口) A1302(15~64歳人口) A1303(65歳以上人口) A4101(出生数) 北海道 5,092,000 514,000 2,897,000 1,681,000 24,430 東京都 14,086,000 1,513,000 9,368,000 3,205,000 86,348 沖縄県 1,468,000 236,000 882,000 350,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
import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.model_selection import cross_val_score

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 都道府県

y = df['A4101'].values                       # A4101 = 出生数

# A) 元の列のみ(総人口・生産年齢人口・高齢人口)
X_raw = df[['A1101', 'A1302', 'A1303']].values
print('raw  ', cross_val_score(Ridge(), X_raw, y, cv=5).mean())

# B) 派生特徴を追加
df['若年比率']    = df['A1301'] / df['A1101']
df['高齢比率']    = df['A1303'] / df['A1101']
df['生産年齢比率'] = df['A1302'] / df['A1101']
df['log総人口']   = np.log10(df['A1101'])

X_eng = df[['A1101', 'A1302', 'A1303',
            '若年比率', '高齢比率', '生産年齢比率', 'log総人口']].values
print('eng  ', cross_val_score(Ridge(), X_eng, y, cv=5).mean())

実行結果の要約(出力は環境依存。 概算値):

項目
raw R² (5-CV)0.992
engineered R² (5-CV)0.993
追加特徴量数+4
R² 改善幅+0.001
最重要派生特徴若年比率
作業時間目安数時間〜数日

🧮 SSDSE-B-2026 で派生変数を作って予測精度比較

🎯 このコードでやること: SSDSE-B-2026 の生の人口カウント特徴量で予測した場合と、 「若年比率」「高齢化率」「生産年齢比率」「log 総人口」の 4 派生変数を加えた場合で、 線形回帰の CV R² を比較する。 率・対数への変換で予測精度が大きく変わる。

📥 入力: SSDSE-B-2026、 47 都道府県、 ターゲットは「合計特殊出生率」(A4103)。

 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
import pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score, KFold

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)
y  = df['A4103']                              # A4103 = 合計特殊出生率(率=ターゲット)

# (1) 生の特徴量だけ(人口カウント+消費支出)
X_raw = df[['A1101', 'A1301', 'A1302', 'A1303', 'L3221']]

# (2) 派生変数を追加(カウントを比率・対数に変換)
df['若年比率']    = df['A1301'] / df['A1101']
df['高齢化率']    = df['A1303'] / df['A1101']
df['生産年齢比率'] = df['A1302'] / df['A1101']
df['log総人口']   = np.log10(df['A1101'])
X_aug = pd.concat([X_raw, df[['若年比率', '高齢化率', '生産年齢比率', 'log総人口']]], axis=1)

pipe = Pipeline([('sc', StandardScaler()), ('rd', Ridge(alpha=1.0))])
cv = KFold(5, shuffle=True, random_state=42)

r2_raw = cross_val_score(pipe, X_raw, y, cv=cv, scoring='r2')
r2_aug = cross_val_score(pipe, X_aug, y, cv=cv, scoring='r2')
print(f'生特徴量のみ        R² = {r2_raw.mean():.4f}  ±{r2_raw.std():.4f}')
print(f'+ 4 派生変数        R² = {r2_aug.mean():.4f}  ±{r2_aug.std():.4f}')
print(f'改善幅              ΔR² = {r2_aug.mean()-r2_raw.mean():+.4f}')

📤 実行例:

生特徴量のみ R² = 0.3496 ±0.2628 + 4 派生変数 R² = 0.8250 ±0.0516 改善幅 ΔR² = +0.4754

💬 結果の読み方: 生の人口カウントだけでは R² = 0.35 と低い(出生率という「率」を絶対数から当てるのは無理がある)。 だが若年比率・高齢化率などの派生を加えると R² = 0.83 まで跳ね上がる(ΔR² ≈ +0.48)。 CV 分散も大きく縮む(汎化が安定)。 47 県という小サンプルでも、 ドメイン知識(率・対数)を反映した派生は絶大な効果を生む。 これが「特徴量設計が ML の 80% を占める」と言われる所以。

🧮 数式に値を入れて手で計算する: 特徴量追加による精度向上

合成データで特徴量数増加に伴うモデル R² を計算する。

Step 1: 特徴量数 vs R²

特徴数調整 R²
10.500.49
30.700.69
50.800.78
100.850.81
200.860.78

※ n=100 サンプル

Step 2: 調整 R² の式

adj R² = 1 - (1-R²)·(n-1)/(n-k-1) 特徴 5 個: adj = 1 - 0.20·99/94 = 1 - 0.2106 ≈ 0.789 特徴 20 個: adj = 1 - 0.14·99/79 = 1 - 0.175 ≈ 0.825 (実際は過学習で下がる)

🐍 Python で再現

1
2
3
4
5
6
7
import numpy as np
n = 100
k = np.array([1, 3, 5, 10, 20])
r2 = np.array([0.50, 0.70, 0.80, 0.85, 0.86])
adj = 1 - (1 - r2) * (n - 1) / (n - k - 1)
print(f"adj R²: {adj.round(3)}")
print(f"最大 adj index: {adj.argmax()}")

📤 実行結果

adj R²: [0.495 0.691 0.789 0.833 0.825] 最大 adj index: 3

💬 手計算 (Step 2) と Python 出力が一致。 特徴 10 個で adj R² 最大。

🐍 Python 実装

scikit-learn / pandas を使った最小実装パターン。 上の SSDSE-B 計算と同じスタイルですが、 ここでは「読み込み→前処理→学習→評価」のテンプレを 4 つのスニペットに分けます。

① データ読み込み & 概観

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
1
2
3
4
import pandas as pd
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)
print(df.shape, df.columns.tolist()[:8])

② 特徴量と目的変数

1
2
3
X = df[['A1101', 'A1303']].values      # 総人口・高齢人口
y = df['A1301'].values                 # 15歳未満人口を予測
print('X shape =', X.shape, ',  y shape =', y.shape)

③ 訓練/テスト分割 + モデル学習

1
2
3
4
5
6
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0)
model = RandomForestRegressor(n_estimators=300, random_state=0).fit(X_tr, y_tr)
print('R^2 (test) =', model.score(X_te, y_te))

④ 評価と可視化

1
2
3
4
5
6
import matplotlib.pyplot as plt
pred = model.predict(X_te)
plt.scatter(y_te, pred)
plt.plot([y_te.min(), y_te.max()], [y_te.min(), y_te.max()], 'r--')
plt.xlabel('実測'); plt.ylabel('予測'); plt.title('「特徴量エンジニアリング」関連モデルの予測精度')
plt.tight_layout(); plt.savefig('out.png', dpi=150)

※ 「特徴量エンジニアリング」固有の本格コードは上の 🧮 SSDSE-B 実値計算 節を参照。

🐍 応用コード — 人口カウントから「若年比率」「高齢化率」を派生させる

SSDSE 公的データを題材に、 特徴量エンジニアリング を実際に動かす最小コードです。 paths は引数に直書きで、 初心者がコピペで動かせる形を優先しています。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) A4103(合計特殊出生率) L3221(消費支出(二人以上の世帯)) 北海道 5,092,000 1,681,000 1.06 296,888 東京都 14,086,000 3,205,000 0.99 341,320 沖縄県 1,468,000 350,000 1.6 251,222 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pandas as pd
import numpy as np

# データ読み込み(SSDSE-B 都道府県・47 県 × 112 列)
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)
print('shape:', df.shape)
print('列コードの先頭:', df.columns.tolist()[:6])

# 使う列(A1101=総人口, A1303=高齢人口, L3221=消費支出, A4103=出生率)
features = ['A1101', 'A1303', 'L3221', 'A4103']
print(df[features].describe())

次に、 特徴量エンジニアリング に固有の処理を加えます。 ここがページごとの「肝」になる部分。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score

# 比率特徴量を作る(カウントそのままより率が効く)
df['若年比率']    = df['A1301'] / df['A1101']
df['高齢化率']    = df['A1303'] / df['A1101']
df['生産年齢比率'] = df['A1302'] / df['A1101']

X = df[['若年比率', '高齢化率', '生産年齢比率', 'B4101', 'L3221']].values
y = df['A4103'].values                 # A4103 = 合計特殊出生率

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0)
model = RandomForestRegressor(n_estimators=200, max_depth=4, random_state=0).fit(X_tr, y_tr)

pred_tr = model.predict(X_tr)
pred_te = model.predict(X_te)
print(f'train R^2 = {r2_score(y_tr, pred_tr):.3f}')
print(f'test  R^2 = {r2_score(y_te, pred_te):.3f}')
print(f'test RMSE = {np.sqrt(mean_squared_error(y_te, pred_te)):.4f}')

さらに可視化を加えると、 学んだ内容が「眼で」確認できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import matplotlib.pyplot as plt

plt.figure(figsize=(7,5))
plt.scatter(y_te, pred_te, alpha=0.7, edgecolor='k')
lims = [min(y_te.min(), pred_te.min()), max(y_te.max(), pred_te.max())]
plt.plot(lims, lims, 'r--', linewidth=2, label='完全予測ライン')
plt.xlabel('実測 出生率')
plt.ylabel('予測 出生率')
plt.title('特徴量エンジニアリング を使ったモデルの予測精度(SSDSE-B-2026)')
plt.legend()
plt.tight_layout()
plt.savefig('out_feature-engineering.png', dpi=150)

最後に、 同じ問題を別の角度から見る「クロスバリデーション版」も用意します。

1
2
3
4
5
6
7
8
from sklearn.model_selection import cross_val_score

scores = cross_val_score(
    RandomForestRegressor(n_estimators=200, max_depth=4, random_state=0),
    X, y, cv=5, scoring='r2'
)
print(f'5-fold CV R^2 = {scores.mean():.3f}{scores.std():.3f})')
print('各 fold:', np.round(scores, 3))

🐍 実装パターン集 — 状況別レシピ

同じ「特徴量エンジニアリング」を使うにも、 データの形・規模・目的によって書き方が変わります。 4 つの典型パターンを示します。

パターン A:探索的・最小構成

📥 入力例(SSDSE-B-2026 全体:564 行 × 112 列 = 47 都道府県 × 2012〜2023 年) 年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上人口) A4101(出生数) … 2023 R01000 北海道 5,092,000 1,681,000 24,430 … 2023 R13000 東京都 14,086,000 3,205,000 86,348 … 2023 R47000 沖縄県 1,468,000 350,000 12,549 … …(残り 112 列は住宅・家計・教育・医療など)
1
2
3
4
import pandas as pd
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)
print(df.shape, df.head(3))

パターン B:パイプライン化(前処理+モデル)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Ridge

pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('model',  Ridge(alpha=1.0)),
])
pipe.fit(X_tr, y_tr)
print('R^2 =', pipe.score(X_te, y_te))

パターン C:交差検証+ハイパーパラメータ探索

1
2
3
4
5
6
from sklearn.model_selection import GridSearchCV

params = {'model__alpha': [0.01, 0.1, 1.0, 10.0, 100.0]}
gs = GridSearchCV(pipe, params, cv=5, scoring='r2', n_jobs=-1)
gs.fit(X, y)
print('best:', gs.best_params_, 'score:', gs.best_score_)

パターン D:可視化付きの結果保存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import matplotlib.pyplot as plt
import json

pred = gs.predict(X_te)
plt.figure(figsize=(7,5))
plt.scatter(y_te, pred, alpha=0.7, edgecolor='k')
plt.plot([y_te.min(), y_te.max()], [y_te.min(), y_te.max()], 'r--')
plt.xlabel('実測'); plt.ylabel('予測'); plt.title('特徴量エンジニアリング 結果')
plt.tight_layout(); plt.savefig('result_feature-engineering.png', dpi=150)

with open('result_feature-engineering.json', 'w', encoding='utf-8') as f:
    json.dump({'best_params': gs.best_params_,
               'cv_score': gs.best_score_,
               'test_score': gs.score(X_te, y_te)}, f, ensure_ascii=False, indent=2)

🐍 多項式特徴量と交互作用項

🎯 このコードでやること: PolynomialFeatures で 2〜3 次の多項式・交互作用項を一括生成し、 元の 5 特徴量が 20・55 特徴量へ膨張する様子を見る。 過学習リスクと精度のトレードオフを Ridge で評価する。

📥 入力: SSDSE-B-2026、 X=5 特徴量(比率+気温+消費)、 y=合計特殊出生率。

 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 numpy as np
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score, KFold

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['若年比率']    = df['A1301'] / df['A1101']
df['高齢化率']    = df['A1303'] / df['A1101']
df['生産年齢比率'] = df['A1302'] / df['A1101']
y = df['A4103']                        # 合計特殊出生率
X = df[['若年比率', '高齢化率', '生産年齢比率', 'B4101', 'L3221']]

cv = KFold(5, shuffle=True, random_state=42)
for deg in [1, 2, 3]:
    pipe = Pipeline([
        ('sc',   StandardScaler()),
        ('poly', PolynomialFeatures(degree=deg, include_bias=False, interaction_only=False)),
        ('rd',   Ridge(alpha=1.0)),
    ])
    r2 = cross_val_score(pipe, X, y, cv=cv, scoring='r2')
    n_feat = PolynomialFeatures(degree=deg, include_bias=False).fit(X).n_output_features_
    print(f'degree={deg}  特徴量数={n_feat:3d}  CV R² = {r2.mean():.4f}  ±{r2.std():.4f}')

📤 実行例:

degree=1 特徴量数= 5 CV R² = 0.8083 ±0.0432 degree=2 特徴量数= 20 CV R² = 0.1399 ±1.3087 degree=3 特徴量数= 55 CV R² = -3.9389 ±6.2699

💬 結果の読み方: degree=1(5 特徴量)が最良で CV R² = 0.81。 次数を上げると特徴量が 20 → 55 個 へ急増し、 サンプル数 47 を上回るあたりで Ridge の正則化があっても CV R² が急落・分散も激増する(degree=3 では負に転落)。 典型的な curse of dimensionality。 多項式特徴量を入れるときは「次数を上げすぎない」「正則化を強める」「サンプル数とのバランスを見る」の 3 原則を守ること。

数式を言葉で読み解く: 多項式の次元爆発

$p$ 個の特徴量で degree $d$ の多項式(交互作用込み)を作ると、 特徴量数は

$$ \binom{p+d}{d} - 1 $$

になる。 $p=5, d=2$ なら $\binom{7}{2}-1 = 20$、 $p=5, d=3$ なら $\binom{8}{3}-1 = 55$。 サンプル数 $n=47$ より多くなると線形代数的に「優決定系」となり、 解が存在しない or 数値的に不安定になる。 これを避けるのが Ridge の役割($X^\top X + \alpha I$ で常に正則化)。

🐍 ビニング(離散化)の効果

🎯 このコードでやること: 連続変数「年平均気温」を 4 分位で離散化し、 元の連続値モデルと CV R² で比較する。 ビニングは非線形効果を線形モデルで吸収できる場合に有効だが、 情報損失とのトレードオフ。

📥 入力: SSDSE-B-2026、 X=比率 3 種+年平均気温、 y=合計特殊出生率。

 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 pandas as pd
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler, KBinsDiscretizer
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import cross_val_score, KFold

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['若年比率']    = df['A1301'] / df['A1101']
df['高齢化率']    = df['A1303'] / df['A1101']
df['生産年齢比率'] = df['A1302'] / df['A1101']
y = df['A4103']                        # 合計特殊出生率
X = df[['若年比率', '高齢化率', '生産年齢比率', 'B4101']]   # B4101 = 年平均気温

cv = KFold(5, shuffle=True, random_state=42)

# (1) 連続値のまま
pipe1 = Pipeline([('sc', StandardScaler()), ('rd', Ridge())])
r2_a = cross_val_score(pipe1, X, y, cv=cv, scoring='r2').mean()

# (2) 年平均気温だけ 4 分位ビニング
ct = ColumnTransformer([
    ('temp_bin', KBinsDiscretizer(n_bins=4, encode='onehot-dense', strategy='quantile'),
     ['B4101']),
    ('rest',     StandardScaler(), ['若年比率', '高齢化率', '生産年齢比率']),
])
pipe2 = Pipeline([('ct', ct), ('rd', Ridge())])
r2_b = cross_val_score(pipe2, X, y, cv=cv, scoring='r2').mean()

print(f'連続のまま          R² = {r2_a:.4f}')
print(f'年平均気温を 4 分位 R² = {r2_b:.4f}')
print(f'差                  ΔR²= {r2_b-r2_a:+.4f}')

📤 実行例:

連続のまま R² = 0.8097 年平均気温を 4 分位 R² = 0.8380 差 ΔR²= +0.0283

💬 結果の読み方: 年平均気温は 4 分位ビニングした方が R² が僅かに上がる(ΔR² ≈ +0.03)。 気温と出生率の関係が非線形(暖かい地方ほど出生率が高い傾向)なため、 One-Hot 化で階段状の効果を線形モデルが捉えられる。 逆に線形関係が強い変数では連続値のままが勝つ。 ビニングは「順序情報を捨てる」代わりに「非線形効果を One-Hot で扱える」という交換であり、 効くかはドメイン次第。

🐍 自動特徴量生成(feature-engine)

🎯 このコードでやること: feature-engine ライブラリの MathFeatures を使って 6 特徴量から「合計」「平均」「最大」「分散」を自動生成し、 R² への寄与を見る。 ドメイン知識なしでも一定の派生が作れるのが自動特徴量の魅力。

📥 入力: SSDSE-B-2026、 X=6 特徴量(人口カウント+気温+消費)、 y=合計特殊出生率。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
from feature_engine.creation import MathFeatures
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score, KFold

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)
y = df['A4103']                        # 合計特殊出生率
cols = ['A1101', 'A1301', 'A1302', 'A1303', 'B4101', 'L3221']
X = df[cols]

mf = MathFeatures(variables=cols, func=['sum', 'mean', 'max', 'std'])
X_new = mf.fit_transform(X)
print('元の特徴量数:', X.shape[1], '→ 拡張後:', X_new.shape[1])

cv = KFold(5, shuffle=True, random_state=42)
pipe = Pipeline([('sc', StandardScaler()), ('rd', Ridge(alpha=1.0))])
print('元のみ      R²:', cross_val_score(pipe, X,     y, cv=cv, scoring='r2').mean().round(4))
print('元+自動生成 R²:', cross_val_score(pipe, X_new, y, cv=cv, scoring='r2').mean().round(4))

📤 実行例:

元の特徴量数: 6 → 拡張後: 10 元のみ R²: 0.6366 元+自動生成 R²: 0.6378

💬 結果の読み方: 自動生成された統計量(合計・平均・最大・分散)はごく僅かの改善(+0.0012)に留まる。 ドメイン知識ベースの派生(若年比率・高齢化率など)が生んだ ΔR² ≈ +0.48(前掲)と比べると桁違いに小さい。 自動特徴量はベースラインを底上げするのに有効だが、 ドメイン知識の代替にはならない。

数式を言葉で読み解く: なぜ自動生成だけでは足りないか

自動生成は「与えられた変数集合に対する非情報的な統計量」を吐き出す。 一方ドメイン知識ベースの派生(例: 「15歳未満人口 / 総人口 = 若年比率」)は 意味的に解釈可能な比 を生む。 後者は次元解析的にも妥当で、 線形モデルが直接捉えられない「分母正規化」を含意する。 数式で書けば: $f(\text{15歳未満人口}, \text{総人口}) = \text{15歳未満人口}/\text{総人口}$ は単純な交互作用や和では表せず、 ドメイン知識でしか思いつかない関数形である。

⚠️ よくある落とし穴(5 つ)

❌ 目的変数を使った特徴量(リーケージ)
Target Encoding を fold 外で計算しないと未来情報が混入。 必ず CV 内で。
❌ 派生特徴を闇雲に大量生成
次元の呪い + 多重共線性 + 過学習。 仮説駆動で作り、 importance や mRMR で選別。
❌ ドメイン知識を軽視
「総人口 ÷ 県面積 = 人口密度」のような重要派生は機械的探索より人間の方が見つけやすい。
❌ 全データで fit してリーク
StandardScaler や Target Encoder を全データで fit してから CV すると未来情報が漏れる。 Pipeline で fold 毎に fit。
❌ テスト時に派生特徴を再現できない
本番では訓練と完全に同じ変換を再現できる仕組み(Pipeline 永続化)を整える。

⚠️ さらに 5 つの落とし穴 — 実務で痛い目を見るパターン

❌ デフォルト設定をそのまま信じる
ライブラリのデフォルト引数は「平均的なケース」向け。 あなたのデータが平均的でなければ、 必ず設定を再検討する必要があります。 公式 docstring を読む癖をつけましょう。
❌ スケーリングを忘れる
「総人口」(数百万) と「出生率」(0.0〜2.0) では値域が 10⁶ 倍違う。 距離ベースの手法では、 必ず StandardScaler / MinMaxScaler でスケールを揃えること。
❌ 訓練データでの前処理パラメータをテストに使わない
StandardScaler の fit訓練データだけに対して行い、 テストには transform のみを適用。 これを混同するとデータリーケージになる。
❌ メトリクスの単位を見落とす
RMSE を「絶対値で 100」と聞いて大きいか小さいかは、 目的変数のスケールによる。 「出生率」(0〜2) で RMSE=100 はあり得ない、 などのサニティチェックを必ず。
❌ 「精度が高い = 良いモデル」と短絡
precision/recall の不均衡、 ラベルの偏り、 ベースラインとの比較を見ないと、 「高精度」は単に多数派を予測しているだけかもしれません。

🕰 歴史的経緯と現代的意味

特徴量エンジニアリング は、 統計学と計算機科学の流れの中から生まれました。 下の年表はこの分野全体の流れで、 特徴量エンジニアリング 固有の年表ではありません。 この用語がどの時代の産物かを掴むために置いています。

時期出来事この時代に起きたこと
前史統計学・情報理論の基盤整備数式的な土台
古典期機械学習の黎明(1960〜80 年代)「特徴量エンジニアリング」の原型が登場
展開期scikit-learn / TensorFlow など実装の普及(2010〜)誰でも 1 行で使える時代に
現代大規模モデル時代(2020〜)「特徴量エンジニアリング」の意味が再解釈される

現代の文脈では、 古典的な定義のままでは説明しきれない使い方も出てきています。 教科書の定義を出発点としつつ、 実務での「変奏」も知っておくとよいでしょう。

❓ よくある質問

Q1. なぜこの定義になっているの? 別の式じゃダメ?

理論的には別定義も可能ですが、 「数学的に扱いやすい」「経験的に良い結果が出る」「歴史的経緯」の 3 拍子で現在の定義が標準化されています。 学術論文では別定義を「変種」として議論することもよくあります。

Q2. データが少ない(47 県)でも意味ある分析になる?

教育用途・探索的分析では十分。 ただし「統計的有意」を主張するには n=47 は不足することが多いので、 解釈は慎重に。 ブートストラップで信頼区間を出すと頑健性が確かめられます。

Q3. scikit-learn 以外でも実装はある?

PyTorch / TensorFlow / XGBoost / LightGBM など多数。 ただし基本的な動作確認は scikit-learn が一番速いので、 まず sklearn で動かしてから他に移植するのがおすすめ。

Q4. 大規模データ(百万行)でも同じ方法でいける?

計算量・メモリの観点でアルゴリズムを切り替える必要があります。 mini-batch 版、 サブサンプリング、 近似アルゴリズムの利用を検討します。 47 県スケールで本質を理解した後の応用課題です。

Q5. 論文を書くとき、 この概念をどう引用すべき?

古典的な定義は原典(教科書や著名論文)、 実装は使用ライブラリのバージョン情報を併記するのが標準。 「Murphy 2012」「Hastie et al. 2009」あたりが定番引用です。

Q6. 関連用語との学習順序は?

下の「📚 関連グループ教材」セクションのリストが、 推奨される学習順序の一つです。 上位概念から入って詳細に降りる「トップダウン」と、 1 つの具体例から始めて他に広げる「ボトムアップ」、 どちらも一長一短。 自分の学び方に合わせて。

⚠️ 特徴量設計の 8 つの落とし穴

落とし穴何が起きるか対策
target leakagetarget encoding で fold をまたぐout-of-fold で集計
test 漏洩test 統計量で train を標準化Pipeline で fit は train のみ
多重共線性「人口」と「15-64+65以上」を両方入れるVIF 確認、 PCA、 削除
過学習特徴量数 > サンプル数正則化、 次元削減
過剰なビニング情報損失連続値と比較
スケール混在勾配が偏り収束遅延StandardScaler、 RobustScaler
カテゴリ高カーディナリティOne-Hot で次元爆発target encoding、 hashing
時系列で未来情報混入将来値で past を符号化expanding window で集計

特に target leakage はコンペで上位入賞者の typical なミス。 「リーダーボードでは強かったが本番で全く効かない」モデルは大体これが原因。

🗺 用語マインドマップ — 周辺概念の整理

「特徴量エンジニアリング」を中央に置いて、 周辺概念を 5 つの方向に整理します。 これは記憶の足場になります。

方向隣接概念関係性
北 (上位)表現学習 (Bengio 2013)・機械学習パイプライン特徴量エンジニアリングを包含する設計思想 (人手 vs 自動)
南 (下位)one-hot・binning・対数変換・target encoding・ラグ特徴SSDSE-B-2026 で「人口比 = 高齢者数 / 総人口」を作る等の具体操作
東 (発展)featuretools (DFS)・tsfresh・AutoFeat・Deep Feature Synthesis人手設計を自動化する発展形 (Kanter & Veeramachaneni 2015)
西 (前提)EDA・記述統計・ドメイン知識・pandas/numpy特徴量設計の前に必須となる土台
中央特徴量エンジニアリング「Kaggle で最も差がつくのは特徴量設計」(Pedro Domingos 2012)

マインドマップは「学んだ用語を整理する道具」として優秀。 紙にこの 5 方向を書き、 自分なりの隣接概念を埋めると、 暗黙的にあった理解構造が可視化されます。

📝 自己検証クイズ — 5 問

「特徴量エンジニアリング」を本当に理解できたか、 自分でテストできるクイズです。 答えは展開で確認。

Q1. 「特徴量エンジニアリング」を 30 秒で同僚に説明するとしたら、 何を最初に言う?

模範回答:上の「💡 30秒結論」を参照。 ポイントは「何のために使うか」を最初に言うこと。 定義や数式から入ると相手が引きます。

Q2. 数式の左辺と右辺、 それぞれ「動かせる量」「固定する量」はどれ?

模範回答:データは観測値で固定、 パラメータは学習で動かす、 出力は計算結果。 上の「📐 数式の構造をもう一度」を参照。

Q3. SSDSE-B-2026 で「特徴量エンジニアリング」を使ったとき、 何が変わる?

模範回答:生データ (人口・所得・面積) のままより、 派生特徴 (1 人当たり所得 = 所得 / 人口、 人口密度 = 人口 / 面積、 高齢化率 = 65 歳以上 / 総人口、 地方区分 one-hot) を作ると線形モデルの R² が 0.4 → 0.7 に跳ね上がる場合がある。 ただし n=47 と少ないので、 特徴量数 ≤ 10 程度に抑えないと過学習する。 LOOCV または LeaveOneOut で都道府県を 1 つずつ抜いた汎化性能を必ず測る。

Q4. 「特徴量エンジニアリング」と類似手法の最大の違いは?

模範回答:上の「🌐 似た概念との比較」表を参照。 1 文で言える違いを持っておくと、 「なぜこっちを選んだか」を説明できます。

Q5. 「特徴量エンジニアリング」を使うときに最も気をつけるべき落とし穴は?

模範回答:上の「⚠️ 落とし穴」と「⚠️ さらに 5 つの落とし穴」セクションから、 自分のプロジェクトに最も関連するものを 1 つ選んで言語化してみましょう。

特徴量エンジニアリング EDA / 派生特徴設計 one-hot / target encoding Featuretools (Kanter 2015) SHAP (Lundberg 2017) Lasso 特徴選択 生データ vs 学習特徴

🔗 隣接手法への橋渡し

「特徴量エンジニアリング」は単独で完結せず、 隣接する手法と接続することで分析パイプラインの一部として機能する。 以下に具体的な接続関係を示す。

「特徴量エンジニアリング」は (1) 生データ → (2) ドメイン知識でビニング / 多項式 / 交互作用 / 集約特徴 → (3) Target Encoding / Frequency Encoding → (4) Lasso / SHAP / Permutation Importance で評価 → (5) リーク防止 (時系列 CV) → (6) パイプライン化、 という 6 段で運用する。

🌳 手法選択フロー

特徴量エンジニアリングは「変数の型 × データ規模 × モデル種別 × リーク制約」の 4 軸で操作を決める。 SSDSE-B-2026 のような小規模 (n=47) と Kaggle の大規模 (n=10⁶+) では推奨手法が異なる。

  1. Step 1: 変数の型は?
    • 数値連続値 (例: 人口・所得) → 対数変換・Box-Cox・分位ビニング・標準化
    • カテゴリ低濃度 (≤10 水準, 例: 地方区分) → one-hot encoding
    • カテゴリ高濃度 (≥100 水準, 例: 都道府県+市区町村) → target encoding (CV-fold で漏洩防止) or frequency encoding
    • 順序尺度 (例: 学年・等級) → ordinal encoding (整数化で順序保持)
    • 日時 → 年・月・曜日・休日フラグ・周期成分 (sin/cos)
    • テキスト → BoW・TF-IDF・単語埋め込み・BERT 埋め込み
  2. Step 2: モデルとの相性は?
    • 線形モデル (重回帰, ロジスティック, Lasso) → 標準化必須・非線形は手動で多項式/交互作用追加
    • 木系 (RF, XGBoost, LightGBM) → 標準化不要・one-hot より直接カテゴリ可・欠損も処理可
    • ニューラルネット → 埋め込み層 (Entity Embedding, Guo & Berkhahn 2016) でカテゴリ自動学習
  3. Step 3: データ規模は?
    • SSDSE-B-2026 (n=47): 派生特徴は 5〜10 個に抑える (過学習防止)、 LOOCV で検証、 1 人当たり指標 (所得/人口) や比率 (高齢者数/総人口) が王道
    • n=1,000〜10,000 → ドメイン知識ベースの手設計が効果大、 target encoding は 5-fold CV で
    • n≥100,000 → AutoML / Featuretools (Kanter & Veeramachaneni 2015) で自動生成、 深層学習で end-to-end も検討
  4. Step 4: リーク (data leakage) 防止は?
    • 時系列 → TimeSeriesSplit で過去のみから target encoding、 未来情報を使わない
    • 群別 → GroupKFold で同一群が train/test を跨がない
    • スケーリング (StandardScaler) は train で fit, test に transform (Pipeline で固定)
  5. Step 5: 重要度評価は?
    • Lasso 係数 → 線形での寄与
    • Permutation Importance (Breiman 2001) → モデル非依存・テストデータで評価
    • SHAP (Lundberg 2017) → 個別予測の寄与分解、 木系で高速

SSDSE-B-2026 で特徴量エンジニアリングを実践する場合は、 まず生変数で OLS のベースライン R² を取り、 そこから「1 人当たり」「比率」「対数」「地方 one-hot」を順に追加して R² の改善を確認、 LOOCV で過学習していないか検証する流れが標準的。

🎮 触って理解する

下の左パネルには「同心円状に配置された 2 クラス」のデータがある。 内側の点と外側の点は、 生の座標 (x, y) のままではどんな直線を引いても分けられない(線形分離不可能)。 ところが、 半径特徴 r² = x² + y² を 1 つ加えるだけで、 変換後の空間では1 本の境界で分けられるようになる。 ボタンで特徴量変換を切り替え、 精度がどう変わるかを体感してほしい。 計算は毎回、 実際にロジスティック回帰(勾配降下法)を訓練して求めている。

使い方: ①上のボタンで特徴量を選ぶ ②「ノイズ」スライダーや「データ再生成」で難易度を変える ③右パネルの青い縦線をドラッグ(スマホは指でスワイプ)して手動のしきい値も試せる。 左パネルの色付き領域が「線形分類器が引いた決定境界」。
元の空間 (x, y) と決定境界
色付き領域=分類器が「内側」「外側」と判定する範囲
変換後の空間
青い縦線=手動しきい値(ドラッグ可)

体感のポイント: 「生の特徴 [x, y]」では、 分類器がどんな直線を引いても内側と外側が混ざり、 精度は五分五分(約 50%)付近から上がらない。 半径特徴 x²+y² を 1 つ加えた瞬間、 元の空間では円形の境界が引けるようになり、 変換後の空間では 1 本のしきい値でほぼ完全に分離できる。 多項式特徴 [x², y², xy] はさらに柔軟で、 楕円や回転した境界も表現できる。 これが「アルゴリズムを変えなくても、 良い特徴を作るだけで 線形分類器が非線形問題を解ける」という特徴量エンジニアリングの核心である。 ノイズを上げると、 良い特徴でも完全分離が崩れる(データの質の限界)ことも確認できる。

💡 直感・落とし穴・発展(深掘り)

直感 — 良い特徴は「学習を楽にする」: モデルの表現力とは「特徴 × モデル構造」の掛け算で決まる。 線形モデルは境界が直線(超平面)に限られるが、 上のデモのように特徴側で非線形性を先に注入すれば、 線形モデルのまま曲がった境界を引ける。 これはサポートベクターマシンのカーネル法(特徴空間へ写像してから線形分離)と本質的に同じ発想で、 SVM は「良い特徴写像を暗黙に使う」と読み替えられる。 逆に言えば、 適切な特徴があれば単純なモデルで十分なことが多く、 「複雑なモデルより先に、 まず良い特徴を疑え」が実務の鉄則。

発展 — 手作りから自動化・表現学習へ: 特徴を人手で設計する代わりに、 データから特徴表現そのものを学ばせる方向が主流になりつつある。 (1) 自動特徴生成(Featuretools の Deep Feature Synthesis, AutoML)は、 集約・変換の組み合わせを機械的に探索する。 (2) PCAカーネル PCA は分散最大の軸へ写像して特徴を圧縮・抽出する。 (3) 表現学習(representation learning)は、 深層学習が生データから階層的に特徴を自動獲得する枠組みで、 画像の畳み込み特徴や埋め込み表現自己教師あり学習で得る汎用表現がその代表。 ただし「良い特徴を人が与える」古典的アプローチは、 小標本・解釈性重視・表形式データでは依然として最強クラスであり、 デモで見たように1 個の適切な特徴が数百層のネットに匹敵することもある。

🧭 解説深化 — 特徴量は「何を作るか」より「いつ・どのデータで作るか」

本ページ本文では「どんな派生特徴を作るか」(比率・対数・交互作用) を扱いました。 姉妹ページ「特徴量」が座標系・分母の選び方を掘り下げたのに対し、 ここでは別角度、 すなわち変換を「作る手順」そのものに焦点を当てます。 テーマは 2 つ ——「① 交互作用・多項式項は中心化してから作る」「② 前処理・特徴量選択は訓練データだけで作る」。 いずれも SSDSE-B-2026 の 2023 年・47 都道府県実測値で確かめます。

🎨 直感 — 交互作用は R² を押し上げるが、そのまま作ると共線性で自爆する

合計特殊出生率 A4103 を、 子ども割合 (A1301/A1101×100) と高齢化率 (A1303/A1101×100) で線形回帰すると、 2023 年実測で決定係数 R² = 0.8418。 ここに「子ども割合 × 高齢化率」の交互作用項を 1 本足すと R² = 0.8562 へ上がります (いずれも 47 県・全県あてはめ)。 交互作用は「2 つの変数が同時に効くときだけ現れる非線形」を線形モデルに持ち込む手段で、 特徴量エンジニアリングの定番です。

ただし作り方に落とし穴があります。 高齢化率 x とその 2 乗 をそのまま特徴量にすると、 47 県での相関は r = 0.9972 — ほぼ完全な共線性で、 係数は不安定になり解釈もできません。 ところが平均 (31.586%) を引いて中心化してから 2 乗すると、 同じ情報を持ちながら相関は r = −0.3725 まで落ちます (2023 年実測)。 交互作用項も同様で、 生の child×agingchild と r = 0.378 相関するのに対し、 標準化後の積では r = −0.361。 「掛ける・累乗する前に中心化する」だけで、 多項式・交互作用特徴の多重共線性は大幅に緩みます。

⚠️ 落とし穴(重要)— 「全データで特徴量選択」は数字にウソをつかせる

本文の落とし穴一覧でも「全データで fit するとリーク」と触れましたが、 ここではその被害額を実測します。 課題は同じく TFR (A4103) の予測。 候補特徴は SSDSE-B-2026 の数値列 108 本すべて (実データ、 合成なし)。 47 県を「訓練 35・テスト 12」にランダム分割し、 各分割で |相関| 上位 5 特徴を選んで線形回帰、 テスト R² を測る — これを乱数シード 20260614 で 200 回反復した平均が次です。

教訓は「精度が上がったら、 まず前処理がテストデータに触れていないかを疑う」。 scikit-learn なら Pipeline に選択器・スケーラをまとめ、 交差検証の fold 内で毎回 fit させれば、 このリークは構造的に防げます。

🔭 発展 — 「特徴量を作る」を検証プロトコルの一部として設計する

上の 2 つは同じ原則の裏表です。 特徴量エンジニアリングは「変換関数 f を作る」だけでなく、 f のパラメータをどのデータで推定するか」まで含めて初めて完結します。 中心化の平均値、 標準化の平均・分散、 交互作用の基準点、 ターゲットエンコーディングの集計、 特徴選択の相関 — これらはすべてデータから推定されるパラメータであり、 訓練 fold の外の情報を使えば漏洩します。 発展的には、 (a) 多項式・交互作用の自動生成 (PolynomialFeatures) を中心化とセットで組み、 (b) 正則化 (Ridge/Lasso) で生成した大量の項を抑え込み、 (c) Nested CV で「特徴生成→選択→学習」全体を一つのパイプラインとして評価する、 という 3 段構えが定石です。 「良い特徴」とは単体で相関が高い列ではなく、 正しい検証プロトコルの中でも生き残る列を指します。

※ 本節の数値はすべて data/raw/SSDSE-B-2026.csv の 2023 年・47 都道府県データからの実測値 (使用列: A1101, A1301, A1303, A4103、 リーク実測は数値列 108 本を候補・乱数シード 20260614・200 分割の平均)。 合成データは使用していません。