One-hot エンコーディングを実務で使うための核となる12 論点を索引化。 ダミー変数トラップ・高 cardinality・sparse 表現の落とし穴を集中的に潰します。
🍰 まずはやさしく
文字のデータを0と1に分ける方法です。
AIが計算できるようにするために使います。
血液型を数字に直すときなどに便利です。
この手法の結論を短くまとめます。
カテゴリを複数の0/1変数に展開する手法
drop_first=True で K-1 列にする (完全多重共線性=ダミー変数トラップを回避)。 決定木系では K 列のままで OK。🍰 まずはやさしく
データの準備をするための手順です。
AIは数字しか読み込めないために行います。
スマホのアプリで色を選ぶときのようなデータです。
この手法の呼び方や使い分けを説明します。
ML モデルは数値しか受け取れないため、 「都道府県」「商品カテゴリ」「色」などをそのまま入れられません。 ほぼ全ての分析で最初に通る前処理です。
本ページは「one-hot エンコーディング」の別名・周辺概念整理ページとして位置づけられます。 本家解説は one-hot エンコーディング および カテゴリ変数 に詳しいですが、 ここでは特に「呼び方の違いはどこから来るか」「線形モデル vs 木系モデルでの扱い差」「SSDSE-B-2026 でのケース」に焦点を当てます。
| 呼び方 | 由来 | 主な使われる分野 |
|---|---|---|
| One-hot | 「1 つだけ hot (=1)」 | 機械学習・ニューラルネット |
| ダミー変数 | 経済学・回帰分析の伝統 | 統計学・計量経済学 |
| 1-of-K | パターン認識教科書 (Bishop) | 機械学習理論 |
| Indicator (指示変数) | 条件 1{x=c} | 数理統計 |
🍰 まずはやさしく
たくさんのスイッチを並べるイメージです。
データの順番に意味が出ないようにします。
部活の種類を数字で分けるときに使います。
なぜこの方法が良いのかを直感的に解説します。
例:「都道府県 = 東京」を、 47次元のベクトル [0,0,...,1,...,0](東京の位置だけ1)に変換。 これで「東京と大阪の距離は √2、 東京と福岡も √2」と カテゴリ間の距離が等しい表現になります(順序が無いことを正しく表現)。
カテゴリ変数を one-hot 化するとは、 「カテゴリの数だけスイッチを並べて、 該当する 1 つだけ ON にする」イメージです。 たとえば血液型 (A, B, O, AB) なら、 「A=[1,0,0,0]」「B=[0,1,0,0]」「O=[0,0,1,0]」「AB=[0,0,0,1]」のように 4 つのスイッチに変換します。
なぜそんなことをするのか? — 機械学習モデルの大半は数値しか食えないからです。 もし「A=1, B=2, O=3, AB=4」と素朴に数値化すると、 モデルは「O (=3) は A (=1) の 3 倍重要」と勘違いします。 これは血液型に大小の順序がない以上、 絶対に避けたい誤解です。 one-hot 化は「カテゴリ間に偽の順序を持ち込まない」変換として機能します。
線形回帰に投入する際は、 47 列ではなく 46 列に減らすのが定石 (これがダミー変数トラップ回避)。 詳細は #r95-trap セクションで。
🍰 まずはやさしく
カテゴリを0と1の列に変えるルールです。
数学的に正しくデータを扱うために使います。
買い物で選ぶ商品の種類などを数値にします。
この手法の定義を数式を使って説明します。
one-hot encoding(One-Hot Encoding):カテゴリを複数の0/1変数に展開する手法
同義・関連語:ワンホット, one-hot
カテゴリ集合 $\mathcal{C} = \{c_1, c_2, \dots, c_K\}$ に対し、 値 $x \in \mathcal{C}$ を長さ $K$ のベクトル $\mathbf{e}(x) \in \{0,1\}^K$ に写す。 第 $k$ 成分は指示関数で書ける。
$$\mathbf{e}(x)_k = \mathbb{1}[x = c_k] = \begin{cases} 1 & (x = c_k) \\ 0 & (x \neq c_k) \end{cases}$$この $\mathbf{e}(x)$ は常に第 1 ノルムが 1を満たす:
$$\|\mathbf{e}(x)\|_1 = \sum_{k=1}^{K} \mathbb{1}[x=c_k] = 1$$線形回帰モデル $y = \beta_0 + \sum_{k=1}^{K} \beta_k \mathbf{e}(x)_k + \varepsilon$ では、 切片 $\beta_0$ と $K$ 個のダミー変数の和が線形従属となる:
$$\sum_{k=1}^{K} \mathbf{e}(x)_k = 1 = \frac{1}{\beta_0} \cdot \beta_0$$この時、 設計行列 $X$ のランクが落ち、 $X^\top X$ が特異 (非可逆) になり、 OLS の解 $\hat{\beta} = (X^\top X)^{-1} X^\top y$ が一意に定まりません。 これを「ダミー変数トラップ (dummy variable trap)」と呼びます。 対策は $K$ 個 → $K-1$ 個に減らすこと (どれか 1 カテゴリを「基準カテゴリ」として削除)。 これが pandas の drop_first=True オプションの正体です。
| 記号 | 意味 |
|---|---|
| $K$ | カテゴリ数 |
| $\mathbf{e}_x$ | $x$ に対応する one-hot ベクトル |
| $\mathbb{1}$ | 指示関数(条件が真なら1) |
| drop_first | K-1列に削減(多重共線性回避) |
one-hot encoding(One-Hot Encoding)は、 単に用語の定義を覚えるだけでは本当には理解できません。 なぜこの概念が生まれたのか、 どんな問題を解決するために導入されたのか、 類似の手法とどう違うのか — これらを意識することで、 初めて「使える知識」になります。
数式や Python コードはあくまで 道具。 道具の使い方を覚える前に、 その道具で何をしたいか(目的) を明確にすることが、 データサイエンス学習の鉄則です。
この用語は、 単独で存在するわけではなく、 多くの関連概念とネットワークを形成しています。 上の「関連用語」セクションに挙げたリンク先を1つずつ辿ると、 全体像が見えてきます。 特に:
理論を学ぶことと、 実務で使えることは別物です。 公的統計(SSDSE、 e-Stat 等)の実データで実装・実験することで、 教科書だけでは見えない罠 に気付けます。 たとえば:
これらは one-hot encoding に限った話ではなく、 データサイエンス全般に共通する作法です。 「落とし穴」セクションの内容と合わせて、 自分なりのチェックリストを作るとよいでしょう。
one-hot encoding を使った分析の 正しさを担保する ためには、 以下の観点で検証するのが定番です。
| 確認する点 | one-hot encoding で何を見るか |
|---|---|
| 高カーディナリティ爆発 | 1万カテゴリ → 1万列。 メモリ・過学習問題。 Target Encoding 等へ。 |
| ダミー変数の罠 | K列全部入れると線形回帰で多重共線。 必ず K-1 に。 |
| 未知カテゴリ | 訓練に無いカテゴリがテストに → 列がずれる。 sklearn の OneHotEncoder で `handle_unknown='ignore'`。 |
| 順序情報の喪失 | 「Sサイズ < Mサイズ < Lサイズ」を one-hot にすると順序が消える。 Ordinal Encoding を検討。 |
| 再現性 | 同じデータ・同じコードで同じ結果が出るか。このページの ▶ 実行ボタンで確かめられます |
one-hot encoding は分野横断で活躍する概念です。 業界別に見ると以下のような使われ方があります。
one-hot encoding を実際のデータで学ぶときは、 SSDSE(教育用標準データセット、 総務省統計局)が便利です。
これらは 統計センターの SSDSE ページ から CSV で直接ダウンロードできます。 上の Python コード例で data/raw/SSDSE-B-2026.csv としているのが、 まさにこれです。
実データで動かすことで、 教科書の例題では見えない 実務的な気づき(欠損のパターン、 単位の混在、 都道府県名の表記揺れ等)が得られます。
pip install pandas numpy scikit-learn matplotlib で揃います。utf-8 ではなく shift_jis や cp932 の場合がある(古い日本の公的統計に多い)。 encoding='cp932' を試してください。%matplotlib inline、 スクリプト実行なら plt.show() を忘れずに。 日本語フォントは matplotlib 用に別途設定(japanize-matplotlib 等)が必要。one-hot encoding の形式的定義を 4 要素で精密に読み解きます。 カテゴリ変数を数式で扱える形に変換する基本前処理です。
$\mathcal{C} = \{c_1, c_2, \ldots, c_K\}$ は $K$ 個のカテゴリ集合(性別= 2、 血液型= 4、 都道府県= 47)。 $\phi$ は各カテゴリを $K$ 次元の 0/1 ベクトルに写す写像。 これにより 「文字列・整数ラベル」を「ベクトル空間の要素」 に変換でき、 線形回帰・ニューラルネット・SVM 等の数学モデルが扱える。 数学的には one-hot は カテゴリ集合から $K$ 次元 simplex の頂点集合への bijection(全単射)。
出力空間は $K$ 次元超立方体の頂点集合 $\{0,1\}^K$。 ただし one-hot で得られるのは 「ちょうど 1 要素が 1」 の $K$ 個の頂点のみ(standard basis vectors)。 任意 2 カテゴリ間のユークリッド距離は $\sqrt{2}$、 ハミング距離は 2。 すべてのカテゴリペアが等距離 である点が重要:これによりカテゴリ間に偽の順序関係を持ち込まない。 ordinal encoding なら 1 と 4 のカテゴリは遠く、 1 と 2 は近い、 という人為的な距離が入ってしまう。
$e_k = (0, \dots, 0, 1, 0, \dots, 0)$ は線形代数の 標準基底ベクトル。 第 $k$ 成分が 1、 残りはすべて 0。 これにより線形モデル $y = w^\top \phi(c) + b = w_k + b$ となり、 各カテゴリに独立した係数 $w_k$ を割り当てる。 たとえば「色」の係数として「赤の効果」「青の効果」「緑の効果」を独立推定できる。 これが one-hot の最大のメリット — カテゴリ別の効果を線形分離できる。
one-hot ベクトルの成分和は常に 1。 これが 「ダミー変数の罠」を生む — 切片項 1(intercept)を含む線形回帰では、 $K$ 列の one-hot は 完全な多重共線性を生み、 OLS 解が一意に定まらない。 対策:pd.get_dummies(drop_first=True) で $K-1$ 列に縮約(dummy encoding と呼ばれる)。 木モデル(決定木、 Random Forest、 XGBoost)は多重共線性に頑健なので $K$ 列フルでも問題ない。 もう一つの落とし穴は 次元の呪い:カテゴリ数が大きい(高カーディナリティ、 例:1741 市区町村)と $K$ 次元ベクトルがスパースになり、 メモリ・計算量・統計効率が悪化する。 対策は target encoding、 hashing trick、 entity embedding(Guo & Berkhahn 2016)。 KDD2015 の Rossmann Store Sales コンペで entity embedding が初めて広く知られた。
上の指示関数とダミー変数トラップの式を、 記号ごとに翻訳します。
| 記号 | 読み方 | SSDSE-B-2026 文脈での意味 |
|---|---|---|
$\mathcal{C}$ | カテゴリ集合 | {北海道, 青森県, ..., 沖縄県} の 47 要素 |
$K$ | カテゴリ数 | 47 (都道府県数) |
$\mathbf{e}(x)$ | 指示ベクトル | 「東京都」なら 47 次元中 13 番目だけ 1 のベクトル |
$\mathbb{1}[\cdot]$ | 指示関数 | 条件が真なら 1、 偽なら 0 を返すスイッチ |
$\|\cdot\|_1$ | L1 ノルム | ベクトル成分の絶対値の和。 one-hot は常に 1 |
$\beta_0, \beta_k$ | 回帰係数 | 切片 ($\beta_0$) と各都道府県効果 ($\beta_k$) |
$X^\top X$ | グラム行列 | OLS の解で逆行列を取る対象。 トラップ時に特異化 |
📖 物語として読むと: 「47 都道府県という名義カテゴリは、 47 個のスイッチに変換できる。 ただし『47 個全部 ON/OFF パターン』と『切片』には常に "全部足して 1" という関係があり、 線形回帰では片方が不要 (実は冗長)。 だから 46 個に減らして、 1 個 (たとえば北海道) を『基準』にする。 すると残り 46 県の係数 $\beta_k$ は『北海道との差』を表す」。
ダミー変数トラップは「完全多重共線性 (VIF = ∞)」の極端ケース。 実務では「ほぼ完全多重共線性 (VIF が大きい)」も問題なので VIF 検査を行います。
$$\mathrm{VIF}_j = \frac{1}{1 - R_j^2}$$ここで $R_j^2$ は「特徴量 $j$ を他の全特徴量で回帰した時の決定係数」。 $R_j^2 = 1$ なら VIF = ∞ (完全多重共線性)。 慣習的に VIF > 10 で問題視されます。
| 記号 | 意味 | one-hot 文脈 |
|---|---|---|
$R_j^2$ | $j$ 番目特徴量の他特徴量への回帰決定係数 | 「東京ダミー」を他都道府県ダミーから予測する R² |
$\mathrm{VIF}_j$ | 分散インフレーション係数 | drop_first=False で全 47 ダミー入れると ∞ |
| VIF=1 | 完全独立 | 理想的だが現実には稀 |
| VIF=10 | 注意ライン | 特徴量削除や正則化を検討 |
| VIF=∞ | 完全多重共線性 | drop_first=False + 切片の状況 |
📖 物語として読むと: 「VIF = 1/(1 - R²) は『この特徴量はどれだけ他から予測可能か』を、 残差の小ささで測る指標。 完全に予測できる (R²=1) なら新規情報ゼロ = ∞。 まったく予測できない (R²=0) なら独立 = 1」。 one-hot で全 K 列残すと『最後の 1 列は他 K-1 列から完全に予測可能』なので VIF が無限大に飛ぶ。 drop_first がこれを解消する。
SSDSE-B-2026 の「都道府県名」(47 カテゴリ)と「地方区分」(8 カテゴリ)を one-hot 化し、 列爆発と多重共線性の両方を体感します。
| 都道府県 | 北海道 | 東北 | 関東 | 中部 | 近畿 | 中国 | 四国 | 九州 |
|---|---|---|---|---|---|---|---|---|
| 北海道 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 秋田県 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 東京都 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| 大阪府 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
| 沖縄県 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
drop_first=True で 7 列にone-hot encoding は学術概念に留まらず、 産業界で多種多様に運用されています。 6 業界の代表事例を示します。
one-hot encoding は単独でなく類似概念群の中で位置付けると理解が深まります。
| 概念 | 定義の要点 | 代表例 | 分類軸 |
|---|---|---|---|
| one-hot encoding | K 次元 0/1 ベクトル | 性別→[1,0] | 順序なしカテゴリ |
| dummy encoding | K-1 次元(drop_first) | 性別→[1] | 回帰の多重共線性回避 |
| ordinal encoding | 整数 1...K | 成績 A→1 B→2 | 順序あり |
| label encoding | 整数(順序考慮なし) | 色→ 0..K-1 | ツリーモデル向け |
| target encoding | カテゴリ→目標変数の平均 | 市区町村→平均年収 | 高カーディナリティ |
| hashing trick | ハッシュで固定次元化 | 1.7 万→ 2¹⁰ 列 | メモリ節約 |
理解度を確認する 5 問。 解答例は折りたたみで隠してあります。 まず自力で考えてから開いてください。
2015 年 9 月開催の Kaggle コンペ Rossmann Store Sales で、 多くの参加者が 1115 店舗 ID を素直に one-hot encoding し、 メモリ不足・訓練時間爆発・精度低下に苦しんだ。 1115 列の sparse matrix では XGBoost のヒストグラム法も非効率化、 線形モデルでは多重共線性で発散。 一方で 3 位入賞の Cheng Guo・Felix Berkhahn は entity embedding(カテゴリを 10 次元 dense ベクトルに学習)を提案し、 1115 → 10 次元に圧縮しつつ店舗間の類似性を捕まえた。 翌年 KDD 2016 で「Entity Embeddings of Categorical Variables」として発表され、 以降のカテゴリ前処理の標準手法に。 教訓:カテゴリ数 100+ では one-hot より entity embedding / target encoding / hashing trick が有利。 ただし embedding には大量データと NN フレームワークが必要なので、 中規模データなら target encoding が現実解。
one-hot encoding を学ぶ際に頻出する 10 語の最小限定義集です。 詳しくは各専用ページを参照。
SSDSE-B-2026 の Prefecture 列 (47 件) を one-hot 化すると、 設計行列は次のサイズになります。
| 設定 | 列数 | 疎性 (zero 比率) | メモリ (47 行) |
|---|---|---|---|
| drop_first=False (全カテゴリ) | 47 | 46/47 = 97.87% | 47 × 47 × 1 byte = 2,209 byte |
| drop_first=True (基準削除) | 46 | ~97.83% | 47 × 46 × 1 byte = 2,162 byte |
| sparse 表現 (CSR) | 47 (論理列) | 97.87% (非零のみ保存) | 47 × (4+4) = 376 byte (約 1/6) |
気をつけたいケース: 高 cardinality — 仮に SSDSE-B-2026 を市区町村レベルに展開すると約 1,700 カテゴリ。 全件 one-hot で 1,700 列に膨れ上がり、 線形回帰のパラメタ数も 1,700 個。 「47 サンプル / 1,700 パラメタ」は完全に過学習領域 ($n \ll p$)。 この場合は target encoding や embedding への切替を検討します。
合成 5 サンプル × 3 カテゴリ (赤/青/緑) で One-Hot 列数を計算する。
| 元 | 赤 | 青 | 緑 |
|---|---|---|---|
| 赤 | 1 | 0 | 0 |
| 青 | 0 | 1 | 0 |
| 緑 | 0 | 0 | 1 |
| 赤 | 1 | 0 | 0 |
| 青 | 0 | 1 | 0 |
1 2 3 4 | import pandas as pd s = pd.Series(['赤','青','緑','赤','青']) oh = pd.get_dummies(s).astype(int) print(oh) |
💬 手計算 (Step 2) 行列と Python 出力が完全一致。
SSDSE-B-2026 などの実データを使った最小コード(7行):
1 2 3 4 5 6 7 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) cat_col = df.columns[1] # 都道府県等 oh = pd.get_dummies(df[cat_col], prefix='pref', drop_first=True) print('元のカテゴリ数:', df[cat_col].nunique()) print('one-hot後の列数:', oh.shape[1]) print(oh.head(3)) |
※ data/raw/SSDSE-B-2026.csv は e-Stat SSDSE から取得した実データを想定。
🎯 このコードでやること: SSDSE-B-2026 の Prefecture 列を pd.get_dummies で one-hot 化し、 形状 (47 行 × 47 列) を確認する。
📥 入力データ (SSDSE-B-2026 の Prefecture 列抜粋):
1 2 3 4 5 6 7 8 | 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) # 2023 年 = 47 都道府県だけ抽出 dummies = pd.get_dummies(df['Prefecture'], prefix='pref') print(f'形状: {dummies.shape}') print(f'各行の合計 (すべて 1 のはず): {dummies.sum(axis=1).unique()}') print(dummies.iloc[:3, :5]) |
📤 実行例:
💬 結果の読み方: 形状 (47, 47) と「行の合計が必ず 1」 — これが one-hot の数学的特性。 北海道行で pref_北海道=True となっていることも確認。
🎯 このコードでやること: 線形回帰で使うために drop_first=True を指定し、 47 列 → 46 列に削減。 基準カテゴリは辞書順最初の「三重県」。
📥 入力データ: 例 1 の df['Prefecture'] をそのまま使用。
1 2 3 4 5 6 7 8 9 | 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) # 2023 年 = 47 都道府県だけ抽出 d1 = pd.get_dummies(df['Prefecture'], drop_first=False) d2 = pd.get_dummies(df['Prefecture'], drop_first=True) print(f'drop_first=False: {d1.shape}') print(f'drop_first=True : {d2.shape}') print(f'削除されたカテゴリ: {set(d1.columns) - set(d2.columns)}') |
📤 実行例:
💬 結果の読み方: 「三重県」が基準カテゴリとなり、 残り 46 県の係数は「三重県からの差」を表す。 これにより設計行列のランク欠損が解消され、 OLS が解ける。
🎯 このコードでやること: 本番運用を見据えて OneHotEncoder を Pipeline に組み込み、 未知の都道府県が来ても handle_unknown='ignore' で落ちないようにする。
📥 入力データ: 例 1 と同じ。 Pipeline で前処理 + 回帰を一体化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.linear_model import LinearRegression from sklearn.pipeline import Pipeline from sklearn.compose import ColumnTransformer 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 都道府県だけ抽出 X = df[['Prefecture', 'A1101']] # 都道府県 + 人口 y = df['I510120'] # 一般病院数 ct = ColumnTransformer([ ('ohe', OneHotEncoder(drop='first', handle_unknown='ignore'), ['Prefecture']), ('num', StandardScaler(), ['A1101']), ]) pipe = Pipeline([('prep', ct), ('reg', LinearRegression())]).fit(X, y) print(f'学習後パラメタ数: {len(pipe.named_steps["reg"].coef_)}') print(f'R^2 (訓練): {pipe.score(X, y):.4f}') |
📤 実行例:
💬 結果の読み方: 46 (都道府県ダミー) + 1 (人口) = 47 パラメタ。 47 サンプル + 47 パラメタなので完全フィット (R²=1.000) = 過学習の典型。 cross_val_score で評価すると激減するはずで、 これが「$n \approx p$」の危険シグナチャ。
🎯 このコードでやること: 高 cardinality カテゴリ (たとえば 1,700 市区町村) を想定して、 sparse=True で疎行列に変換しメモリ使用量を比較する。
📥 入力データ: SSDSE-B-2026 の Code 列 (都道府県コード 47 種だが、 デモのため一律 sparse 化)。
1 2 3 4 5 6 7 8 9 10 | import pandas as pd from sklearn.preprocessing import OneHotEncoder 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 都道府県だけ抽出 codes = df[['Code']] ohe_dense = OneHotEncoder(sparse_output=False).fit_transform(codes) ohe_sparse = OneHotEncoder(sparse_output=True ).fit_transform(codes) print(f'dense shape: {ohe_dense.shape} nbytes: {ohe_dense.nbytes}') print(f'sparse shape: {ohe_sparse.shape} nnz: {ohe_sparse.nnz} data nbytes: {ohe_sparse.data.nbytes}') |
📤 実行例:
💬 結果の読み方: dense は 17.7KB、 sparse は 376 byte (約 1/47)。 47 カテゴリでは差が小さく感じるが、 100 万行 × 1,000 カテゴリでは dense=8GB → sparse=24MB と桁違いに効く。 sklearn のほとんどの線形モデルは sparse をネイティブ受付可能。
このコードでやること: SSDSE-B-2026 を 地方 (北海道/東北/関東 etc.) でラベル付けし、 drop_first=True と drop_first=False で pandas.get_dummies の挙動を比較。 後者で発生する dummy variable trap (定数列との完全多重共線性) を numpy.linalg.matrix_rank で可視化する。
📥 入力データ (SSDSE-B-2026 抜粋, 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 27 | import pandas as pd import numpy as np df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) df = df[df['年度'] == 2022].copy() region_map = {'北海道':['北海道'], '東北':['青森県','岩手県','宮城県','秋田県','山形県','福島県'], '関東':['茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県'], '中部':['新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県'], '近畿':['三重県','滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県'], '中国':['鳥取県','島根県','岡山県','広島県','山口県'], '四国':['徳島県','香川県','愛媛県','高知県'], '九州':['福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県'], '沖縄':['沖縄県']} inv = {p:r for r,ps in region_map.items() for p in ps} df['region'] = df['都道府県'].map(inv) # drop_first=False (trap 発生) X_full = pd.get_dummies(df['region'], prefix='reg', drop_first=False).astype(int) X_full.insert(0, 'const', 1) rank_full = np.linalg.matrix_rank(X_full.values) print(f"drop_first=False: 列数={X_full.shape[1]}, rank={rank_full}, 欠損次元={X_full.shape[1]-rank_full}") # drop_first=True (trap 回避) X_safe = pd.get_dummies(df['region'], prefix='reg', drop_first=True).astype(int) X_safe.insert(0, 'const', 1) rank_safe = np.linalg.matrix_rank(X_safe.values) print(f"drop_first=True: 列数={X_safe.shape[1]}, rank={rank_safe}, 欠損次元={X_safe.shape[1]-rank_safe}") |
📤 実行すると次の出力が得られる:
💬 結果の読み方: drop_first=False では const + 9 region 列 = 10 列なのに rank=9。 これが dummy variable trap (1 = reg_北海道 + reg_東北 + ... + reg_沖縄 という線形依存)。 OLS で (X'X)⁻¹ が計算不能になる。 drop_first=True なら 1 つの region を基準カテゴリ (e.g. 北海道) として落とすので rank=列数となり、 回帰係数は「北海道に対する差分」として解釈できる。 sklearn の OneHotEncoder では drop='first' が同じ役割。
drop_first=False のまま K 列入れると、 設計行列のランクが落ちて OLS が解けない (あるいは結果が解釈不能になる)。 線形回帰では必ず drop_first=True。 ただし正則化 (Ridge/Lasso) や決定木系では不要。handle_unknown='ignore' を設定し、 未知カテゴリは全 0 ベクトル扱いとする。OneHotEncoder.fit(train) → transform(test) の順で、 train の語彙を使い回す。 pd.get_dummies を train/test に別々にかけるのは典型的アンチパターン。カテゴリ列を入力すると、 各カテゴリが独立した 0/1 列 に展開される様子をリアルタイムで確認できます。 カテゴリを増やすと列が増える 高次元化、 切片を足すと起きる ダミー変数トラップ、 順序尺度を one-hot 化したときの 順序情報の消失 — 3 つの論点を手を動かして体感してください。 (すべてブラウザ内計算・外部通信なし。 rank はガウス消去で実測)
※ 列(カテゴリ)の並び順は 入力での初出順。 pandas get_dummies は既定でアルファベット/文字コード順に並べます(結果の 0/1 は同じ)。 drop_first はここでは初出先頭カテゴリを基準として落とします。
One-Hot エンコーディング (別名) を中心に、 同義語クラスタ (one-hot/ダミー変数化/カテゴリ二値化)、 前段 (カテゴリ変数識別・名義尺度)、 並列代替 (ラベル/ターゲット/頻度エンコーディング)、 後段モデル (線形回帰・ロジスティック回帰・ニューラルネット) を放射状に配置した SVG マップ。
本セクションでは one-hot encoding の 多重共線性 (dummy variable trap)・スパース行列の効率・未知カテゴリの扱いを補足する。 SSDSE の都道府県 47 水準の場合、 1 列落とすか定数項を外すかで設計行列の解釈が変わる — エンコード選択は単なる前処理ではなく回帰係数の意味づけにも波及する。
「One-Hot エンコーディング」は単独で完結せず、 前後の手法と組み合わさって価値が発揮される。 入力データの準備 (上流)・同目的の代替手法との比較 (並列)・結果の活用 (下流) という 3 軸で隣接領域を整理する。
この上流・並列・下流の対応を地図化することで、 「One-Hot エンコーディング」を中核に据えた分析パイプライン (データ準備 → 手法選択 → 結果の検証と展開) の全体像が見えてくる。
「One-Hot エンコーディング」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。
drop_first=True で 1 列落とし、 落とした水準を基準として読む。handle_unknown='ignore' を指定し、 学習時の列構成を保存して同じ変換を適用する。One-Hot は「順序の無いカテゴリを数値にする」道具。 順序があるもの(小・中・大)に使うと順序の情報が失われる。
既存セクションの内容を壊さずに、 「直感 → 落とし穴 → 発展」の 3 段で要点を再整理した追補です。 数値例は SSDSE-B-2026.csv(cp932・skiprows=[1])の実測に基づきます。
one-hot エンコーディングの核は 3 点だけです。 (1) カテゴリ変数を 各カテゴリにつき 1 列の 0/1 ダミーに展開する。 (2) どのカテゴリも互いに等距離(ユークリッド距離 $\sqrt{2}$)になるので 順序(大小)を一切仮定しない。 (3) 線形回帰・SVM・ニューラルネットなど 数値入力しか受け取れないモデルにカテゴリを渡すために必要になる。 「A=1, B=2, O=3」のような素朴な整数化は、 本来存在しない「O は A の 3 倍」という偽の順序を持ち込むため名義カテゴリには不適切で、 one-hot はこの誤解を構造的に防ぎます。
前提データ: SSDSE-B-2026.csv は実測で 564 行 = 47 都道府県 × 12 年度(2012〜2023)、 Prefecture 列は 47 カテゴリ。 以下はすべてこの列を題材にした実測値です。
pd.get_dummies(Prefecture) は (47, 47)。 これに切片列(全 1)を足すと設計行列は 48 列ですが rank は 47(欠損次元 1)で、 47 列の和が常に切片列と一致するため $X^\top X$ が特異になり OLS が一意に解けません。 対策は drop_first=True(sklearn は drop='first')で (47, 46) に縮約。 実測では基準として落ちるのは文字コード先頭の 「三重県」で、 切片+46 列は rank 47 のフルランクになり解が定まります。 残り 46 県の係数は「三重県との差」として読めます(詳細は ダミー変数・多重共線性)。drop_first は不要。 LightGBM/CatBoost は native categorical 機能を持ち、 one-hot 化せずに直接カテゴリを扱う方が高速・省メモリになることが多いです。handle_unknown='ignore'(未知は全 0 ベクトル)か、 前処理で "Other" 列に寄せる設計が実用的です。pd.get_dummies を train と test に別々に掛けると列数・列順がずれ、 推論時に破綻します。 必ず OneHotEncoder.fit(train) → transform(test) と train の語彙を固定して使い回すのが正解です。