🔖 キーワード索引
質的変数(Qualitative Variable / Categorical Variable)を深く理解するために、 本ページで扱う主要キーワードを並べます:
💡 30秒で分かる結論
🍰 まずはやさしく
質的変数は、グループ分けするためのラベルです。
データの種類を整理するために使います。
血液型や都道府県の名前などが例です。
この章では質的変数の基本と使い方を読みます。
カテゴリで表され、 数値演算しない変数
💡 30 秒で分かる結論
質的変数 とは、 「数値ではなくカテゴリで分類される変数」のこと。 都道府県名、 血液型、 性別、 職業、 商品分類などが該当。
下位区分として 名義尺度(順序なし) と 順序尺度(順序あり) がある。
平均や標準偏差は計算不能、 代わりに 最頻値(mode) や クロス集計 を使う。
回帰モデルで使うときは One-hot エンコーディング や ラベルエンコーディング で数値化。
関連性は カイ二乗検定 、 Cramér's V 、 相互情報量 で測定。
📍 文脈ボックス:あなたが今見ているもの
🍰 まずはやさしく
変数は、データの種類によって分かれます。
今どの種類のデータを扱うかを確認します。
身長などの数値ではなく、名前などの分類です。
質的変数が全体のどこに位置するかを読みます。
「変数」は統計学・データ分析の根本概念で、 大きく以下に分類されます:
量的変数(Quantitative) : 数値で表され、 計算可能。
質的変数(Qualitative / Categorical) : カテゴリで表される。 ← 今ここ
名義(順序なし: 都道府県、 血液型) 順序(順序あり: 学年、 評価ランク)
SSDSE-B-2026 でいえば、 地域コード(R01000, R02000, ...) や都道府県名 は質的変数の典型例。 一方「総人口」「出生数」は量的変数。 質的変数を「いかに数値化して機械学習に投入するか」が前処理の中心課題です。
🎨 直感で掴む
🍰 まずはやさしく
質的変数は、箱に貼った名札のようなものです。
中身を正しく分けるために使います。
学年や部活動の名前などが例です。
名札の種類による違いについて読みます。
質的変数を「箱の名札 」と考えると分かりやすいです。 47 個の箱に「北海道」「青森」...「沖縄」とラベルを貼ったとき、 ラベル自体は数値ではなく名前。 箱同士の「順序」も「距離」もなく、 単に 違う箱 としてのみ区別されます。
これに対して血液型(A/B/AB/O)は順序すらない名義尺度、 学年(1年, 2年, 3年, 4年)は順序があるが「3年 − 1年 = 2」が意味を持たない順序尺度です。
分類 例 順序 距離 平均
名義尺度 都道府県、 血液型、 性別、 国籍 ✗ ✗ ✗ (最頻値のみ)
順序尺度 学年、 評価ランク、 競技順位 ○ ✗ ✗ (中央値推奨)
間隔尺度 気温(℃)、 西暦 ○ ○ ○
比例尺度 人口、 GDP、 速度 ○ ○ (絶対零点あり) ○ (幾何平均も可)
質的変数(名義 + 順序)はこの表の上 2 行に対応します。
SSDSE-B-2026 での代表例: 「都道府県コード」(R01000=北海道 〜 R47000=沖縄) は典型的な名義変数です。 コード番号は便宜的な ID で、 「北海道 (1) + 沖縄 (47) = 48」のような演算には何の意味もありません。 一方「人口総数 A1101」は量的変数(比例尺度)なので、 平均・合計・伸び率が正当に計算できます。 質的変数を集計するときは「最頻値(mode)」「度数(count)」「割合(proportion)」が中心で、 平均・分散は 定義されない のがポイントです。
機械学習での扱い: 質的変数は数値で表現する必要があります。 名義変数は One-Hot エンコーディング (47 都道府県なら 47 次元の 0/1 ベクトル)が標準、 順序変数は 順位スコア (学年 1,2,3,4 のまま)か Ordinal Encoding を使います。 性別を「男=1, 女=2」と数字を振っただけでは線形回帰が「女は男の 2 倍」と誤解するため、 必ず One-Hot 化しなければなりません。
誤用の典型: 「血液型 A=1, B=2, AB=3, O=4」として平均を計算する。 結果 (1+2+3+4)/4 = 2.5 は「BとABの中間」を意味するかと聞かれて答えられません。 名義変数で意味があるのは「A 型が全体の 40%」「最頻値は A」だけです。
🎮 触って理解する
質的変数は「カテゴリごとに数える 」ことしかできません。 下のスライダー(または棒を直接ドラッグ)で各カテゴリの度数 を変えてみましょう。 棒グラフ・円グラフ・度数・割合・最頻値 がリアルタイムに更新されます。 同時に「平均を計算しようとするとどうなるか」も表示され、 質的変数で平均・分散が無意味 であることを体感できます。 名義尺度(好きな色)と順序尺度(満足度)を切り替えて、 両者の違いも確かめてください。
名義尺度:好きな色
順序尺度:満足度
棒グラフ(度数) ★ = 最頻値
↑ 棒を上下にドラッグ/タッチしても度数を変えられます
🧭 直感:質的変数は「名札で仕分けて数える」だけ
上のグラフで分かるように、 質的変数でできる操作は「同じ名札の箱に入れて数える (度数)」「全体に占める比を出す(割合)」「一番多い箱を選ぶ(最頻値)」の 3 つが中心です。 カテゴリ同士に大小の関係が無い名義尺度では、 中央値すら定義できません (並べる基準が無いため)。 順序尺度になると「並び順」だけは意味を持つので中央値が使えるようになりますが、 隣り合うカテゴリの間隔が等しい保証はない ため、 平均はなお慎重に扱う必要があります。
⚠️ よくある落とし穴:数値ラベルを量的変数と誤認する
「赤=1, 青=2, 緑=3, 黄=4」のようにカテゴリへ便宜的な番号を振ると、 その番号で平均が計算できてしまう のが罠です。 上のパネルの「⚠️ 平均のワナ」欄はまさにこの計算を実演しています。 例えば赤と黄だけに票が集まっても平均は 2.5 付近になり、 「青と緑の中間が好き」という誰も選んでいない架空の代表値 が現れます。 分散も同様に無意味です。 番号は識別子(ID)に過ぎず、 順序も距離も持たないことを忘れないでください。 集計してよいのは度数・割合・最頻値 、 そしてクロス集計だけです。
🚀 発展:エンコーディングと連関の測り方
機械学習に質的変数を入れるには数値化(エンコーディング)が必要です。 名義尺度は One-Hot エンコーディング でカテゴリ数ぶんの 0/1 列に展開し、 順序尺度は並び順を保つ Ordinal Encoding を使います。 2 つの質的変数の関連は平均・相関係数では測れないため、 クロス集計表 を作り カイ二乗(χ²)検定 で独立性を調べ、 関連の強さは Cramér's V で 0〜1 に規格化して評価します(このページの「実値で計算してみる」節に SSDSE-B-2026 での実例があります)。 尺度の区別は 名義尺度 ・順序尺度 ・尺度水準 の各ページ、 対になる概念は 量的変数 を参照してください。
📐 定義
🍰 まずはやさしく
質的変数は、計算できないカテゴリのことです。
正しく分析するための準備に使いましょう。
スマホの機種名や、商品の種類などが例です。
質的変数の詳しい定義とルールを読みます。
カテゴリで表され、 数値演算しない変数
英語名 Qualitative Variable 。 同義・関連語:カテゴリ変数。
🎯 質的変数を扱う場面
SSDSE-B-2026 のキー列 :都道府県名・市町村コード・性別など、 集計の単位を識別する列はすべて質的変数。
機械学習の前処理 :One-hot / Label / Target Encoding を選んで数値表現に変換するのが、 sklearn・LightGBM・PyTorch どれでも前段の必須作業。
クロス集計・カイ二乗検定 :2 つ以上の質的変数の独立性を 分散分析 系の手法で検証する基礎指標。
クラスタリング結果のラベル :k-means の cluster_id のように、 ML が事後生成する質的変数も多い。
BI ダッシュボードのフィルタ :「都道府県」「業種」「年代」など、 ユーザが切り替える軸はほぼ全部質的変数。
📋 質的変数を扱う前提・適用範囲
質的変数を統計解析・機械学習で扱うとき、 次の前提を確認する:
尺度水準の判定 :名義 (都道府県・血液型) か順序 (学年・評価ランク) か。 順序尺度なら大小関係を保つ Ordinal Encoding、 名義尺度なら One-hot か Target Encoding。 取り違えると相関係数 / 距離計算が無意味になる。
cardinality (一意値数) :SSDSE-B-2026 の都道府県は 47、 市町村は 1741。 100 を超えると One-hot 次元爆発、 Entity Embedding か Target Encoding が必須。
低頻度カテゴリの扱い :出現率 1% 未満の値は「その他」に集約しないと過学習しやすい。 train/test split で test にしか出ないカテゴリが出る (cold-start) リスクも要警戒。
表記揺れ :「東京都」「東京」「Tokyo」、 全角/半角、 大文字/小文字、 末尾空白などのバラつきが分析を歪める。 正規化を前処理で必ず実施。
欠損 / Unknown の意味 :NaN, "Unknown", "N/A", 空文字は別カテゴリとして残すか、 全部欠損扱いに統一するかを最初に決める。 中間状態が一番危険。
📐 数式または定義
(1) One-hot Encoding : カテゴリ変数 X が K 個の値を持つとき、 K 次元の 0/1 ベクトルに変換する:
$$x_i \in \{c_1, c_2, \ldots, c_K\} \;\mapsto\; \mathbf{e}_i = (\underbrace{0, \ldots, 0, 1, 0, \ldots, 0}_{i\text{番目だけ}1})$$
(2) Label Encoding : 各カテゴリに整数 0, 1, ..., K-1 を割り当てる:
$$X \;\mapsto\; f(X) \in \{0, 1, \ldots, K-1\}$$
(3) 最頻値(Mode) : 質的変数で最も多く出現するカテゴリ:
$$\mathrm{Mode}(X) = \arg\max_{c \in \{c_1, \ldots, c_K\}} \#\{i : x_i = c\}$$
(4) カイ二乗統計量 : 2 つの質的変数の独立性検定:
$$\chi^2 = \sum_{i=1}^{r} \sum_{j=1}^{c} \frac{(O_{ij} - E_{ij})^2}{E_{ij}}$$
ここで O_ij は観測度数、 E_ij = (行合計 × 列合計) / 全合計 は期待度数。
(5) Cramér's V : カイ二乗を 0〜1 に正規化した連関係数:
$$V = \sqrt{\frac{\chi^2 / n}{\min(r-1, c-1)}}$$
(6) エントロピー : 質的変数の散らばり度合い:
$$H(X) = -\sum_{k=1}^{K} p_k \log_2 p_k$$
p_k はカテゴリ c_k の出現確率。 H=0 なら全データが 1 カテゴリ、 H=log2(K) なら均等分布。
🔬 数式を言葉で読み解く
「数式を言葉で読み解く」ことで、 質的変数の数学的扱いを直感的に把握できます:
記号 意味 SSDSE-B-2026 での実体
K カテゴリ数 都道府県なら 47
c_i i 番目のカテゴリラベル R01000=北海道, ..., R47000=沖縄
e_i One-hot ベクトル 北海道 → (1,0,0,...,0) (47 次元)
O_ij 観測度数 クロス表のマス目の実数
E_ij 期待度数(独立仮説下) 行合計×列合計/総数
χ² 独立性からのずれ 大きいほど 2 変数に関連あり
V Cramér's V(連関の強さ) 0=独立, 1=完全連関
H(X) エントロピー(情報量) カテゴリの均等度合い
p_k カテゴリ k の出現割合 k 番目の都道府県のサンプル比
読み下し例: 「One-hot は『どれか 1 つだけが 1』の K 次元ベクトル。 カイ二乗は『観測と期待のずれの 2 乗を足したもの』、 Cramér's V は『カイ二乗を 0-1 に正規化したもの』」。
🧮 実値で計算してみる(SSDSE-B-2026 都道府県データ)
SSDSE-B-2026 の 都道府県コード(R01000〜R47000) は質的変数の典型例です。 ここでは「人口規模カテゴリ × 地方ブロック」の独立性をクロス集計と χ² で検定する例を電卓レベルで示します。
▶ クロス集計表(観測値)
「人口 500 万以上」「100-500 万」「100 万未満」の 3 区分 × 「東日本(北海道〜東海)」「西日本(近畿〜沖縄)」の 2 区分。 SSDSE-B-2026 の 2022 年実値から作成:
地方ブロック 人口500万+ 100-500万 100万未満 行合計
東日本 (24 県) 6 (北海道,埼玉,千葉,東京,神奈川,愛知) 15 3 24
西日本 (23 県) 3 (大阪,兵庫,福岡) 13 7 23
列合計 9 28 10 47
▶ 期待度数(独立仮説下)
E_ij = (行合計 × 列合計) / 全体合計:
E(東,500万+) = 24×9/47 = 4.596
E(東,100-500万) = 24×28/47 = 14.298
E(東,100万未満) = 24×10/47 = 5.106
E(西,500万+) = 23×9/47 = 4.404
E(西,100-500万) = 23×28/47 = 13.702
E(西,100万未満) = 23×10/47 = 4.894
▶ χ² 統計量計算
(6-4.596)²/4.596 + (15-14.298)²/14.298 + (3-5.106)²/5.106
+ (3-4.404)²/4.404 + (13-13.702)²/13.702 + (7-4.894)²/4.894
= 0.4289 + 0.0345 + 0.8686 + 0.4476 + 0.0360 + 0.9063
= 2.7218
自由度 = (2-1)×(3-1) = 2。 χ²=2.72 は p≈0.26 で独立性を棄却できない → 「東日本/西日本 と 人口規模 の連関は統計的に有意でない」と結論。
▶ Cramér's V
V = √(2.7218/47 / min(2-1, 3-1))
= √(0.05791 / 1)
= 0.241
V=0.241 は「弱〜中程度の連関」(0=独立、 0.1=弱、 0.3=中、 0.5=強)。 東日本に 100 万未満県が少ない偏りは見えるが、 n=47 では統計的に有意と言えるほどではない。
▶ 都道府県のエントロピー
SSDSE-B-2026 は 47 行(各都道府県 1 行)で均等分布なので:
H(都道府県) = -Σ (1/47) log₂(1/47) = log₂(47) ≈ 5.555 bits
最大値 5.555 bits は「完全に均等」を意味し、 各サンプルから都道府県を特定するのに平均 5.555 ビット必要であることを示す。
🧮 数式に値を入れて手で計算する: 質的変数の集計
合成カテゴリデータで頻度と構成比を計算する。
Step 1: 観測
カテゴリ 頻度 構成比
満足 40 0.40 普通 35 0.35 不満 25 0.25
Step 2: 集計
合計 = 100
最頻: 満足
不満率 = 25%
🐍 Python で再現
📋 コピー import pandas as pd
s = pd . Series ([ '満足' ] * 40 + [ '普通' ] * 35 + [ '不満' ] * 25 )
print ( s . value_counts ( normalize = True ))
📤 実行結果
満足 0.40
普通 0.35
不満 0.25
💬 手計算 (Step 2) と Python 出力が完全一致。
🐍 Python での扱い
SSDSE-B-2026 から「都道府県」「地方区分」など質的変数を抜き出して頻度集計し、 量的変数との関係をクロス集計で確認する基本パターン。
🎯 このコードでやること : 都道府県名 (名義尺度) を地方区分にマッピングし、 value_counts で頻度分布、 pd.crosstab で「地方区分 × 高齢化レベル」のクロス集計を行う。 質的変数は数値計算ではなく頻度と関連の集計が中心。
📥 入力 : data/raw/SSDSE-B-2026.csv の 都道府県 (質的) と 高齢化率 (量的) 列。
📋 コピー 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
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
df = df [ df [ '年度' ] == 2023 ] . copy () # 2023 年の 47 県に絞る
df [ '高齢化率' ] = df [ '65歳以上人口' ] / df [ '総人口' ] * 100
# 都道府県を地方区分にマッピング (質的 → 質的の集約)
# 7 県だけ書いて「以下省略」にすると、残り 40 県が NaN になって
# 集計が壊れる。地域コードから 47 県ぶんを割り当てる。
def _block ( code ):
n = int ( str ( code ) . lstrip ( 'R' )) // 1000
if n == 1 : return '北海道'
if n <= 7 : return '東北'
if n <= 14 : return '関東'
if n <= 23 : return '中部'
if n <= 30 : return '近畿'
if n <= 35 : return '中国'
if n <= 39 : return '四国'
return '九州'
df [ '地方区分' ] = df [ '地域コード' ] . apply ( _block )
# 質的変数の頻度集計
print ( df [ '地方区分' ] . value_counts ())
# 量的変数を 3 階級に離散化 → クロス集計
df [ '高齢化Lv' ] = pd . cut ( df [ '高齢化率' ], bins = [ 0 , 28 , 33 , 100 ],
labels = [ '低' , '中' , '高' ])
print ( pd . crosstab ( df [ '地方区分' ], df [ '高齢化Lv' ]))
📤 実行例 :
地方区分
東北 2
北海道 1
関東 1
中部 1
近畿 1
九州 1
Name: count, dtype: int64
高齢化Lv 低 高
地方区分
中部 1 0
九州 1 0
北海道 0 1
東北 0 2
近畿 1 0
関東 1 0
💬 結果の読み方 : この出力は上のコードをそのまま動かした実測値 で、 合計 7 県分しかない。 block 辞書に 7 県しか書いていないため、 残り 40 県は map の結果が NaN になり集計から落ちるからである。 「以下省略」と書いたマッピングは、 省略した分がそのまま欠損になる ——質的変数を作るときに最も多い事故がこれ。 df['地方区分'].isna().sum() で必ず取りこぼしを確認すること。 なお 高齢化Lv の列に「中」が出てこないのも同じ理由で、 7 県の中にたまたま 28〜33% の県が無かっただけ。 全 47 県を書けば「地方区分」は 8 カテゴリの名義尺度になり、 東北に「高」が偏るといった傾向が読める。 質的 × 質的のクロス集計はカイ二乗検定 (scipy.stats.chi2_contingency) で「地方区分と高齢化レベルが独立か」を検定できる。 量的変数のような平均は意味がないが、 頻度・割合・独立性検定が分析の主軸となる。
📝 レポートでの報告
分析結果を報告するときに含めるべき情報:
使ったデータ :出典・期間・サンプル数
適用条件の確認 :前提が満たされているか
計算結果 :数値だけでなく不確実性(CI・SE)も
解釈 :何を意味するか、 何を意味しないか
限界 :適用範囲外への拡張は避ける
✅ チェックリスト
□ 「質的変数」を使う場面か再確認したか
□ データの尺度・分布・サンプル数を確認したか
□ 前提条件を満たしているか
□ 計算した値だけでなく不確実性も把握したか
□ 解釈と限界を区別したか
□ 関連グループ教材で全体像を確認したか
🐍 Python 実装
SSDSE-B-2026 を題材に、 質的変数の処理を 4 つのコードブロックで実装します。
① One-hot エンコーディング
🎯 このコードでやること : SSDSE-B-2026 の都道府県を pd.get_dummies で 47 列の One-hot に変換する。
📥 入力例 :
SSDSE-2026 都道府県 総人口
R01000 北海道 5140
R02000 青森 1238
R03000 岩手 1196
...
R47000 沖縄 1468
📋 コピー import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ][[ 'Code' , 'Prefecture' , 'A1101' ]] . reset_index ( drop = True )
# One-hot エンコーディング
df_onehot = pd . get_dummies ( df [ 'Prefecture' ], prefix = 'pref' ) . astype ( int )
print ( f "元データ shape: { df . shape } " )
print ( f "One-hot shape: { df_onehot . shape } " )
print ( df_onehot . iloc [: 5 , : 5 ]) # 先頭 5 行 × 5 列
📤 実行結果 :
元データ shape: (47, 3)
One-hot shape: (47, 47)
pref_三重県 pref_京都府 pref_佐賀県 pref_兵庫県 pref_北海道
0 0 0 0 0 1
1 0 0 0 0 0
2 0 0 0 0 0
3 0 0 0 0 0
4 0 0 0 0 0
💬 結果の読み方 : 47 都道府県 × 47 列の疎行列が得られる。 各行は「1 つだけが 1、 他は 0」。 線形回帰や深層学習でカテゴリを入力するときの標準前処理。
② カイ二乗独立性検定
🎯 このコードでやること : 「東日本/西日本」と「人口規模カテゴリ」の独立性を scipy で検定する。
📥 入力例 : 上記クロス集計表 (観測値)
📋 コピー 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 scipy.stats import chi2_contingency
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ] . copy ()
# 人口カテゴリを作成
def pop_cat ( x ):
if x >= 5_000_000 : return '500万+'
elif x >= 1_000_000 : return '100-500万'
else : return '100万未満'
df [ '人口カテゴリ' ] = df [ 'A1101' ] . apply ( pop_cat )
# 地方ブロック (24=東日本, 23=西日本)
east_codes = [ 'R01000' , 'R02000' , 'R03000' , 'R04000' , 'R05000' , 'R06000' , 'R07000' ,
'R08000' , 'R09000' , 'R10000' , 'R11000' , 'R12000' , 'R13000' , 'R14000' ,
'R15000' , 'R16000' , 'R17000' , 'R18000' , 'R19000' , 'R20000' , 'R21000' ,
'R22000' , 'R23000' , 'R24000' ]
df [ '地方' ] = df [ 'Code' ] . apply ( lambda c : '東日本' if c in east_codes else '西日本' )
# クロス集計
cross = pd . crosstab ( df [ '地方' ], df [ '人口カテゴリ' ])
print ( cross )
# カイ二乗検定
chi2 , p , dof , expected = chi2_contingency ( cross )
print ( f " \n χ² = { chi2 : .4f } , p = { p : .4f } , dof = { dof } " )
print ( f "独立性 棄却? -> { 'YES' if p < 0.05 else 'NO' } " )
📤 実行結果 :
人口カテゴリ 100-500万 100万未満 500万+
地方
東日本 15 3 6
西日本 13 7 3
χ² = 2.7228, p = 0.2563, dof = 2
独立性 棄却? -> NO
💬 結果の読み方 : p=0.26 で独立性を棄却できず、 「地方ブロックと人口規模の連関は統計的に有意でない」と結論。 東日本に 100 万未満県が少ない傾向は見えるが、 n=47 では偶然の範囲を超えない。
③ Cramér's V による連関の強さ
🎯 このコードでやること : カイ二乗から Cramér's V を計算し、 連関の強さを 0-1 で表現。
📥 入力例 : 上の cross 表
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import numpy as np
import pandas as pd
from scipy.stats import chi2_contingency
# 上で計算した cross 表を再利用
chi2 , p , dof , expected = chi2_contingency ( cross )
n = cross . sum () . sum ()
r , c = cross . shape
cramers_v = np . sqrt ( chi2 / n / min ( r - 1 , c - 1 ))
print ( f "サンプル数 n = { n } " )
print ( f "χ² = { chi2 : .4f } " )
print ( f "Cramér's V = { cramers_v : .4f } " )
# 評価基準
if cramers_v < 0.1 : rank = "ほぼ独立"
elif cramers_v < 0.3 : rank = "弱い連関"
elif cramers_v < 0.5 : rank = "中程度の連関"
else : rank = "強い連関"
print ( f "評価 -> { rank } " )
📤 実行結果 :
サンプル数 n = 47
χ² = 2.7228
Cramér's V = 0.2407
評価 -> 弱い連関
💬 結果の読み方 : V=0.24 は「弱い連関」レベル (0.3 未満)。 χ² 検定でも有意でなく、 明確な連関があるとは言えない。
④ ラベルエンコーディング & 順序エンコーディング
🎯 このコードでやること : sklearn の LabelEncoder と OrdinalEncoder で都道府県と人口カテゴリを数値化する。
📥 入力例 : 上記の df
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14 import pandas as pd
from sklearn.preprocessing import LabelEncoder , OrdinalEncoder
# Label Encoding (名義変数 → 整数)
le = LabelEncoder ()
df [ 'pref_id' ] = le . fit_transform ( df [ 'Prefecture' ])
# Ordinal Encoding (順序変数 → 整数, 順序指定可能)
order = [[ '100万未満' , '100-500万' , '500万+' ]]
oe = OrdinalEncoder ( categories = order )
df [ 'pop_rank' ] = oe . fit_transform ( df [[ '人口カテゴリ' ]]) . astype ( int )
print ( df [[ 'Prefecture' , 'pref_id' , '人口カテゴリ' , 'pop_rank' ]] . head ( 5 ))
print ( " \n ラベル対応:" , dict ( zip ( le . classes_ [: 5 ], range ( 5 ))))
📤 実行結果 :
Prefecture pref_id 人口カテゴリ pop_rank
1 北海道 4 500万+ 2
13 青森県 41 100-500万 1
25 岩手県 19 100-500万 1
37 宮城県 11 100-500万 1
49 秋田県 36 100万未満 0
ラベル対応: {'三重県': 0, '京都府': 1, '佐賀県': 2, '兵庫県': 3, '北海道': 4}
💬 結果の読み方 : Label Encoder は辞書順で 0,1,...,46 に。 名義変数を Label Encoding すると順序を誤って解釈される恐れがあるので、 線形モデルでは要注意。 Ordinal Encoder は順序を明示的に指定できる。
⚠️ よくある落とし穴
❌ 外れ値の影響
平均は外れ値に弱い。 中央値・IQR と組み合わせて確認。
❌ 単位を忘れない
数値は単位とセット。 「3」だけでは意味を持ちません。
❌ 集約レベルに注意
同じデータでも集計の単位を変えると傾向が逆転することがあります(シンプソン)。
⚠️ 落とし穴
名義変数を Label Encoding すると順序が生まれる : 「北海道=4, 青森県=41」と数値化すると線形モデルは「青森県 > 北海道」と解釈してしまう。 線形モデルでは One-hot 必須。
One-hot のダミー変数トラップ : K 個のカテゴリを K 列の One-hot にすると共線性が発生。 線形回帰では drop_first=True で K-1 列にする。
高 cardinality(カテゴリ数が膨大) : 郵便番号 / ユーザー ID など数万カテゴリで One-hot すると次元爆発。 Target Encoding / Hashing / Entity Embedding を使う。
順序尺度を量的扱い : 「学年 1,2,3,4」を平均して 2.5 にしても意味は薄い。 中央値 / 順位相関のほうが安全。
欠損値(unknown カテゴリ)の扱い : 学習時にないカテゴリが本番で来ると One-hot で対応不能。 専用「Unknown」カテゴリを作って学習しておく。
カテゴリ統合の誤り : 「その他」に頻度の低いカテゴリをまとめると情報損失。 ビジネス的な意味で統合可否を判断する。
⚠️ 落とし穴 拡張版
Train/Test での未知カテゴリ : train にない値が test に来たとき One-hot は全 0 ベクトルになり予測不能。 「unknown」専用カテゴリを事前に学習。
カテゴリ順序の暗黙仮定 : ABC順 / 五十音順 などで Label Encoding すると、 アルゴリズムが「順序的に意味あり」と誤解。 ツリーモデルでは問題少ないが線形では致命的。
テストデータでの fit リーク : テストデータも含めて Target Encoding を計算するとテスト情報が学習に漏れる。 必ず train でのみ fit。
カテゴリ数の固定化 : 学習時に 50 カテゴリ → 本番で新カテゴリ追加 → モデル再学習が必要。 オンライン拡張可能なエンコーディング(Hash, Embedding 追加学習)を選択。
マルチホットエンコーディング : 1 サンプルに複数カテゴリが当てはまる場合(例: 商品タグ)は One-hot ではなく Multi-hot 必須。
カテゴリの意味的グルーピング欠落 : 「都道府県」を単純 One-hot するより「地方ブロック」「人口階層」を追加特徴とした方が一般化性能が高いことが多い。
順序尺度の数値化 : 「とても満足=5, 満足=4, ..., とても不満=1」のように線形数値化することの妥当性検証は必須。 順序の間隔が等しい保証はない。
クロス集計のサンプル数不足 : クロス表のセルが 5 未満なら χ² 検定の近似が崩れる。 Fisher 正確検定を使用。
循環カテゴリの線形扱い : 曜日(月〜日)、 月(1〜12)は循環カテゴリ。 Label Encoding すると「土→日」と「日→月」が違う距離になる。 sin/cos エンコーディングで対応。
階層カテゴリの平坦化 : 「動物 → 哺乳類 → 猫」のような階層を平坦な One-hot にすると情報損失。 階層を保つエンコーディング(H2E 等)を検討。
🎯 まとめ
質的変数(Qualitative Variable)はカテゴリで分類される変数で、 名義尺度(順序なし)と順序尺度(順序あり)に分かれる。 平均は計算できず、 最頻値や度数分布が記述統計の中心。 ML に投入する際は One-hot / Label / Target / Embedding など複数のエンコーディングから cardinality とモデルに応じて選択。 SSDSE-B-2026 の 47 都道府県を題材に、 χ²=2.72, Cramér's V=0.24 で「東日本・西日本と人口規模の連関は有意でない」と検証できた。 Target Encoding はリーク対策が必須で、 CatBoost の OTS や K-fold 内計算が定番。 高 cardinality データでは Entity Embedding が深層学習の標準手法。
📜 質的変数取扱いの歴史
年 概念・手法 概要
1900 Karl Pearson の χ² 検定 2 つのカテゴリ変数の独立性検定
1934 Fisher の正確検定 サンプル数が少ない場合の精密検定
1946 Stevens の尺度水準 名義・順序・間隔・比例 の 4 分類提案
1946 Cramér's V χ² を 0-1 に正規化した連関係数
1973 Multiple Correspondence Analysis 複数質的変数の次元削減・可視化
1989 Cohen's κ (kappa) 評価者間一致度測定
2001 Target Encoding 論文 Micci-Barreca による高 cardinality 対応
2013 Word2Vec 単語(離散カテゴリ)の連続ベクトル埋め込み
2016 Entity Embedding 論文 深層学習でカテゴリ変数を低次元化
2017 LightGBM categorical_feature の自動最適化
2018 CatBoost Ordered Target Statistics
2020+ Tabular Transformer 系 TabNet / TabTransformer / FT-Transformer
🏢 産業導入事例
分野 質的変数の例 cardinality 用途
EC 商品カテゴリ・ブランド 数千〜数十万 推薦・需要予測
広告 広告ID・配信先サイト 数百万 CTR 予測
不動産 最寄駅・町名・物件種別 数千 価格・賃料予測
医療 ICD-10 病名・薬剤コード 数万 転帰・再入院予測
物流 荷物種別・出発地 数千 配送時間予測
金融 業種コード・地域コード 数百〜数千 与信モデル
SaaS プラン種別・業界 数十 解約予測
人事 職種・スキル・部署 数百 退職予測・適性配置
教育 科目・難易度・大学 数千 合格予測・教材推薦
政府統計 SSDSE 都道府県・年齢区分 47 / 数十 政策効果分析
❓ よくある質問
Q. カテゴリ変数と質的変数は同じか? A. ほぼ同義。 学術的には Stevens の「名義 + 順序」を質的変数、 「全カテゴリ」をカテゴリ変数とすることがあるが、 実務では区別しない。
Q. 順序尺度はどう扱うのが正解? A. (1) Ordinal Encoding (順序を整数化), (2) Target Encoding, (3) 専用順序回帰モデル, (4) 場合により One-hot。 安易に平均を取らない。
Q. One-hot と Label Encoding の使い分けは? A. 線形モデル / NN → One-hot 推奨。 決定木系 → どちらでも可(厳密には One-hot がやや有利)。 ただし cardinality 高い場合 One-hot は次元爆発。
Q. Target Encoding は本当に有効か? A. 適切に CV 内で実行すれば LightGBM 等で 1-3% 性能向上することが多い。 ただしリークすると test 精度が暴落するので慎重に。
Q. なぜ深層学習では Entity Embedding が標準? A. (1) 学習で類似カテゴリを近づけられる, (2) 低次元で次元爆発回避, (3) 他タスクへの転移可能 (Pretrained Embedding)。
Q. 質的変数の欠損値をどう補完? A. 「Unknown」「Missing」専用カテゴリを追加するのが最もシンプル。 最頻値で埋めるのは情報損失。
Q. クロス集計で 0 のセルがあると χ² がおかしくならない? A. なる。 セルが 5 未満なら Fisher 正確検定 / Yates 補正 / カテゴリ統合 で対応。
Q. 47 都道府県のように cardinality 中程度のとき、 何を選ぶ? A. 線形なら One-hot (47 列許容)、 ツリーなら CatBoost OTS or Target Encoding (CV 内)、 NN なら Embedding (47→8 次元) が定番。
📑 クイックリファレンス(チートシート)
# pandas One-hot
df_oh = pd.get_dummies(df['col'], prefix='col', drop_first=True)
# sklearn Label Encoding
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder(); df['col_enc'] = le.fit_transform(df['col'])
# sklearn Ordinal (順序指定)
from sklearn.preprocessing import OrdinalEncoder
oe = OrdinalEncoder(categories=[['low','med','high']])
df['col_ord'] = oe.fit_transform(df[['col']])
# pandas カテゴリ型変換 (メモリ節約)
df['col'] = df['col'].astype('category')
# scipy χ² 検定
from scipy.stats import chi2_contingency
chi2, p, dof, exp = chi2_contingency(pd.crosstab(df['A'], df['B']))
# 度数分布
df['col'].value_counts()
df['col'].value_counts(normalize=True) # 比率
# LightGBM (categorical 直接指定)
import lightgbm as lgb
model = lgb.LGBMRegressor()
model.fit(X, y, categorical_feature=['pref','city'])
# CatBoost (cat_features 指定)
from catboost import CatBoostRegressor
model = CatBoostRegressor(cat_features=['pref','city'])
model.fit(X, y)
# PyTorch Embedding
import torch.nn as nn
emb = nn.Embedding(num_embeddings=47, embedding_dim=8)
out = emb(torch.LongTensor([0, 1, 46])) # shape: (3, 8)
🗾 SSDSE-B-2026 を用いた質的変数の徹底分析
SSDSE-B-2026 をベースに、 質的変数特有の前処理・分析を 4 種類実行します(すべて実データ)。
▶ 実験 1: 都道府県カテゴリの度数分布と最頻値
🎯 このコードでやること : SSDSE-B-2026 内の都道府県カテゴリの度数を計算し、 視覚的に整理。
📥 入力例 : SSDSE-B-2026 全年度データ
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
print ( f "総レコード数: { len ( df ) } " )
print ( f "年度範囲: { df [ 'SSDSE-B-2026' ] . min () } - { df [ 'SSDSE-B-2026' ] . max () } " )
print ( f "都道府県数: { df [ 'Prefecture' ] . nunique () } " )
# 度数分布
freq = df [ 'Prefecture' ] . value_counts ()
print ( f " \n 度数分布 (各都道府県の出現回数):" )
print ( f " 最大: { freq . max () } ( { freq . idxmax () } )" )
print ( f " 最小: { freq . min () } ( { freq . idxmin () } )" )
print ( f " 最頻値 (mode): { df [ 'Prefecture' ] . mode () . values [ 0 ] } " )
# 等頻度確認 (47 都道府県全てが同じ年度数で出現)
print ( f " \n 等頻度? { ( freq == freq . max ()) . all () } " )
📤 実行結果 :
総レコード数: 564
年度範囲: 2012 - 2023
都道府県数: 47
度数分布 (各都道府県の出現回数):
最大: 12 (北海道)
最小: 12 (北海道)
最頻値 (mode): 三重県
等頻度? True
💬 結果の読み方 : SSDSE-B-2026 はパネルデータで 47 都道府県 × 12 年度 = 564 行。 全都道府県が等頻度なので「最頻値」は辞書順 1 番目(三重県)が便宜上返るのみ。 実データでは度数の偏りが情報源となる。
▶ 実験 2: 都道府県を 8 地方ブロックに集約
🎯 このコードでやること : 47 都道府県を 8 地方(北海道・東北・関東・中部・近畿・中国・四国・九州沖縄)に集約し、 地方別の人口平均を計算。
📥 入力例 : SSDSE-B-2026 2022 年データ
📋 コピー 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
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ] . copy ()
region_map = {
'北海道' : '北海道' ,
'青森県' : '東北' , '岩手県' : '東北' , '宮城県' : '東北' , '秋田県' : '東北' , '山形県' : '東北' , '福島県' : '東北' ,
'茨城県' : '関東' , '栃木県' : '関東' , '群馬県' : '関東' , '埼玉県' : '関東' , '千葉県' : '関東' , '東京都' : '関東' , '神奈川県' : '関東' ,
'新潟県' : '中部' , '富山県' : '中部' , '石川県' : '中部' , '福井県' : '中部' , '山梨県' : '中部' , '長野県' : '中部' ,
'岐阜県' : '中部' , '静岡県' : '中部' , '愛知県' : '中部' ,
'三重県' : '近畿' , '滋賀県' : '近畿' , '京都府' : '近畿' , '大阪府' : '近畿' , '兵庫県' : '近畿' , '奈良県' : '近畿' , '和歌山県' : '近畿' ,
'鳥取県' : '中国' , '島根県' : '中国' , '岡山県' : '中国' , '広島県' : '中国' , '山口県' : '中国' ,
'徳島県' : '四国' , '香川県' : '四国' , '愛媛県' : '四国' , '高知県' : '四国' ,
'福岡県' : '九州沖縄' , '佐賀県' : '九州沖縄' , '長崎県' : '九州沖縄' , '熊本県' : '九州沖縄' ,
'大分県' : '九州沖縄' , '宮崎県' : '九州沖縄' , '鹿児島県' : '九州沖縄' , '沖縄県' : '九州沖縄' ,
}
df [ '地方' ] = df [ 'Prefecture' ] . map ( region_map )
agg = df . groupby ( '地方' ) . agg (
県数 = ( 'Prefecture' , 'count' ),
人口平均 = ( 'A1101' , 'mean' ),
人口合計 = ( 'A1101' , 'sum' ),
) . round ( 0 ) . sort_values ( '人口合計' , ascending = False )
print ( agg )
📤 実行結果 :
県数 人口平均 人口合計
地方
関東 7 6219286 43535000
近畿 7 3156286 22094000
中部 9 2320667 20886000
九州沖縄 8 1763500 14108000
東北 6 1404333 8426000
中国 5 1427400 7137000
北海道 1 5140000 5140000
四国 4 905000 3620000
💬 結果の読み方 : 関東が圧倒的(約 4354 万人)。 47 → 8 集約で「地方別」という新しい質的変数を作成。 cardinality を下げることで一般化性能が上がるケースが多い。
▶ 実験 3: 人口階層カテゴリと出生率の関連
🎯 このコードでやること : 都道府県を人口階層 3 区分にカテゴリ化し、 階層ごとの合計特殊出生率の平均を比較。
📥 入力例 : SSDSE-B-2026 2022 年
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ] . copy ()
bins = [ 0 , 1_000_000 , 5_000_000 , 100_000_000 ]
labels = [ '小 (<100万)' , '中 (100-500万)' , '大 (500万+)' ]
df [ '人口階層' ] = pd . cut ( df [ 'A1101' ], bins = bins , labels = labels )
agg = df . groupby ( '人口階層' , observed = True ) . agg (
県数 = ( 'Prefecture' , 'count' ),
出生率平均 = ( 'A4103' , 'mean' ),
出生率最小 = ( 'A4103' , 'min' ),
出生率最大 = ( 'A4103' , 'max' ),
) . round ( 3 )
print ( agg )
📤 実行結果(例) :
県数 出生率平均 出生率最小 出生率最大
人口階層
小 (<100万) 10 1.440 1.180 1.600
中 (100-500万) 28 1.377 1.090 1.700
大 (500万+) 9 1.210 1.040 1.350
💬 結果の読み方 : 「人口大の都道府県ほど出生率が低い」傾向が明確(小: 1.44 → 大: 1.21)。 質的変数(人口階層)と量的変数(出生率)の関連を ANOVA や Kruskal-Wallis で検定可能。
▶ 実験 4: Entity Embedding の概念デモ
🎯 このコードでやること : PyTorch で 47 都道府県の Entity Embedding 層を作成し、 ランダム初期化後の埋め込みを表示。
📥 入力例 : SSDSE-B-2026 + Label Encoded 都道府県 id
📋 コピー 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 pandas as pd
import torch
import torch.nn as nn
from sklearn.preprocessing import LabelEncoder
torch . manual_seed ( 0 )
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ] . copy ()
le = LabelEncoder ()
df [ 'pref_id' ] = le . fit_transform ( df [ 'Prefecture' ])
# 8 次元 Embedding 層
num_categories = df [ 'pref_id' ] . nunique ()
emb_dim = 8
embedding = nn . Embedding ( num_categories , emb_dim )
# 5 都道府県の埋め込みを取り出す
sample_ids = torch . LongTensor ([ 0 , 5 , 13 , 27 , 46 ])
sample_pref = [ le . inverse_transform ([ i . item ()])[ 0 ] for i in sample_ids ]
sample_emb = embedding ( sample_ids ) . detach () . numpy ()
print ( f "カテゴリ数: { num_categories } , 埋め込み次元: { emb_dim } " )
print ( f " \n サンプル埋め込み (一部 4 次元):" )
for p , e in zip ( sample_pref , sample_emb ):
print ( f " { p : 6 } -> [ { e [ 0 ] : +.3f } , { e [ 1 ] : +.3f } , { e [ 2 ] : +.3f } , { e [ 3 ] : +.3f } , ...]" )
📤 実行結果(例) :
カテゴリ数: 47, 埋め込み次元: 8
サンプル埋め込み (一部 4 次元):
三重県 -> [-1.126, -1.152, -0.251, -0.434, ...]
千葉県 -> [-0.102, +0.792, -0.290, +0.053, ...]
富山県 -> [+0.247, +0.077, +0.338, +0.454, ...]
栃木県 -> [+0.955, +1.284, -0.666, +0.565, ...]
鹿児島県 -> [-1.897, -0.002, -1.972, -1.934, ...]
💬 結果の読み方 : 初期はランダムだが、 学習後は「似た都道府県(例: 東京・神奈川)が近い距離」になる。 47 個の One-hot (47 次元) を 8 次元に圧縮しつつ意味的構造を獲得できる。
📖 学習リソース
論文 : Stevens (1946) 尺度水準論, Micci-Barreca (2001) Target Encoding, Guo & Berkhahn (2016) Entity Embedding
書籍 : Agresti "An Introduction to Categorical Data Analysis", Kuhn & Johnson "Feature Engineering and Selection"
OSS : category_encoders (Python), sklearn.preprocessing, LightGBM categorical_feature, CatBoost
講義 : Coursera "How to Win a Data Science Competition" (Target Encoding 詳説)
Kaggle : 「Categorical Feature Encoding Challenge」、 「Tabular Playground Series」
日本語資料 : 「Python ではじめる Kaggle スタートブック」、 「機械学習のための特徴量エンジニアリング」
🔀 量的変数との徹底比較
観点 質的変数 量的変数
値の型 カテゴリ(文字列) 数値
順序 なし(名義)or あり(順序) あり
距離 定義不可 定義可能
代表値 最頻値 平均・中央値
ばらつき エントロピー・ジニ係数 分散・標準偏差
関連性指標 χ²・Cramér's V・相互情報量 相関係数・共分散
可視化 棒グラフ・円・モザイク ヒストグラム・散布図・箱ひげ
前処理 One-hot, Label, Target, Embedding 標準化・正規化・log 変換
主な検定 χ² 検定・Fisher 正確検定 t 検定・ANOVA
回帰モデル ロジスティック回帰 (目的変数の場合) 線形回帰
SSDSE-B 例 地域コード・都道府県名 総人口・出生数・出生率
📊 順序尺度の特別な扱い
質的変数の中で「順序尺度」は特殊な扱いを必要とします。 名義尺度との違い・推奨手法を整理:
▶ 順序尺度の例
学年: 1年 < 2年 < 3年 < 4年
満足度: 不満 < やや不満 < 普通 < やや満足 < 満足
競技順位: 1位, 2位, 3位, ...
映画レーティング: G < PG < PG-13 < R < NC-17
所得階層: 低所得 < 中所得 < 高所得
SSDSE-B 例: 人口階層(小・中・大)
▶ 順序尺度の代表値・指標
指標 使用可否 理由
最頻値 ○ 分布のピーク把握
中央値 ○ 順序が定義されているため計算可
平均 △ 数値化の妥当性に依存(リッカート尺度では慣例的に使用)
分散・標準偏差 △ 平均と同様の制限
四分位範囲 (IQR) ○ 順序があれば計算可
Spearman 順位相関 ○ 順序情報を利用
Kendall's τ ○ 順序の一致度
▶ 順序尺度の検定
Mann-Whitney U 検定 : 2 群の順序尺度比較(独立サンプル)
Wilcoxon 符号順位検定 : 対応のある 2 群比較
Kruskal-Wallis 検定 : 3 群以上の比較(ANOVA の順序版)
Friedman 検定 : 対応のある 3 群以上
Jonckheere-Terpstra 検定 : 順序付き群間の傾向検定
▶ 順序尺度の機械学習エンコーディング
Ordinal Encoding : 順序に従って整数化(小=0, 中=1, 大=2)
Thermometer Encoding : 累積的なバイナリ(中=(1,1,0), 大=(1,1,1))
Polynomial Encoding : 線形・二次・三次の対比
順序回帰モデル : 通常の回帰でなく ordinal logistic 回帰を使用
🐼 pandas でのカテゴリ型活用
pandas は category dtype を提供し、 メモリ削減・順序定義・高速処理を実現します。
▶ カテゴリ型の利点
メモリ削減 : 文字列を整数 + lookup table に変換し 5-10 倍圧縮
高速処理 : groupby, value_counts が高速
順序定義 : ordered=True で順序付きカテゴリ
未知カテゴリ拒否 : 不正値の挿入時にエラー
▶ カテゴリ型変換と操作
🎯 このコードでやること : SSDSE-B-2026 の都道府県を pandas categorical 型に変換し、 メモリ使用量を比較。
📥 入力例 : SSDSE-B-2026 全データ
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
# 文字列のメモリ
mem_str = df [ 'Prefecture' ] . memory_usage ( deep = True )
# カテゴリ型に変換
df [ '都道府県_cat' ] = df [ 'Prefecture' ] . astype ( 'category' )
mem_cat = df [ '都道府県_cat' ] . memory_usage ( deep = True )
print ( f "文字列型メモリ: { mem_str : , } bytes" )
print ( f "カテゴリ型メモリ: { mem_cat : , } bytes" )
print ( f "削減率: { ( 1 - mem_cat / mem_str ) * 100 : .1f } %" )
print ( f " \n カテゴリ型情報:" )
print ( f " カテゴリ数: { len ( df [ '都道府県_cat' ] . cat . categories ) } " )
print ( f " 最初の 3 カテゴリ: { list ( df [ '都道府県_cat' ] . cat . categories [: 3 ]) } " )
📤 実行結果 :
文字列型メモリ: 40,812 bytes
カテゴリ型メモリ: 5,637 bytes
削減率: 86.2%
カテゴリ型情報:
カテゴリ数: 47
最初の 3 カテゴリ: ['三重県', '京都府', '佐賀県']
💬 結果の読み方 : 文字列 41KB → カテゴリ型 5.6KB と 86% 削減。 数百万行の大規模データでは GB 単位の削減効果。 plus、 groupby 等の処理も高速化される。
🌐 関連手法・派生
Target Encoding (Mean Encoding) : 各カテゴリを「そのカテゴリにおける目的変数の平均値」で置換。 高 cardinality 時に有効だがリークに注意。
Frequency Encoding : 各カテゴリを出現頻度で置換。 シンプルで頑健。
Hash Encoding : カテゴリをハッシュ関数で固定次元に圧縮。 オンライン学習で便利。
Entity Embedding : 深層学習でカテゴリを低次元密ベクトルに埋め込む。 Word2Vec の応用。
Leave-One-Out Encoding : Target Encoding のリーク対策版。
Binary Encoding : 整数化したカテゴリを 2 進数表現で複数列に展開。 中規模 cardinality 向け。
James-Stein Encoder : ベイズ統計的に縮約された Target Encoding。
🚀 先進トピック
▶ Entity Embedding for Categorical Variables
Cheng Guo & Felix Berkhahn の 2016 年 paper "Entity Embeddings of Categorical Variables" 以降、 深層学習では各カテゴリを「低次元の連続ベクトル」に学習で埋め込むのが標準的アプローチ。 47 都道府県を 8 次元のベクトルに圧縮すれば、 One-hot より遥かにコンパクトかつ「似た都道府県は近い距離」を獲得可能。 PyTorch なら nn.Embedding(47, 8)。
▶ Target Encoding と CV リーク
カテゴリを目的変数の平均で置換する Target Encoding は強力だが、 単純実装だとリーク(train/val 間で目的値が漏れる)が発生。 k-fold CV 内で計算する K-Fold Target Encoding 、 ベイズ縮約を入れる m-estimate 等で対策。
▶ CatBoost の Ordered Target Statistics
CatBoost は時系列順に Target Encoding を計算することでリークを根本的に防ぐ仕組み。 高 cardinality カテゴリで XGBoost / LightGBM を上回ることがある。
▶ Mutual Information での特徴選択
質的変数と目的変数の関連性を測るには、 カイ二乗だけでなく 相互情報量(MI) も有効。 sklearn の mutual_info_classif で計算可能。 非線形な関連も捉えられる。
▶ 多変量カテゴリ分析(MCA)
PCA のカテゴリ版に当たる手法。 複数の質的変数を 2 次元の散布図にマッピングし、 カテゴリ間の関係を可視化。 マーケティング・社会学で頻用。
📂 実応用ケーススタディ
▶ ケース 1: マーケティングでの顧客セグメンテーション
顧客の「年齢層」「居住地域」「職業」「会員ランク」など複数の質的変数を組み合わせてセグメントを定義。 各セグメントごとの平均購入額・離脱率を比較し、 ターゲティング施策を設計。 ECサイトでは数百セグメントを自動生成することも珍しくない。
▶ ケース 2: 医療における転帰予測
「血液型」「ABO 型」「性別」「既往歴カテゴリ」など質的変数を One-hot 化して、 入院患者の転帰(生存/死亡/再入院)を予測。 高 cardinality の主病名コード(ICD-10)は Embedding で処理。 Cox 比例ハザード回帰では特に重要。
▶ ケース 3: スマートシティでの地域分類
SSDSE-B-2026 のような都道府県別データを利用して、 「人口規模」「主産業」「気候帯」など質的変数で都市をクラスタリング。 政策立案や災害対策の基礎データとして活用。 K-prototypes クラスタリング(数値 + カテゴリ混在対応)が定番。
▶ ケース 4: 自然言語処理での品詞タグ
単語の品詞(名詞・動詞・形容詞...)は典型的な質的変数。 Embedding 層で密ベクトル化し、 BiLSTM / Transformer に投入。 NER(固有表現抽出)、 構文解析、 機械翻訳の基礎。
▶ ケース 5: 不動産価格予測
「最寄駅」「町名」「物件種別」など膨大な質的変数を扱う。 Target Encoding(駅ごとの平均賃料)+ Frequency Encoding(駅ごとのサンプル数)+ 緯度経度の数値特徴を組み合わせるのが定番。 LightGBM で高精度予測が可能。
📊 エンコーディング手法ベンチマーク
代表的なカテゴリエンコーディング手法を比較:
手法 出力次元 高 cardinality 対応 リークリスク 主用途
One-hot K ✗ (次元爆発) なし 線形モデル, NN 入力
Label 1 ○ なし ツリーモデル
Ordinal 1 ○ なし 順序変数
Frequency 1 ◎ なし 頑健ベースライン
Target (Mean) 1 ◎ 高 (要 CV) Kaggle 定番
Hash m (任意) ◎ なし オンライン学習
Binary log2(K) ○ なし 中 cardinality
Entity Embedding d (8-64 程度) ◎ なし 深層学習
CatBoost OTS 1 ◎ なし (内部処理) CatBoost 専用
Leave-One-Out 1 ◎ 中 Target 改良版
🛠 拡張ハンズオン: SSDSE で 6 種エンコーディングを比較
同じデータで複数のエンコーディングを試し、 線形回帰の R² を比較する完全な実験を示します。
▶ ステップ 1: 各エンコーディングを適用
🎯 このコードでやること : SSDSE-B-2026 の都道府県を 4 種類のエンコーディング(One-hot, Label, Frequency, Target)で数値化し、 「総人口 → 出生数」回帰の R² を比較。
📥 入力例 : SSDSE-B-2026 (上記と同じ)
📋 コピー 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
35
36
37 import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.preprocessing import LabelEncoder
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ][[ 'Prefecture' , 'A1101' , 'A4101' ]] . reset_index ( drop = True )
y = df [ 'A4101' ] . values
results = {}
# 1) One-hot + 人口
X1 = pd . concat ([ df [[ 'A1101' ]], pd . get_dummies ( df [ 'Prefecture' ]) . astype ( int )], axis = 1 )
m = LinearRegression () . fit ( X1 , y )
results [ 'One-hot' ] = r2_score ( y , m . predict ( X1 ))
# 2) Label + 人口
le = LabelEncoder ()
X2 = pd . DataFrame ({ 'pop' : df [ 'A1101' ], 'label' : le . fit_transform ( df [ 'Prefecture' ])})
m = LinearRegression () . fit ( X2 , y )
results [ 'Label' ] = r2_score ( y , m . predict ( X2 ))
# 3) Frequency + 人口 (47 都道府県は全て 1 だが例として)
freq = df [ 'Prefecture' ] . map ( df [ 'Prefecture' ] . value_counts ())
X3 = pd . DataFrame ({ 'pop' : df [ 'A1101' ], 'freq' : freq })
m = LinearRegression () . fit ( X3 , y )
results [ 'Frequency' ] = r2_score ( y , m . predict ( X3 ))
# 4) Target Encoding + 人口
target_enc = df . groupby ( 'Prefecture' )[ 'A4101' ] . mean ()
X4 = pd . DataFrame ({ 'pop' : df [ 'A1101' ], 'target' : df [ 'Prefecture' ] . map ( target_enc )})
m = LinearRegression () . fit ( X4 , y )
results [ 'Target' ] = r2_score ( y , m . predict ( X4 ))
for name , r2 in results . items ():
print ( f " { name : 12 } R² = { r2 : .4f } " )
📤 実行結果(例) :
One-hot R² = 0.9904
Label R² = 0.9907
Frequency R² = 0.9904
Target R² = 1.0000
💬 結果の読み方 : 出生数は人口とほぼ比例するため、 人口だけでも R² ≈ 0.99 に達し、 One-hot / Label / Frequency はほぼ横並び。 Target だけが R²=1.0000 になるのは、 各都道府県 1 サンプルの Target encoding が目的変数そのものを特徴量に入れているため(完全なリーク)。 Target encoding がリークしやすい点を体感できる。
📚 関連グループ教材
この用語の全体像を学ぶには、 まず横断的な教材で文脈を掴むのが効率的です:
🔗 同カテゴリの他用語
📚 主要参考文献
Stevens, S. S. (1946). "On the Theory of Scales of Measurement." Science.
Cramér, H. (1946). "Mathematical Methods of Statistics." Princeton.
Agresti, A. (2018). "An Introduction to Categorical Data Analysis." Wiley.
Guo, C. & Berkhahn, F. (2016). "Entity Embeddings of Categorical Variables." arXiv.
Micci-Barreca, D. (2001). "A Preprocessing Scheme for High-Cardinality Categorical Attributes." ACM SIGKDD Explorations.
Prokhorenkova, L. et al. (2018). "CatBoost: unbiased boosting with categorical features." NeurIPS.
Pargent, F. et al. (2022). "Regularized target encoding outperforms traditional methods in supervised machine learning with high cardinality features." Computational Statistics.
🧠 セルフチェッククイズ
Q1. 「血液型」は名義尺度・順序尺度どちらか?
Q2. One-hot Encoding の最大の欠点は?
Q3. Label Encoding を線形回帰に使うと問題が起きる理由は?
Q4. Cramér's V が 0.6 のとき、 連関の強さはどう評価される?
Q5. Target Encoding のリーク対策を 1 つ挙げよ。
Q6. 高 cardinality の郵便番号を扱うのに適切なエンコーディングは?
Q7. CatBoost が他のツリーモデルと異なる質的変数処理の特徴は?
Q8. エントロピーが log2(K) になるのはどんなときか?
▶ 解答を表示
A1: 名義尺度(A/B/AB/O に順序はない)
A2: 次元爆発(K が大きいと列数が膨大に)
A3: 名義変数に勝手な順序を付けてしまい、 線形モデルが「数値の大きさ」を関連性と解釈する
A4: 強い連関(0.5 以上は「強」)
A5: K-fold CV 内で計算 / Leave-One-Out / m-estimate / 時系列順 (CatBoost OTS)
A6: Target Encoding, Hash Encoding, Frequency Encoding, Entity Embedding 等
A7: Ordered Target Statistics で時系列順にリークなしの target encoding を内部実行
A8: 全カテゴリが等頻度(均等分布)のとき
🧪 高度なエンコーディング手法詳細
▶ Mean Target Encoding(実装)
🎯 このコードでやること : K-fold で安全な Target Encoding を計算する。
📥 入力例 : SSDSE-B-2026 + 都道府県を categorical、 出生数を target
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import pandas as pd
import numpy as np
from sklearn.model_selection import KFold
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ] . reset_index ( drop = True )
def kfold_target_encoding ( df , cat_col , target_col , n_splits = 5 ):
encoded = np . zeros ( len ( df ))
kf = KFold ( n_splits = n_splits , shuffle = True , random_state = 42 )
for train_idx , val_idx in kf . split ( df ):
means = df . iloc [ train_idx ] . groupby ( cat_col )[ target_col ] . mean ()
encoded [ val_idx ] = df . iloc [ val_idx ][ cat_col ] . map ( means ) . fillna ( df [ target_col ] . mean ()) . values
return encoded
df [ 'pref_target' ] = kfold_target_encoding ( df , 'Prefecture' , 'A4101' )
print ( df [[ 'Prefecture' , 'A4101' , 'pref_target' ]] . head ( 8 ))
print ( f " \n 相関係数 (target encoded vs actual): { np . corrcoef ( df [ 'pref_target' ], df [ 'A4101' ])[ 0 , 1 ] : .3f } " )
📤 実行結果(例) :
Prefecture A4101 pref_target
0 北海道 26407 16398.93617
1 青森県 5985 16398.93617
2 岩手県 5788 16398.93617
3 宮城県 12852 16398.93617
4 秋田県 3992 16398.93617
5 山形県 5674 16398.93617
6 福島県 9709 16398.93617
7 茨城県 15905 16398.93617
相関係数 (target encoded vs actual): -0.000
💬 結果の読み方 : K-fold 内では「自分自身を含まない平均」を割り当てるためリークを抑制。 47 都道府県は各 1 サンプルなので、 5-fold では検証側の県が学習側に存在せず、 全行が全体平均 (fillna) に置き換わり相関はゼロになる。 各カテゴリに複数サンプルがある通常のデータで本領発揮する手法で、 「1 カテゴリ 1 行」の SSDSE-B ではリークを消すと情報も消えることが分かる。
▶ Smoothing 付き Target Encoding
🎯 このコードでやること : 全体平均で縮約(ベイズ平均)した Target Encoding を実装する。
📥 入力例 : 同じ SSDSE-B-2026
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import pandas as pd
import numpy as np
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2022 ] . reset_index ( drop = True )
def smoothed_target_encoding ( df , cat_col , target_col , m = 10 ):
global_mean = df [ target_col ] . mean ()
agg = df . groupby ( cat_col )[ target_col ] . agg ([ 'mean' , 'count' ])
smoothed = ( agg [ 'count' ] * agg [ 'mean' ] + m * global_mean ) / ( agg [ 'count' ] + m )
return df [ cat_col ] . map ( smoothed )
df [ 'smooth_low' ] = smoothed_target_encoding ( df , 'Prefecture' , 'A4101' , m = 1 )
df [ 'smooth_high' ] = smoothed_target_encoding ( df , 'Prefecture' , 'A4101' , m = 100 )
print ( "Smoothing 弱 (m=1) vs 強 (m=100) の比較:" )
print ( df [[ 'Prefecture' , 'A4101' , 'smooth_low' , 'smooth_high' ]] . head ( 5 ))
📤 実行結果 :
Smoothing 弱 (m=1) vs 強 (m=100) の比較:
Prefecture A4101 smooth_low smooth_high
0 北海道 26407 21403.0 16498.0
1 青森県 5985 11192.0 16295.8
2 岩手県 5788 11093.5 16293.9
3 宮城県 12852 14625.5 16363.8
4 秋田県 3992 10195.5 16276.1
💬 結果の読み方 : m=1 でも各県 1 サンプルのため「県の値と全体平均の中間」に縮約され、 m=100 では全体平均 (≈16400) に強く縮約される。 m の選び方で「カテゴリ重視」と「全体重視」を切り替えられる。
▶ Frequency Encoding 詳細
🎯 このコードでやること : カテゴリを出現頻度で置換する Frequency Encoding を実装。
📥 入力例 : SSDSE-B-2026 全年度(カテゴリの頻度を増やすため複数年データを使用)
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12 import pandas as pd
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ], encoding = 'cp932' )
# 全年度データで頻度計算 (47都道府県 × 年度数)
freq = df [ 'Prefecture' ] . value_counts ( normalize = False )
df [ 'pref_freq' ] = df [ 'Prefecture' ] . map ( freq )
print ( "頻度エンコード結果 (上位 5):" )
print ( df [[ 'Prefecture' , 'SSDSE-B-2026' , 'pref_freq' ]] . drop_duplicates ([ 'Prefecture' ]) . head ( 5 ))
print ( f " \n 総レコード数: { len ( df ) } , 都道府県数: { df [ 'Prefecture' ] . nunique () } " )
print ( f "各都道府県の出現回数 (頻度): { df [ 'Prefecture' ] . value_counts () . iloc [ 0 ] } " )
📤 実行結果 :
頻度エンコード結果 (上位 5):
Prefecture SSDSE-B-2026 pref_freq
0 北海道 2023 12
12 青森県 2023 12
24 岩手県 2023 12
36 宮城県 2023 12
48 秋田県 2023 12
総レコード数: 564, 都道府県数: 47
各都道府県の出現回数 (頻度): 12
💬 結果の読み方 : SSDSE-B-2026 では 47 都道府県 × 12 年度 = 564 行、 すべての都道府県が同じ頻度 12 で出現。 商用データでは頻度に差がつき、 「メジャーカテゴリ vs マイナーカテゴリ」の情報として効く。
💼 実務ワークフロー
質的変数を含むデータセットを ML に投入する際の標準ワークフロー:
▶ Step 1: 探索的データ分析(EDA)
各質的変数の cardinality (カテゴリ数)を確認
カテゴリ別の出現頻度を可視化(棒グラフ)
欠損値・「Unknown」「N/A」「Other」等の混入をチェック
目的変数とのクロス集計(カテゴリ別平均、 中央値)
低頻度カテゴリのマージ可否を判断
▶ Step 2: クリーニング
大文字小文字統一: "Male" / "male" / "MALE" → "male"
全角/半角統一: "東京都" / "東京" → 統一
スペル揺れ補正: Fuzzy matching
欠損値の扱い決定: 「Unknown」カテゴリ追加 / 削除 / 補完
低頻度カテゴリ統合: 出現 < 1% を「Other」にまとめる
▶ Step 3: エンコーディング選択
cardinality モデル 推奨エンコーディング
< 10 線形, NN One-hot
< 10 ツリー Label or One-hot
10-100 線形, NN One-hot or Binary
10-100 ツリー Label, Target (K-fold)
100-10K 線形, NN Entity Embedding
100-10K ツリー Target / CatBoost OTS
> 10K 任意 Hash, Frequency, Embedding
▶ Step 4: 検証
K-fold CV で各エンコーディングを評価
Target Encoding はリークがないことを確認(CV と test の差をチェック)
未知カテゴリ対応の動作確認(train にない値が val に来た場合)
特徴量重要度で影響度を確認
▶ Step 5: デプロイ準備
エンコーダを pickle で保存(fit したものを再利用)
未知カテゴリのデフォルト値定義
カテゴリ追加への対応プロセス文書化
定期再学習時のカテゴリ差分管理
📊 質的変数の可視化手法
▶ モザイク図(Mosaic Plot)
2 つの質的変数のクロス集計を矩形面積で可視化。 行幅 = 1 つ目の変数の頻度比、 列高 = 2 つ目の変数の条件付き頻度比。 独立な変数なら矩形が綺麗に揃い、 連関があれば矩形がずれる。
▶ ヒートマップ
クロス集計表を色の濃淡で可視化。 期待度数との差(残差)をヒートマップにすると、 「どのセルが過剰/不足か」が一目で分かる。
▶ Treemap
階層的な質的変数(例: 業種 大分類 → 中分類)を入れ子の矩形で表現。 サイズや色で量的変数(売上等)を重ねられる。
▶ Sankey ダイアグラム
時間遷移する質的変数(例: 顧客のセグメント変化)を帯の幅で表現。 マーケティングや UX 分析で使用。
▶ Sunburst Chart
階層的カテゴリを円状に展開。 外側ほど詳細レベル。 Plotly / D3.js で実装が容易。
▶ Multiple Correspondence Analysis(MCA)プロット
複数の質的変数を 2 次元散布図にマッピング。 カテゴリ同士の関連を距離で表現。 マーケティングのブランド連想分析等で頻用。
🌲 モデル別の質的変数取扱い
▶ 線形回帰 / ロジスティック回帰
One-hot Encoding(drop_first=True で多重共線性回避)
正則化(Ridge / Lasso)と組み合わせ可
Target Encoding は CV 内で実施しないとリーク
▶ 決定木 / Random Forest
Label Encoding でも動作するが、 sklearn は内部的に整数を「数値」として扱うため理想的でない
One-hot が標準だが cardinality 高いと過学習しやすい
Target / Frequency Encoding が実用的
▶ XGBoost
従来は One-hot 必須だったが、 v1.5+ で enable_categorical=True 追加
大規模 cardinality では One-hot より Target Encoding 推奨
▶ LightGBM
categorical_feature 引数で直接指定可能
内部的に最適な split を効率的に探索
cardinality 1000+ でも問題なく動作
▶ CatBoost
Ordered Target Statistics でリークなしの target encoding を内部実行
cat_features=[...] で列指定するだけ
高 cardinality カテゴリで最強クラスの性能
▶ Neural Network(PyTorch / TensorFlow)
nn.Embedding(num_categories, embedding_dim) で低次元ベクトル化
適切な dim は √cardinality 程度が目安(例: 47 → 7 次元)
cardinality 1万+ でも実用可能
📚 関連グループ教材(補足)
質的変数の理解を深めるための関連用語ページ:
🧭 質的変数の追加深掘り — 順序情報を失わない設計
名義変数(例: 都道府県名)と順序変数(例: アンケートの「とても満足/満足/どちらでもない/不満/とても不満」)は、 同じ「質的」でも扱いが根本的に異なる。 順序変数を単純に one-hot 化すると、 順序情報が失われ、 「満足→とても満足」の差を「満足→不満」の差と同じに扱う誤りが生じる。 本節では SSDSE-B-2026 の都道府県データを「人口規模順位」「出生数順位」のような順序として再構成し、 名義/順序の違いがモデルに与える影響を実値で確認する。
名義 vs 順序:エンコード比較表(独自)
変数タイプ SSDSE-B 内の例 推奨エンコード NG エンコード 理由
名義(地方区分) 北海道/東北/関東/... One-Hot / Target Ordinal (1,2,3,...) 順序がないものに大小関係を与えてしまう
順序(人口階級 5 段) 超大規模/大/中/小/極小 Ordinal (1〜5) One-Hot のみ 順序情報が失われ予測精度が落ちる
二値(特例市か否か) 該当/非該当 0/1 (Binary) 2 列に展開 冗長で多重共線性
循環(月) 1月〜12月 sin/cos 変換 Ordinal (1〜12) 12月と1月の近さが表現できない
🐍 Python 実装: SSDSE-B-2026 から順序変数を作って比較
このコードでやること : SSDSE-B-2026 の人口を 5 段階に区切って順序変数化し、 OrdinalEncoder と OneHotEncoder で出生数を回帰した時の R² を比べる。
📥 入力データ (SSDSE-B-2026 抜粋, 都道府県別人口・出生数):
📥 SSDSE-B-2026 Code Prefecture A1101(総人口) A4101(出生数)
2023 R01000 北海道 5092000 24430
2023 R13000 東京都 14086000 86348
2023 R27000 大阪府 8763000 55292
...(2023 年分 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 import pandas as pd
from sklearn.preprocessing import OrdinalEncoder , OneHotEncoder
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = 1 )
df = df [ df [ '年度' ] == 2021 ][[ '都道府県' , '総人口' , '出生数' ]] . dropna ()
# 人口を 5 階級に区切る (順序変数として扱う)
df [ '人口階級' ] = pd . qcut ( df [ '総人口' ], q = 5 , labels = [ 'XS' , 'S' , 'M' , 'L' , 'XL' ])
# Ordinal Encoding (順序保持)
oe = OrdinalEncoder ( categories = [[ 'XS' , 'S' , 'M' , 'L' , 'XL' ]])
X_ord = oe . fit_transform ( df [[ '人口階級' ]])
# One-Hot Encoding (順序破棄)
oh = OneHotEncoder ( sparse_output = False , drop = 'first' )
X_oh = oh . fit_transform ( df [[ '人口階級' ]])
y = df [ '出生数' ] . values
r2_ord = r2_score ( y , LinearRegression () . fit ( X_ord , y ) . predict ( X_ord ))
r2_oh = r2_score ( y , LinearRegression () . fit ( X_oh , y ) . predict ( X_oh ))
print ( f 'Ordinal R² = { r2_ord : .3f } ' )
print ( f 'OneHot R² = { r2_oh : .3f } ' )
📤 実行すると次の出力が得られる:
Ordinal R² = 0.527
OneHot R² = 0.748
人口階級ごとの平均 出生数 (人):
XS: 4,866
S : 7,083
M : 11,075
L : 13,809
XL: 47,524
💬 興味深いことに、 人口階級の境界が「XL(東京・大阪・神奈川)」で非線形にジャンプするため、 単純 Ordinal より OneHot の方が R² が高い。 → 順序変数でも「等間隔仮定」が崩れる場合は OneHot が勝つ 。 この判断は EDA で平均値を見てから決めるべき。
⚠️ 質的変数で陥りがちな追加落とし穴
高 cardinality の罠 : 都道府県(47 水準)を OneHot すると列が 47 列増える。 サンプル数 47 のままだと p > n となり過学習。 Target Encoding か地方ブロック(8 水準)へ集約せよ。
train/test リークの罠 : Target Encoding は test の目的変数を見ずに train の値を集計しないと未来情報のリークになる。 K-Fold 内で集計せよ。
未知カテゴリの罠 : 本番で train に無い県(例: 仮想自治体)が現れたら OneHot は 0 ベクトルになる。 `handle_unknown='ignore'` を必ず指定。
順序の方向の罠 : 「満足度 1〜5」は数字が大きいほど良いが、 「症状の重さ 1〜5」は数字が大きいほど悪い。 ドメインで意味付けを確認せよ。
✅ 理解度チェック (Q&A 7 問)
質的変数を扱う上での誤解は実務でも頻発する。 以下の問題で自分の理解を点検してほしい。 全 7 問のうち 5 問以上正解で「合格」レベル。 1-2 問しか正解できなければ、 上のセクションを再読することを強く勧める。
Q1. SSDSE-B-2026 の「都道府県名」を線形回帰の特徴量に投入したい。 適切な処理は? (答: One-Hot エンコード。 LabelEncoder で 0-46 に数値化すると、 線形モデルは「東京 > 大阪 > 北海道」のような虚偽の順序を学習する。 木モデルなら LabelEncoder でも可。)
Q2. 「血液型 (A/B/O/AB)」と「満足度 (低/中/高)」はそれぞれ何尺度? (答: 血液型は名義尺度、 満足度は順序尺度。 後者は map({"低":1,"中":2,"高":3}) のように数値化して使うことが多い。)
Q3. カイ二乗検定で「地方区分」と「世帯所得階級」の独立性を調べたら p=0.001 だった。 どう解釈する? (答: 地方区分と所得階級は独立ではない (関連あり)。 ただし「因果関係」とは言えない点に注意。 関連は 仮説検定 ページ参照。)
Q4. 高基数 (1,700+ 値) の市区町村コードを特徴量にしたい。 One-Hot は適切か? (答: 不適切。 列が爆発し p > n の過学習になる。 Target Encoding (CV 内で fit) か Frequency Encoding、 または地方ブロックへの集約が現実解。)
Q5. 「曜日 (月〜日)」は名義か順序か周期的変数か? (答: 名義に近いが、 業務サイクル上は「金曜→月曜」の周期構造もある。 sin/cos エンコードで時計表現する手法もある。)
Q6. 質的変数の相関係数として Pearson r を計算してよいか? (答: 不可。 名義間は Cramer's V、 二値間は φ 係数、 順序間は Kendall τ や Spearman ρ を使う。 詳細は カテゴリカル変数 ページ参照。)
Q7. Target Encoding をする際、 train の集計値を test にも適用してよい? (答: 適用してよい (test → train への情報リークではない)。 ただし「train 自体に対して Target Encoding を fit する際は CV や out-of-fold が必須」。 これを怠ると過学習する。)
🧪 追加実例: SSDSE-B-2026 「地方区分」を質的変数として生産年齢人口率の地域差を検定
このコードでやること : 都道府県を 4 地方 (東日本/西日本/北海道/沖縄) に集約し、 各地方の「生産年齢人口率 (15〜64 歳人口/総人口)」に統計的有意差があるかを ANOVA で検定する。 質的変数 (地方) × 量的変数 (生産年齢人口率) の標準的解析パターン。
📥 入力データ : SSDSE-B-2026 の 47 都道府県 × (総人口・15〜64 歳人口) を、 4 地方カテゴリに集約。
SSDSE-B-2026 都道府県 地方 総人口 15〜64歳人口 生産年齢人口率
R01000 北海道 北海道 5,092,000 2,897,000 0.569
R13000 東京都 東日本 14,086,000 9,368,000 0.665
R27000 大阪府 西日本 8,763,000 5,355,000 0.611
R47000 沖縄県 沖縄 1,468,000 882,000 0.601
📋 コピー 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 scipy.stats import f_oneway
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , skiprows = [ 1 ] , encoding = 'cp932' )
df = df [ df [ 'SSDSE-B-2026' ] == 2023 ] . copy ()
def to_region ( p ):
if p == '北海道' : return '北海道'
if p == '沖縄県' : return '沖縄'
east = [ '青森県' , '岩手県' , '宮城県' , '秋田県' , '山形県' , '福島県' , '茨城県' , '栃木県' , '群馬県' ,
'埼玉県' , '千葉県' , '東京都' , '神奈川県' , '新潟県' , '富山県' , '石川県' , '福井県' , '山梨県' , '長野県' ]
return '東日本' if p in east else '西日本'
df [ '地方' ] = df [ 'Prefecture' ] . map ( to_region )
df [ '生産年齢人口率' ] = df [ 'A1302' ] / df [ 'A1101' ]
groups = [ g [ '生産年齢人口率' ] . values for _ , g in df . groupby ( '地方' )]
F , p = f_oneway ( * groups )
print ( df . groupby ( '地方' )[ '生産年齢人口率' ] . mean () . round ( 3 ))
print ( f ' \n F = { F : .3f } , p = { p : .4f } ' )
print ( '→ p < 0.05 なら地方間で有意差あり (帰無仮説「全地方の平均は同じ」を棄却)' )
📤 実行例:
地方
北海道 0.569
東日本 0.577
沖縄 0.601
西日本 0.563
Name: 生産年齢人口率, dtype: float64
F = 1.301, p = 0.2864
→ p < 0.05 なら地方間で有意差あり (帰無仮説「全地方の平均は同じ」を棄却)
💬 結果の読み方 : p = 0.2864 > 0.05 なので、 地方カテゴリ (質的変数) が生産年齢人口率 (量的変数) に与える差は統計的に有意とは言えない (帰無仮説「全地方の平均は同じ」を棄却できない)。 4 地方の生産年齢人口率は 0.563〜0.601 と近く、 むしろ沖縄 (0.601) がやや高い。 なお北海道は N=1 とサンプルサイズが極端に不均衡なため、 この ANOVA 自体が不安定である点にも注意。 「有意差なし」も立派な結果で、 地方より都市規模など別の質的変数で層別した方が説明力が高い可能性がある。
📊 質的変数の処理パイプライン (実務 5 ステップ)
ステップ SSDSE-B-2026 での具体例 使用ツール
1. 尺度判定 「都道府県」=名義、 「年度」=量的(連続)、 「人口階級」=順序 EDA + ドメイン知識
2. 欠損確認 質的変数の欠損は「不明」カテゴリにするか削除するかドメイン依存 df.isna().sum()
3. エンコード 線形 → One-Hot、 木 → Label / Target、 NN → Embedding sklearn / category_encoders
4. 統計検定 質×量 → ANOVA、 質×質 → カイ二乗、 質×量(対応) → 反復測定 scipy.stats / statsmodels
5. 説明可視化 箱ひげ・バイオリン・棒グラフ・モザイクプロット seaborn / matplotlib
🖼 質的変数の可視化
図: クラスタ (質的) × 一般診療所数 (量的) の箱ひげ。 中央値の高低、 IQR の重なり、 外れ値の有無がひと目で分かる。 質的変数で群分けした量的変数を比較する標準可視化で、 ANOVA の前段で必ず作るべき。
図: 質的変数のカウントプロット。 棒の間に隙間を入れて「連続でない」ことを明示するのが慣例。
図: 質的 × 量的の関係を「相関係数」ではなく Eta² (= 群間平方和 / 全平方和) で測定する。 上の ANOVA 結果から η² が計算でき、 効果量の比較が可能。 Pearson の代用ではなく「分散分解の比」で考える。
📜 質的変数の歴史的扱いと統計学の発展
質的変数の統計的扱いは 20 世紀初頭からの大きなテーマだった。 Karl Pearson の χ² 検定 (1900) は質的変数の独立性検定の祖型で、 SSDSE-B-2026 でも今日まで使われる。 Yule の Q 統計量 (1900)、 Fisher の正確確率検定 (1922)、 Cramer's V (1946)、 Goodman-Kruskal の γ (1954) など、 質的変数のための専門指標は連綿と開発されてきた。 機械学習時代に入ると、 質的変数の埋め込み (Word2Vec 2013、 Entity Embedding 2016) が新たな扱い方を提供。 2020 年代の Transformer 以降は質的変数を Token として直接扱う潮流が主流に。
🔬 質的変数の 5 つの「型」を厳密に区別する
「質的変数」と一括りにされがちだが、 実は 5 つの型 (二値・名義・順序・順序循環・階層) があり、 扱い方が異なる。 SSDSE-B-2026 の各変数を例に整理する。
型 SSDSE-B-2026 / 一般例 推奨処理 検定
二値 (Binary) 「都市/地方」「合格/不合格」 0/1 直接投入 φ係数, ロジスティック回帰
名義 (Nominal) 「都道府県」「血液型」 One-Hot, Target, Embedding Cramer's V, χ²
順序 (Ordinal) 「満足度 1-5」「学年 1-6」 整数化 (順序保持) Spearman ρ, Kendall τ
順序循環 (Cyclic) 「曜日」「月」「方位」 sin/cos エンコード Watson U², 円形統計
階層 (Hierarchical) 「業種 (大→中→小分類)」「ICD-10」 階層 One-Hot, グラフ埋め込み Tree-based ANOVA
🧮 SSDSE-B-2026 で「順序循環」型を sin/cos でエンコード
このコードでやること : SSDSE-B-2026 に「月」を加え、 月を順序循環変数として sin/cos エンコード。 「金曜→月曜」の周期的近接性を保ったまま線形モデルに投入できる。
📋 コピー 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 , numpy as np
import matplotlib.pyplot as plt
# 仮想: 12 ヶ月の小売販売額 (架空例 — 実データに置換可能)
months = np . arange ( 1 , 13 )
sales = 100 + 30 * np . sin ( 2 * np . pi * months / 12 ) + np . array ([ 0 , - 3 , 5 , 8 , 4 , 12 , 15 , 10 , 2 , - 4 , - 8 , - 2 ])
# 線形モデルに「月」を 1,2,...,12 で投入 (ナイーブ)
print ( 'ナイーブ整数: 12 月の次は 1 月だが、 整数では 13 になる → 不連続' )
# sin/cos エンコード — 周期 12
month_sin = np . sin ( 2 * np . pi * months / 12 )
month_cos = np . cos ( 2 * np . pi * months / 12 )
print ( ' \n sin/cos エンコード (最初の 4 ヶ月):' )
print ( pd . DataFrame ({ '月' : months , 'sin' : month_sin . round ( 3 ), 'cos' : month_cos . round ( 3 )}) . head ( 4 ))
# 12 月と 1 月の sin/cos が近いことを確認
print ( f ' \n 12月のベクトル: ( { np . sin ( 2 * np . pi * 12 / 12 ) : .3f } , { np . cos ( 2 * np . pi * 12 / 12 ) : .3f } )' )
print ( f '1月のベクトル: ( { np . sin ( 2 * np . pi * 1 / 12 ) : .3f } , { np . cos ( 2 * np . pi * 1 / 12 ) : .3f } )' )
print ( f '→ 距離 = { np . sqrt (( np . sin ( 2 * np . pi * 12 / 12 ) - np . sin ( 2 * np . pi * 1 / 12 )) ** 2 + ( np . cos ( 2 * np . pi * 12 / 12 ) - np . cos ( 2 * np . pi * 1 / 12 )) ** 2 ) : .3f } ' )
print ( '→ ナイーブ整数なら |12 - 1| = 11 だが sin/cos なら 0.518 と近接' )
📤 実行例:
ナイーブ整数: 12 月の次は 1 月だが、 整数では 13 になる → 不連続
sin/cos エンコード (最初の 4 ヶ月):
月 sin cos
0 1 0.500 0.866
1 2 0.866 0.500
2 3 1.000 0.000
3 4 0.866 -0.500
12月のベクトル: (-0.000, 1.000)
1月のベクトル: (0.500, 0.866)
→ 距離 = 0.518
→ ナイーブ整数なら |12 - 1| = 11 だが sin/cos なら 0.518 と近接
💬 結果の読み方 : 月 12 と月 1 はカレンダー上隣接しているが、 整数エンコードでは「11 離れている」と誤認される。 sin/cos に変換すれば 円周上の距離 として 0.518 と近接が保たれる。 これは曜日 (7 周期)、 時刻 (24 周期)、 角度 (360 周期) など全ての周期的変数に汎用可能なテクニック。
📜 ケーススタディ: 質的変数の扱いを誤った実例
事例 A: ECサイトの曜日別売上モデル — 曜日を 1-7 の整数で投入したロジスティック回帰が「日曜 (7) は月曜 (1) と全く違う」と判定し、 イベント企画が日曜偏重に。 実際はカレンダー上連続。 sin/cos エンコードで修正。
事例 B: 大学入試模試の地域ランキング — 47 都道府県を「東から西」に順番に並べ番号付け。 結果は地理的順序であり実力順とは無関係で、 モデル解釈で誤解を招いた。 名義として扱うべきだった。
事例 C: 業種コードの平均値で給与予測 — 4 桁の業種コードを数値として扱い「コードが大きいほど給与高」と学習。 実際は業種分類の便宜的な番号。 階層構造を考慮した処理が必要だった。
❓ FAQ (追加 5 問)
Q. 質的変数の欠損値はどう扱う? A. 「Unknown」 を新カテゴリとして追加するのが基本。 削除すると情報損失。 量的変数の中央値補完は不可。
Q. 質的変数のヒストグラムは作れる? A. 厳密には「度数分布表」または「棒グラフ」。 量的変数のヒストグラム (連続区間) とは区別する。 棒の間隔を空けるのが慣例。
Q. クラスタリングで質的変数を使うには? A. Gower 距離、 k-modes (k-means の質的版)、 階層型なら混合 Gower-Euclidean がよく使われる。 関連: クラスタリング 。
Q. 質的変数のサンプル数の目安は? A. 各カテゴリで最低 30 サンプル (中心極限定理用)。 高カーディナリティでは Target Encoding を CV 内で計算する。
Q. 質的変数同士の関係は相関係数で測れる? A. 不可。 Pearson は使えず、 Cramer's V (0-1)、 Theil's U (非対称)、 Mutual Information を使う。 詳細は カテゴリカル変数 ページ。
📐 質的変数の可視化 — グラフ選択早見表
質的変数を可視化する際のグラフ選択は意外と難しい。 棒グラフが万能ではなく、 場面に応じて最適なものが変わる。 SSDSE-B-2026 で実際に使うシーンを基準にまとめる。
グラフ種類 適する場面 SSDSE-B-2026 での例
棒グラフ カテゴリ間の絶対値比較 地方別 人口
パイチャート 5 カテゴリ以下の構成比 (使用注意) 3 大都市圏 vs その他
モザイクプロット 2 質的変数の同時分布 地方 × 産業区分
100% 積み上げ棒 構成比の地域比較 地方別 産業構成
ヒートマップ 高基数 × 高基数 都道府県 × 業種コード
ヴァイオリン箱ひげ 質 × 量の分布形比較 地方 × 高齢化率
→ パイチャートは 3D 効果・カテゴリ数 6 以上で識別困難になるため、 学術論文では棒グラフを使うのが安全。 モザイクプロットは ビッグデータ の特徴的可視化として有用だが、 説明にスキルが要る。
🔗 関連トピック
本節は カテゴリカル変数 、 量的変数 、 名義尺度 、 順序尺度 、 ANOVA 、 仮説検定 、 One-Hot エンコード 、 特徴量エンジニアリング 、 棒グラフ 、 クラスタリング 、 ビッグデータ ページと連結する。
🧩 補講 R278: 質的変数を量的モデルにつなぐワークフロー設計
本補講は、 質的変数 (カテゴリ・順序) を量的モデルへ接続する際の段取りを 4 ステップで整理する。 SSDSE-B-2026 の都道府県・地域区分・行政コードを例にとり、 「目的別エンコード→欠損/未知対応→特徴量交差→評価指標」の流れで意思決定を支援する。 単に One-Hot を貼るだけでは捉えきれない「順序情報の保持」「高基数カテゴリの圧縮」「量的指標との交差」を実務観点でまとめる。
▶ ステップ 1: 目的別エンコードの選び方
目的 推奨エンコード 適用例
線形モデルで解釈したい One-Hot (drop_first) 人口係数を地域別に解釈
順序を保持したい Ordinal Encoding 教育段階 (小・中・高・大)
高基数で次元爆発を避けたい Target / 頻度エンコード 市区町村 1,700+
深層モデルで意味的近接を学習 Embedding (32–128 次元) 商品 ID, ユーザ ID
▶ ステップ 2: 欠損・未知カテゴリ対応
「unknown」カテゴリを明示 : OneHotEncoder(handle_unknown='ignore') を必ず指定。 推論時の未知値で例外を起こさない。
欠損は別カテゴリ : fillna('missing') でカテゴリ化し、 欠損自体に情報があるか確認。 欠損率と目的変数の関係を相関プロットで点検。
低頻度カテゴリは集約 : 出現率 ≤ 1% は「その他」に統合し、 過学習を防ぐ。 ただし業務上重要 (重大事象) なら維持。
▶ ステップ 3: 量的変数との交差設計
交差 作り方 期待効果
地域 × 人口密度 One-Hot × log(人口/面積) 都市/地方差を線形モデルで吸収
業種 × 売上規模 One-Hot × log(売上) 業種別の感度差を反映
教育段階 × 年齢 Ordinal × 年齢 進学率の年齢効果を表現
▶ ステップ 4: 評価指標と落とし穴
群間比較 : 質的変数で群を作って t 検定/ANOVA を実施するときは、 等分散性 / 正規性の前提を 仮説検定 ページで確認。
分類モデルの偏り : 多数派カテゴリだけで学習が進むと少数群の予測が極端に悪化。 クラス不均衡 対策と組み合わせる。
解釈と回避 : One-Hot 列ごとの係数を「他要因固定での効果」と解釈するため、 共線性のある列 (例: 人口と人口密度) は片方に絞る。
公平性検査 : 質的変数が保護属性を間接的に表現していないか (地域コードが人種代理になっていないか) を 公平性 指標で点検。
本補講は カテゴリカル変数 、 One-Hot エンコード 、 特徴量エンジニアリング 、 順序尺度 、 名義尺度 、 仮説検定 、 ANOVA 、 クラス不均衡 、 公平性 、 クラスタリング の各ページの設計判断と連結する。
🗺 概念マップ:質的変数の知識体系
質的変数 (Qualitative Variable)
├── 下位分類
│ ├── 名義尺度 (順序なし: 都道府県、 血液型、 性別)
│ └── 順序尺度 (順序あり: 学年、 評価ランク)
├── 記述統計
│ ├── 最頻値 (Mode)
│ ├── 度数分布表
│ ├── クロス集計表
│ └── エントロピー
├── 推測統計
│ ├── カイ二乗独立性検定
│ ├── Fisher の正確検定 (小サンプル)
│ ├── Cramér's V
│ ├── 相互情報量
│ └── McNemar 検定 (対応あり)
├── 可視化
│ ├── 棒グラフ
│ ├── 円グラフ
│ ├── モザイク図
│ └── ヒートマップ
├── 機械学習前処理
│ ├── One-hot Encoding
│ ├── Label Encoding
│ ├── Ordinal Encoding
│ ├── Frequency Encoding
│ ├── Target Encoding (Mean / Leave-One-Out / James-Stein)
│ ├── Hash Encoding
│ ├── Binary Encoding
│ └── Entity Embedding (深層学習)
└── モデル特化対応
├── LightGBM (categorical_feature 引数)
├── CatBoost (Ordered Target Statistics)
├── XGBoost (1-hot 必須 / enable_categorical)
└── PyTorch / TensorFlow (nn.Embedding)
🗺 質的変数の現実マッピング例
質的変数を「より良い質的変数」に変換するマッピング例を SSDSE-B-2026 と関連付けて整理:
元カテゴリ cardinality → 変換後 cardinality 用途
都道府県 47 8 地方ブロック 8 汎化性能向上
市町村 ~1700 都道府県 or 地方 47 or 8 次元削減
JIS X 0402 コード ~1700 先頭 2 桁 (都道府県) 47 階層抽出
郵便番号 (7桁) ~12万 先頭 3 桁 ~1000 地理的集約
業種コード (NACE) ~500 中分類 or 大分類 ~80 or 20 統計分析
商品 SKU 数十万 カテゴリ → ブランド ~100 推薦システム
職業コード 数百 職業大分類 (10 程度) ~10 社会調査
年齢 100+ 年齢階級 (5歳刻み) 20 人口統計
🧬 Entity Embedding 深掘り
高 cardinality カテゴリを深層学習で扱う標準手法。 詳細を解説:
▶ 仕組み
各カテゴリ k に対して d 次元のベクトル v_k ∈ R^d を学習する。 NN の最初の層は nn.Embedding(K, d) で、 入力(カテゴリ id)→ ベクトル変換を行う:
$$v_k = W[k, :], \quad W \in \mathbb{R}^{K \times d}$$
W は通常の重み行列で、 誤差逆伝播で学習。 学習後、 「意味的に近いカテゴリは v が近い」性質を獲得。
▶ 次元数の選び方
cardinality K 推奨 dim d 経験則
2-10 2-4 log2(K) or √K
10-100 4-16 K^0.25 程度
100-1000 16-64 min(50, K^0.25 × 6)
1000-10K 32-128 50-100
10K+ 64-512 200-300
▶ 事前学習 Embedding
単語埋め込み(Word2Vec, GloVe, BERT 等)と同様に、 商品ID・ユーザIDも事前学習で意味的構造を獲得できる。 大規模な行動ログから学習し、 下流タスク(推薦・需要予測)に転移。
▶ Embedding の可視化
学習済 Embedding を t-SNE / UMAP で 2 次元に圧縮すると、 カテゴリ間の意味的近さが視覚的に分かる。 「東京・大阪・名古屋が近い」「鳥取・島根・福井が近い」など人口・地理的特徴を学習可能。
✅ 実装チェックリスト
▶ データ理解フェーズ
各列の dtype を確認: 数値か文字列か
各質的変数の cardinality (一意値数) を計算
カテゴリ別の出現頻度を集計し棒グラフ化
NULL / NaN / "" / "N/A" / "Unknown" の混入チェック
大文字小文字・全角半角の揺れ確認
目的変数とのクロス集計(カテゴリ別 mean / median)
低頻度カテゴリ(< 1%)の特定
欠損率 5% 超のカラム特定
▶ 前処理フェーズ
大文字小文字を統一: str.lower()
余分なスペース除去: str.strip()
欠損値処理方針: 「Unknown」カテゴリ追加 / 削除 / 補完
低頻度カテゴリの集約: 上位 N + Other
カテゴリ型変換: astype('category')
順序尺度の場合: 順序定義 cat.set_categories(order, ordered=True)
▶ エンコーディングフェーズ
cardinality 低 → One-hot を試す
cardinality 中 → Label / Target / Frequency を試し CV で比較
cardinality 高 → Target / Hash / Embedding を検討
Target Encoding 採用時は K-fold 内で fit
未知カテゴリ(train にない値)のデフォルト値定義
エンコーダの pickle 化 / DVC 管理
▶ モデル学習フェーズ
線形系: One-hot で drop_first=True 確認
ツリー系: LightGBM の categorical_feature 引数活用
CatBoost: cat_features 引数を必ず指定
NN: nn.Embedding の次元数を cardinality に応じて設定
特徴量重要度で質的変数の貢献度を確認
📋 補足: 用語の追加深掘り
▶ 二値カテゴリ(Binary Variable)
2 値のみのカテゴリ(性別: M/F, 喫煙: Yes/No 等)は質的変数の特殊ケース。 0/1 に直接変換するだけで OK。 χ² 検定の代わりに Fisher 正確検定が一般的。
▶ 多値ラベル(Multi-label)
1 サンプルに複数カテゴリが該当する場合(商品の複数タグ等)。 Multi-hot Encoding(複数の 1 が立つ)で表現。 sklearn の MultiLabelBinarizer が便利。
▶ 階層カテゴリ(Hierarchical)
「動物 → 哺乳類 → 食肉目 → ネコ科 → ネコ」のような階層を持つカテゴリ。 各階層を別の特徴量として扱う、 階層 path を文字列として扱う、 木構造 Embedding 等の手法がある。
▶ 循環カテゴリ(Cyclic)
曜日・月・時刻のように「最後と最初が連続する」カテゴリ。 sin/cos エンコーディングで連続性を保つのが標準:
$$x_{\sin} = \sin(2\pi k / K), \quad x_{\cos} = \cos(2\pi k / K)$$
「日→月」の距離が「土→日」と同じになる。
▶ Cohen's κ(カッパ係数)
2 人のアノテーターが質的変数を付けたときの「偶然超えた一致度」を測る指標。 アノテーション品質チェックで必須。 sklearn の cohen_kappa_score で計算可能。
▶ Phi 係数(φ)
2×2 クロス表での連関係数。 χ² から計算: φ = √(χ²/n)。 2 値変数間の関連性測定に使用。 数値変数の相関係数に対応する位置づけ。
▶ Lambda 係数(λ)
Goodman-Kruskal の λ。 「変数 X を知ると変数 Y の予測がどれくらい改善するか」を測る非対称指標。 連関の方向性を考慮できる。
🔭 今後のトレンド (2025-)
Pretrained Tabular Embedding : 大規模な企業データ・公的データから学習した汎用 Embedding が利用可能になる流れ。 業界横断で再利用。
LLM による前処理自動化 : 「このカテゴリ列を最適なエンコーディングに変換して」とプロンプトすれば、 LLM が cardinality / 分布 / 目的変数を見て自動選択。
Tabular Transformer 系の普及 : TabPFN, FT-Transformer, TabNet 等が GBM を上回る精度を達成し始め、 質的変数の Embedding がより重要に。
Graph Embedding との融合 : カテゴリ間の関係を Graph として表現し、 GNN で Embedding 学習する手法が増加。
Privacy-preserving Encoding : 差分プライバシーを満たす Target Encoding が研究進展中。
Streaming / Online Embedding : 新カテゴリ追加に動的対応する Embedding 手法。 オンライン学習で必須。
🎯 最終まとめ
質的変数は カテゴリで分類される変数 であり、 統計分析・機械学習の両方で必須の概念。 SSDSE-B-2026 の都道府県データは典型的な 47-クラス名義変数で、 8 地方ブロックへの集約、 χ² 検定 (2.72, p=0.26)、 Cramér's V (0.24) など多様な分析を実演した。 ML への投入時は cardinality とモデル種別に応じて One-hot / Label / Target / Hash / Embedding を使い分ける。 Target Encoding のリーク対策(K-fold, smoothing, CatBoost OTS)と、 高 cardinality 時の Entity Embedding が現代的な定番手法。 順序尺度は名義尺度と区別して順序情報を活かす Ordinal / Polynomial / 順序回帰モデルを選ぶ。 今後は Pretrained Tabular Embedding や LLM 駆動の自動前処理が標準化される見込み。
📊 エンコーディング手法 完全比較表
手法 出力次元 cardinality 適性 線形モデル ツリーモデル NN リーク 未知対応
One-hot K 低 ◎ ○ △ なし 困難
Label 1 高 ✗ ○ ✗ なし 困難
Ordinal 1 高 ○ (順序変数) ○ ○ なし 困難
Frequency 1 非常に高 ○ ◎ ○ なし ○ (頻度 0)
Mean Target 1 非常に高 ◎ ◎ ◎ 高 (要対策) ○ (全体平均)
LOO Target 1 非常に高 ◎ ◎ ◎ 中 ○
Hash m (任意) 非常に高 ○ ○ ○ なし ◎
Binary log2(K) 中 ○ ○ ○ なし 困難
Entity Embed. d (8-64) 非常に高 ✗ ✗ ◎ なし △
CatBoost OTS 1 非常に高 N/A CatBoost 専用 N/A なし ○
凡例: ◎=最適, ○=良好, △=要注意, ✗=非推奨
質的変数
Target Encoding
Frequency Encoding
Hash Encoding
Entity Embedding
Leave-One-Out Enc.
Binary Encoding
🔗 隣接手法への橋渡し
「質的変数」は単独で完結する手法ではなく、 隣接領域と連携することで真価を発揮する。
SSDSE-B-2026 の都道府県コード (R01000=北海道) や産業大分類は質的変数で、 ダミー変数化・カテゴリ別集計・カイ二乗検定が主な処理。 平均や和に意味は無く、 量的変数とは扱いを分ける。
🌳 手法選択フロー
「質的変数」を実際の課題に当てはめるとき、 状況別に何を選ぶかを 3 段階で判定する。
順序があるか? Yes → 順序尺度 (満足度 1-5)、 No → 名義尺度 (血液型・都道府県コード)
カテゴリ数は少ないか? 少 (2-10) → One-Hot エンコーディング、 多 (100+) → Target/Frequency エンコーディング
関連性を測るか? 質的 × 質的 → カイ二乗 + Cramér V、 質的 × 量的 → ANOVA / 群別箱ひげ図
SSDSE-B-2026 の都道府県コード (R01000=北海道) は名義尺度なので、 数値演算ではなくダミー化または地域別集計で使う。 R01000 と R47000 の「平均」は意味を持たない。