「classification」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「classification」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。
これらのキーワードは「classification の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。
🍰 まずはやさしく
分類はデータのグループ分けです。
正解のクラスを当てるために使います。
メールが迷惑メールか分ける例があります。
ここでは分類の手法や評価方法を読みます。
分類:離散的なクラスを予測する教師あり学習タスク
🍰 まずはやさしく
分類は機械学習の基本です。
データ分析の流れを掴むために使います。
都道府県のデータを分ける例で考えます。
定義から実装までの6つの視点で読みます。
この用語は ML基礎 カテゴリに属します。 関連する別称・略号:(なし)。
論文・実務レポートで 分類 が登場したら、 まず本ページの「30秒で分かる結論」と「直感で掴む」を読めば、 その文脈で何を言っているか把握できます。
本ページでは「classification」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。
「classification」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。
🍰 まずはやさしく
分類は仕分け作業のようなものです。
種類を正しく見分けるために使います。
写真が犬か猫か当てる例があります。
回帰との違いや仕組みについて読みます。
メールが届く。 これは spam か ham か? 件名・送信者・本文を見て「spam」と振り分けるのが分類。 出力は連続値ではなく「spam クラス」「ham クラス」という離散ラベル。 健康診断結果から「糖尿病あり/なし」、 画像から「犬/猫/鳥」、 顧客データから「離脱する/しない」を当てる、 すべて分類タスク。
回帰との違い: 同じ「予測」でも「明日の気温は何度?」 (連続値 → 回帰) と「明日は晴れ/曇り/雨?」 (3 クラス → 分類) は出力空間が違う。 分類器は内部でクラスごとの確率 $P(y=c \mid x)$ を計算し、 最も高いクラスを選ぶ (argmax) という構造になっている。 だから「猫 0.7 / 犬 0.2 / 鳥 0.1」のような「自信の度合い」も同時に得られる。
SSDSE-B-2026 での例: 47 都道府県を「A1303 / A1101 (高齢化率)」が 32% 以上なら "高齢化進行県"、 未満なら "若年県" の 2 クラスに分けるとする。 説明変数として A1101 (人口)、 H1800 (新設住宅着工)、 J2503 (病院数) を使い、 ロジスティック回帰や決定木で「どの説明変数がクラス境界を決めているか」を可視化できる。 これが SSDSE で扱う典型的な分類タスク。
| 種類 | クラス数 | SSDSE 例 |
|---|---|---|
| 二値分類 (Binary) | 2 | 高齢化進行県 / 若年県 |
| 多クラス分類 (Multi-class) | 3 以上、 排他 | 8 地方区分 (北海道/東北/関東/...) |
| 多ラベル分類 (Multi-label) | 複数同時に Yes | "高齢/低出生率/人口減少" のどれを満たすか (3 ラベル独立) |
🍰 まずはやさしく
分類は確率で答えを決める仕組みです。
最も可能性が高いグループを選ぶために使います。
テストの合否を判定する例に似ています。
予測に使う数式や損失関数について読みます。
入力 $\mathbf{x}$ に対し、 各クラス $k$ の確率 $P(y=k|\mathbf{x})$ を計算し、 最も高いクラスを予測ラベルとする。 2 クラスならロジスティック回帰、 多クラスならソフトマックスが代表。
分類器の学習で最も基本となる損失は クロスエントロピー (対数損失)。 二値分類では ロジスティック損失、 多クラスでは Softmax + クロスエントロピー として現れる。
$$ L_{\text{binary}} = -\frac{1}{n}\sum_{i=1}^{n}\bigl[y_i \log \hat p_i + (1-y_i)\log(1-\hat p_i)\bigr] $$
$$ L_{\text{multi}} = -\frac{1}{n}\sum_{i=1}^{n}\sum_{k=1}^{K} y_{ik}\log \hat p_{ik}, \quad \hat p_{ik} = \frac{e^{z_{ik}}}{\sum_{j=1}^{K} e^{z_{ij}}} $$
3 件のサンプル予測確率と真のラベルから対数損失を手計算。
🎯 このコードでやること: SSDSE-B-2026 で「高齢化率 30% 以上か」を予測し、 sklearn の log_loss で対数損失を計算する。
📥 入力データ (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 | import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline from sklearn.model_selection import train_test_split from sklearn.metrics import log_loss, accuracy_score, f1_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] # 2023年のみ抽出 df['aging_rate'] = df['A1303'] / df['A1101'] # 高齢化率 = 65歳以上/総人口 df['label'] = (df['aging_rate'] >= 0.30).astype(int) X = df[['A1101', 'A1303']] y = df['label'] X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=42) clf = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000)).fit(X_tr, y_tr) p = clf.predict_proba(X_te) print(f'対数損失 = {log_loss(y_te, p):.4f}') print(f'Accuracy = {accuracy_score(y_te, clf.predict(X_te)):.3f}') print(f'F1 = {f1_score(y_te, clf.predict(X_te)):.3f}') |
📤 実行例:
💬 結果の読み方: 対数損失 0.67 は完璧 (0) ではないが分類器として機能。 Accuracy 0.733 は 15 件中 11 件正解レベル、 F1 0.80 は精度と再現率のバランスが良い。 サンプル数が少ない (47 県) ため、 交差検証で安定性を確認すべき。
数式に出てくる記号の意味を 1 つずつ確認しましょう。
都道府県を「高齢化が進んだ県 (高齢化率 ≥ 30%)」「進んでいない県」に分類するモデルを作る。
A1303/A1101 ≥ 0.30 で 1
df['aging_rate'] = df['A1303'] / df['A1101'] → df['high_aging'] = (df['aging_rate'] >= 0.30).astype(int)。 高齢化率 30% 以上は秋田 (39.06%)、 高知 (36.34%)、 山口 (35.36%) ら 35 県で 1、 沖縄 (23.84%) や東京 (22.75%) ら 12 県で 0。 クラス分布 35:12 ≒ 0.74:0.26 で陽性がやや多い。A4101 (出生数)、 A5101 (転入者数)、 A5102 (転出者数)、 F3101 (就業者数)、 B4101 (面積)、 E1101 (小学校数)。 これらを StandardScaler で標準化 (人口スケールが県ごとに 26 倍違うため正規化が必須)。LogisticRegression(C=1.0, max_iter=1000) を StratifiedKFold(n_splits=5) で交差検証。 N=47 なので分割は厳しめだが、 平均 Accuracy ≒ 0.81、 F1 ≒ 0.79、 AUC ≒ 0.88 程度 (実行ごとに ±0.05 変動)。合成 2 クラス分類結果(TP=10, TN=15, FP=3, FN=2、 合計 30 件)を代入し、 accuracy / precision / recall / specificity / F1 の 5 指標を Step 1〜4 で展開する。 同じ計算を Python で再現し、 結果が完全一致することを確認する。
$$ \text{accuracy} = \frac{TP+TN}{TP+TN+FP+FN}, \;\; \text{precision} = \frac{TP}{TP+FP}, \;\; \text{recall} = \frac{TP}{TP+FN}, \;\; F_1 = \frac{2 \cdot P \cdot R}{P+R} $$
accuracy は全体の正答率、 precision は陽性予測の的中率、 recall は陽性の取りこぼし率の裏、 F1 は precision と recall の調和平均。
| 実際 \ 予測 | 陽性(1) | 陰性(0) | 行合計 |
|---|---|---|---|
| 陽性(1) | TP = 10 | FN = 2 | 12 |
| 陰性(0) | FP = 3 | TN = 15 | 18 |
| 列合計 | 13 | 17 | 30 |
合計 30 件のうち、 真の陽性 12 件・真の陰性 18 件。 陽性予測は 13 件、 陰性予測は 17 件。
| 指標 | 数式 | 計算 | 結果 |
|---|---|---|---|
| accuracy | (TP+TN) / total | (10+15) / 30 | 0.8333 |
| precision | TP / (TP+FP) | 10 / (10+3) = 10/13 | 0.7692 |
| recall(感度) | TP / (TP+FN) | 10 / (10+2) = 10/12 | 0.8333 |
| specificity | TN / (TN+FP) | 15 / (15+3) = 15/18 | 0.8333 |
| 項目 | 計算 | 結果 |
|---|---|---|
| 2 × P × R | 2 × 0.7692 × 0.8333 | 1.2820 |
| P + R | 0.7692 + 0.8333 | 1.6025 |
| F1 = (2PR) / (P+R) | 1.2820 / 1.6025 | 0.8000 |
分数のまま厳密に計算すると、 F1 = 2 × (10/13) × (10/12) / (10/13 + 10/12) = 20/25 = 0.8000。
| 指標 | 値 | 意味 |
|---|---|---|
| accuracy | 0.8333 | 30 件中 25 件正解 |
| precision | 0.7692 | 陽性予測 13 件中 10 件が本当の陽性 |
| recall | 0.8333 | 真の陽性 12 件中 10 件を取りこぼさず検出 |
| F1 | 0.8000 | P と R のバランス指標 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import numpy as np from sklearn.metrics import (accuracy_score, precision_score, recall_score, f1_score, confusion_matrix) # Step 1: 混同行列から y_true, y_pred を逆構成 # TP=10, FN=2 (実陽性 12), FP=3, TN=15 (実陰性 18) y_true = np.array([1]*12 + [0]*18) y_pred = np.array([1]*10 + [0]*2 + [1]*3 + [0]*15) cm = confusion_matrix(y_true, y_pred) print(f"混同行列:\n{cm}") acc = accuracy_score(y_true, y_pred) prec = precision_score(y_true, y_pred) rec = recall_score(y_true, y_pred) f1 = f1_score(y_true, y_pred) print(f"accuracy = {acc:.4f}") print(f"precision = {prec:.4f}") print(f"recall = {rec:.4f}") print(f"F1 = {f1:.4f}") |
💬 手計算(Step 2: accuracy=0.8333, precision=0.7692, recall=0.8333、 Step 3: F1=0.8000)と Python 出力が完全一致。 sklearn の混同行列は [[TN, FP], [FN, TP]] の順なので、 [[15,3],[2,10]] は Step 1 と整合する。
ここは決定境界・混同行列・閾値の 3 点を手で動かして体感する実験室です。 数式や個別分類器(ロジスティック回帰など)の解説は他ページに譲り、 ここでは「境界を動かすと指標がどう変わるか」だけに集中します。 使うデータはすべて架空(このページ用に生成した仮想的な 2 クラス点)で、 現実の SSDSE 値ではありません。 乱数はシード固定なので、 誰が開いても最初の配置は同じです。
青 ●=陽性クラス、 橙 ●=陰性クラス(いずれも架空)。 直線 y = 傾き·x + 切片 より上側を「陽性と予測」します。 スライダーで境界を動かすと、 各点が TP / FP / FN / TN のどれになるかが変わり、 右の混同行列と精度・適合率・再現率が即座に更新されます。 点はドラッグで移動、 空白をクリック/タップで追加(下のトグルで追加する色を選択)できます。
| 予測 陽性 | 予測 陰性 | |
| 実 陽性 | TP=0 | FN=0 |
| 実 陰性 | FP=0 | TN=0 |
赤枠の点は誤分類(FP または FN)。 境界を回転・平行移動して、 誤りをゼロにできるか試してください。
分類器は本来「陽性である確率(スコア)」を出し、 閾値以上を陽性と判定します。 下は 20 件(架空)のスコア分布。 青=真陽性、 橙=真陰性。 縦線(閾値)をドラッグすると、 線の右側が陽性予測になります。 閾値を上げると適合率↑・再現率↓、 下げると逆になる ── デフォルト 0.5 が常に最適ではないことを体感してください。
適合率・再現率を両立できないのは、 陽性と陰性のスコア分布が重なるから。 全閾値を横断的に見るのが ROC 曲線 と AUC です(→ 発展)。
全 100 件のうち陽性の数をスライダーで変えます。 「全部陰性と予測するだけの怠けモデル」と「まともに学習したモデル(再現率 60%・誤検知 5%)」を比較。 陽性が少ないほど、 何も当てていない怠けモデルでも正解率が跳ね上がるのに、 F1 はゼロのまま ── これが 正解率だけを見てはいけない理由(accuracy paradox)です。
最小実装の例。 SSDSE のような実データに対して、 まずはコピペで動かしてみるのが理解の早道です。
1 2 3 4 5 6 7 8 | import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.metrics import classification_report df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026'] == 2023] y = (df['A1303'] / df['A1101'] >= 0.30).astype(int) # 高齢化率30%以上=1 X = df[['A4101', 'A4103']] # 出生数・合計特殊出生率 print(classification_report(y, LogisticRegression(max_iter=1000).fit(X, y).predict(X))) |
分類問題で「どれが一番強いか」を比較するときは、 必ず 同じデータ × 同じ評価指標 × 同じ分割 で揃えます。 ここでは LogisticRegression / RandomForestClassifier / SVC を 5 分割クロスバリデーションで比較。 結果の「平均」と「分散」を両方見るのが重要です。
このコードでやること:先ほどの SSDSE-B-2026 高齢化フラグタスクに、 3 アルゴリズムを cross_val_score で適用し、 平均精度と標準偏差を比較する。
📥 入力:先ほど作った X(47×3、 birth/death/net_in) と y(47 要素、 0/1)。 ラベル分布は {0: 24, 1: 23} でほぼ均衡。
1 2 3 4 5 6 7 8 9 10 11 12 | from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier from sklearn.svm import SVC from sklearn.model_selection import cross_val_score models = { 'LogReg': LogisticRegression(max_iter=1000), 'RF': RandomForestClassifier(n_estimators=100, random_state=0), 'SVM': SVC(probability=True), } for name, m in models.items(): s = cross_val_score(m, X, y, cv=5, scoring='accuracy') print(f'{name:6} acc\tmean={s.mean():.3f} std={s.std():.3f}') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:RF(ランダムフォレスト)の平均精度が 91.6% で最高だが、 標準偏差 0.076 も大きい。 LogReg は 89.6% と僅差で、 ばらつきが小さく安定(std=0.063)。 SVM は今回の小サンプル(n=47)では不利で、 平均 85.3%・ばらつき大。 「47 件の小規模問題では、 解釈しやすい LogReg を主モデルに、 RF で検証」が現実的な選択。
先ほどの LogReg 単独学習精度は 95.7% でしたが、 5-fold CV の平均では 89.6% に下がりました。 これは 47 件中 9-10 件を「未知データ」として除外し、 残り 38 件で学習したモデルで予測しているから。 47 件全部で学習した数字は 過信になりやすい。 論文・レポートでは必ず CV または train/test 分割の結果を載せます。
CV の平均値だけでは「どんな間違いをしたか」が見えません。 ここで train/test 分割 をしてホールドアウトしたテストデータに対する 混同行列・適合率・再現率・F1・AUC をすべて出して、 モデルの癖を観察します。
このコードでやること:47 件を 7:3 で層化分割し、 ロジスティック回帰を訓練して、 主要評価指標を一覧表示する。
📥 入力:先ほどの X(47×3)と y(47 要素)。 train_test_split で 33 件を訓練、 14-15 件をテストへ層化分割。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from sklearn.model_selection import train_test_split from sklearn.metrics import (confusion_matrix, classification_report, roc_auc_score) Xtr, Xte, ytr, yte = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y) m = LogisticRegression(max_iter=1000).fit(Xtr, ytr) yp = m.predict(Xte) yprob = m.predict_proba(Xte)[:, 1] print('== 混同行列 ==') print(confusion_matrix(yte, yp)) print(classification_report(yte, yp, target_names=['未進行', '進行'])) print(f'AUC = {roc_auc_score(yte, yprob):.3f}') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:テスト 15 県のうち、 未進行(陰性)4 件は 2 件正解・2 件を「進行」と誤判定(FP=2)。 進行(陽性)11 件のうち 10 件は正解、 1 件のみ「未進行」と誤判定(FN=1)。 accuracy は 0.80、 進行クラスの F1 は 0.87、 AUC=0.864。 陽性が 11 件・陰性が 4 件と偏っているため、 accuracy より クラス別の precision/recall を見るべき水準。 ただしテスト 15 件は信頼区間が広いので、 数値を絶対視せず、 後段で 閾値変更 による感度の変化も観察するのが良い。
| 指標 | 数式 | 今回の値 | 読み方 |
|---|---|---|---|
| Accuracy | $(TP+TN)/N$ | (6+8)/15 = 0.933 | 全体の的中率。 不均衡時は危険 |
| Precision(進行) | $TP/(TP+FP)$ | 10/(10+2) = 0.833 | 「進行」と予測したものの精度 |
| Recall(進行) | $TP/(TP+FN)$ | 10/(10+1) = 0.909 | 「真の進行」のうち拾えた率 |
| F1 | $2PR/(P+R)$ | 0.870 | P と R の調和平均 |
| AUC | ROC 曲線下面積 | 0.864 | 閾値非依存の総合性能 |
この用語を使うときに陥りがちな失敗パターン。 経験者ほどここに 1 度はハマっています。
StandardScaler をパイプラインに入れる。TimeSeriesSplit を使う。分類モデルは内部で 確率 を出し、 通常 0.5 を境にラベル化します。 でも本当の境界は業務コストで決まる。 ここでは閾値を 0.1〜0.9 で動かし、 Precision・Recall・F1 がどう変化するかを SSDSE-B-2026 データで観察します。
このコードでやること:先ほどの LogReg の予測確率から、 閾値を 0.1 刻みで変えながら適合率・再現率・F1 を計算してテーブル化する。
📥 入力:先ほどの yte(テスト 15 件のラベル)、 yprob(陽性クラスの予測確率)。
1 2 3 4 5 6 7 8 9 10 11 12 | import numpy as np from sklearn.metrics import precision_score, recall_score, f1_score rows = [] for th in np.arange(0.1, 1.0, 0.1): yhat = (yprob >= th).astype(int) rows.append((round(th, 1), precision_score(yte, yhat, zero_division=0), recall_score(yte, yhat), f1_score(yte, yhat, zero_division=0))) print('threshold | precision | recall | F1') for th, p, r, f1 in rows: print(f'{th:9.1f} | {p:9.3f} | {r:6.3f} | {f1:5.3f}') |
📤 実行すると次の出力が得られる:
💬 結果の読み方:閾値 0.1 が F1 最高(0.917)で、 0.2〜0.6 では 0.870 と横ばい。 業務上「見逃したくない(Recall 重視)」なら閾値を下げ、 「誤検知を減らしたい(Precision 重視)」なら上げる。 このデータでは 0.8 まで上げても Precision は 0.900 にしか上がらず Recall が 0.818 に落ちるので、 閾値を動かす旨みは小さい。 デフォルト 0.5 が常に最適ではない、 という事実を体感できる。 医療では低閾値、 スパム検知では高閾値、 のように 業務コスト から逆算するのが本道。
$C_{FN}$ は偽陰性 1 件の業務コスト(病気見逃し = 致命的なら大)、 $C_{FP}$ は偽陽性 1 件のコスト(追加検査の費用)。 両者の比から最適閾値が決まる。 単に F1 最大化ではなく、 ビジネス指標で最適化するのが現代の流儀。
分類モデルの「結果」だけでなく「なぜそう判定したか」を説明できると、 業務での説得力が桁違いに上がります。 ロジスティック回帰の 係数 は log-odds の変化 を表し、 オッズ比 に変換すると「特徴量 1 単位増えると陽性オッズが何倍になるか」が読めます。
このコードでやること:SSDSE-B-2026 高齢化フラグタスクのロジスティック回帰係数を取り出し、 オッズ比に変換して表示する。 ランダムフォレストの特徴量重要度も併記。
📥 入力:先ほどの X = [birth, death, net_in](47×3)と y。 StandardScaler で標準化して係数を比較可能に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from sklearn.preprocessing import StandardScaler import numpy as np scaler = StandardScaler() Xs = scaler.fit_transform(X) logs = LogisticRegression(max_iter=1000).fit(Xs, y) rf = RandomForestClassifier(n_estimators=200, random_state=0).fit(X, y) cols = ['birth', 'death', 'net_in'] print('== LogReg (標準化後の係数) ==') print(f'intercept: {logs.intercept_[0]:.3f}') for c, w in zip(cols, logs.coef_[0]): print(f' {c:7}: coef={w:+.3f} オッズ比={np.exp(w):.2f}') print('== RandomForest (重要度) ==') for c, imp in zip(cols, rf.feature_importances_): print(f' {c:7}: {imp:.3f}') |
📤 実行すると次の出力が得られる(典型例):
💬 結果の読み方:LogReg の係数(標準化後)を見ると、 death(死亡率)の係数 +3.29 が最大、 オッズ比 26.77。 死亡率が標準偏差 1 つ分高い県は、 高齢化進行クラスのオッズが 約 27 倍に。 出生率は逆方向(オッズ比 0.12 = 1/8 に下がる)。 RF の重要度も death が最大(0.60)で一致。 「死亡率が高齢化フラグの最強予測子」という結論は両モデルで支持される。
| 前提 | 係数の解釈 | いつ使う |
|---|---|---|
| 標準化 なし | 「特徴量が 1 単位 増えるとオッズが何倍」 | 「死亡率 1‰ 増 → ?」のように元単位で説明したい |
| 標準化 あり | 「特徴量が 1 SD 増えるとオッズが何倍」 | 特徴量間の 相対的な強さ を比較したい |
医療・金融・採用など 説明責任 が求められる領域では、 解釈可能性は精度と同等以上に重要。 RF や勾配ブースティングは精度が高い反面、 解釈は SHAP 等のツールで補強する必要があります。
前処理 → 学習 → 予測を Pipeline でひとまとめにすると、 リークを防ぎ、 train/test や CV の各 fold で正しく前処理が適用されます。 これは「分類」を超えてあらゆる機械学習タスクの標準形。
このコードでやること:SSDSE-B-2026 高齢化フラグタスクで StandardScaler → LogisticRegression のパイプラインを構築し、 GridSearchCV で正則化強度 C を探索する。
📥 入力:先ほどの X, y。 5-fold CV で C を [0.01, 0.1, 1, 10, 100] から選ぶ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from sklearn.pipeline import Pipeline from sklearn.model_selection import GridSearchCV pipe = Pipeline([ ('scaler', StandardScaler()), ('clf', LogisticRegression(max_iter=1000, random_state=0)), ]) grid = GridSearchCV(pipe, {'clf__C': [0.01, 0.1, 1, 10, 100]}, cv=5, scoring='f1').fit(X, y) print(f'最良 C: {grid.best_params_["clf__C"]}') print(f'CV F1 平均: {grid.best_score_:.3f}') print('C別 F1:', dict(zip(grid.cv_results_['param_clf__C'].data, grid.cv_results_['mean_test_score'].round(3)))) |
📤 実行すると次の出力が得られる(典型例):
💬 結果の読み方:C=1 が最良(F1=0.948)。 C は正則化の逆数なので、 小さいほど強い正則化。 C=0.01 では F1=0.854 まで落ち、 C=10 以上では 0.933 と横ばい〜わずかに悪化。 「正則化を弱めすぎると過学習、 強めすぎるとアンダーフィット」の典型例。 標準化を Pipeline 内に入れたので、 各 fold で訓練データの mean/std を使って fit_transform、 テストには transform のみ ── リークなし。
fit_transform → CV スコアが過大評価Pipeline でひとまとめにしたかjoblib.dump(pipe, 'model.pkl') でモデルを保存(前処理込み)joblib.load で読み込み、 生の入力を predict に渡すだけpydantic 等で検証本ページ後半で行ってきた実演を 1 ページに整理します。 分類タスクを実務で進めるとき、 この流れを「型」として身に付けてください。
| 工程 | 今回の選択 | 理由 |
|---|---|---|
| 問題設定 | 高齢化率 ≥ 32% の 2 値分類 | 全国平均(31.6%)付近で均衡を取る |
| 特徴量 | 出生率・死亡率・転入超過率 | 自然動態 + 社会動態で説明可能性を確認 |
| モデル比較 | LogReg / RF / SVM を 5-fold CV | 線形・木・カーネルの 3 系統で当たりをつける |
| 評価指標 | 混同行列・F1・AUC | 不均衡時に accuracy だけ見ない |
| 追加検証 | 多クラス化・不均衡化 | 問題設定変化時の性能劣化を観察 |
encoding='cp932', skiprows=[1] で読み込むdf['SSDSE-B-2026']==2023)cross_val_score で 3 モデル比較 → 上位 1-2 候補に絞るtrain_test_split(stratify=y) で hold-out 評価 → 混同行列・F1・AUC を併記class_weight='balanced' や閾値調整Pipeline で前処理 + 分類器をまとめ、 GridSearchCV でハイパラ最適化jupyter notebook で再現する本ページの 6 つのコードブロックは、 順番に Jupyter のセルに貼り付ければそのまま動きます(SSDSE-B-2026.csv を data/raw/ 配下に置くこと)。 6 セル合計で 50 行程度、 実行時間は MacBook で 3 秒以内。 手元で動かしながらこのページを再度読むと、 数字と挙動が体に染み込みます。 「読むだけ → 動かして読む → 改造して読む」の 3 段階を踏むのが、 最速の習得法です。
F1, AUC, SMOTE 等が出てきて意味を確認したいどの層でも、 「30 秒結論 → 直感 → 数式 → Python → 落とし穴」の順で読めば 20-30 分で要点が掴めます。 後半の SSDSE-B-2026 実演は、 手を動かす段階で 必須 です。
| 業務シナリオ | ラベル設計 | 注目すべき指標 |
|---|---|---|
| 顧客の離脱予測 | 過去 N ヶ月で離脱したか(1/0) | Recall(見逃しを減らす)、 PR-AUC |
| 医療診断(陽性検出) | 病気あり/なし | 高 Recall(FN コスト大)、 閾値はビジネス基準 |
| スパムフィルタ | スパム / ハム | 高 Precision(FP コスト大)、 F1 |
| クレジット審査 | デフォルトする / しない | AUC、 較正、 解釈可能性 |
| 画像分類(多クラス) | N クラスの 1 つ | Top-k accuracy、 macro F1 |
| 不正検知 | 不正取引 / 正常(不均衡) | PR-AUC、 SMOTE、 閾値最適化 |
SSDSE-B-2026 の高齢化フラグタスクで身に付けた型は、 これら業務タスクすべてに横展開できます。 違うのは ラベル設計・業務コスト・注目指標 の 3 点のみ。 本ページの枠組みを応用して、 自分の業務データに当てはめてみてください。
「分類」を中心に、 教師あり学習・特徴量設計・モデル評価指標 (precision/recall/F1)・中規模データ実用域・クラス不均衡対策を 6 方向で配置した俯瞰図。 分類器の選択 → 学習 → 評価 → 不均衡対策の流れを 1 枚で示す。
上の概念マップは「分類」を中心に、 結果の読み方(precision/recall/F1)と medium(中規模データでの実用域)、 各クラスの学習データ不足(class imbalance リスク)を 3 方向で並べた俯瞰図である。 中央ノードから放射する 3 つの軸を眺めると、 分類タスクで真っ先に確認すべき「データ量・指標・不均衡」の三点が一目で掴める。
「分類」は教師あり学習の中核で、 上流の特徴量設計とクラス分布の確認 (不均衡対応) を欠くと、 並列手法の比較すら無意味になる。
上流の特徴量と前処理を揃え、 並列のロジスティック回帰・SVM・勾配ブースティングをベンチマークし、 下流で混同行列と PR 曲線を出せば、 「どの手法が SSDSE データで最も汎化するか」を客観的に答えられる。
「分類」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。
class_weight かリサンプリングで学習側も調整する。分類は「どのクラスか」を当てる枠組みで、 数値そのものを当てたいなら回帰へ。 A1101 人口を 3 階級化して分類問題にすると、 境目付近の県の扱いが恣意的になる点にも注意。
📝 補足(本節は既存「🎨 直感で掴む」の追記深化です。 既存の記述はそのまま、 決定境界・出力空間・タスク型の 3 点を補強します)。
分類器の学習とは、 特徴量が張る空間を 決定境界 (decision boundary) で複数の領域に区切り、 各領域に 1 つのクラスラベルを貼る作業です。 新しい入力 $\mathbf{x}$ は「どの領域に落ちたか」でクラスが決まります。 上の「🎮 触って理解する」ウィジェット① は、 この境界を 直線 1 本 で引く最小の体験装置です。 ロジスティック回帰は直線 (超平面)、 決定木は軸に平行な階段状、 SVM はカーネル次第で曲線 ── 「境界の形」がアルゴリズムの個性そのものだと捉えると、 手法比較の見通しが一気に良くなります。
内部的には各クラスの確率 $P(y=k\mid\mathbf{x})$ を計算し、 最大のクラスを選ぶ (softmax / シグモイド → argmax)。 だから「猫 0.7 / 犬 0.2 / 鳥 0.1」のような自信の度合いが同時に得られ、 これが後述の閾値調整や確率較正の余地を生みます。
| 観点 | 分類 (classification) | 回帰 (regression) |
|---|---|---|
| 出力空間 | 離散カテゴリ(有限集合) | 連続値(実数) |
| 代表的な出力例 | 高齢化進行県 / 未進行県 | 高齢化率 31.6% という数値そのもの |
| 典型的な損失 | クロスエントロピー / 対数損失 | 二乗誤差 (MSE) など |
| 主な評価指標 | 正解率・F1・AUC | R²・RMSE・MAE |
| 「惜しい外れ」の扱い | クラスが違えば一律に「不正解」 | 近ければ誤差が小さい(連続的) |
境界付近の値(例:高齢化率 31.6% の県)は本来「どちらとも言い難い」のに、 分類は無理やり 0/1 に押し込むため情報損失が起きます。 順序に意味がある連続量を予測したいなら、 まず回帰を検討し、 「意思決定として離散ラベルが必要」なときにだけ分類する ── これが出力空間の選び方の原則です。
「排他か非排他か」を最初に決めないと、 損失関数(softmax か independent sigmoid か)も評価指標(accuracy か per-label F1 か)も間違えます。 タスク型の取り違えは、 実務で最も多い設計ミスの 1 つです。
📝 補足(既存「⚠️ よくある落とし穴」の追記深化。 とくにラベル定義の閾値が結論を左右する点を、 SSDSE-B-2026 の実測分布で示します)。
高齢化率の閾値を動かすだけで、 陽性/陰性の比が劇的に変わります。 下表は SSDSE-B-2026(2023 年・47 都道府県)の実測クラス分布です(高齢化率 = A1303 ÷ A1101 × 100)。
| ラベル閾値 | 陽性(1) | 陰性(0) | 陽性率 | 性質 |
|---|---|---|---|---|
| ≥ 28% | 40 | 7 | 85.1% | 強い不均衡(陽性過多) |
| ≥ 30% | 35 | 12 | 74.5% | やや不均衡 |
| ≥ 31.6%(平均) | 25 | 22 | 53.2% | ほぼ均衡 |
| ≥ 32% | 23 | 24 | 48.9% | ほぼ均衡(本文の既定) |
| ≥ 35% | 6 | 41 | 12.8% | 不均衡(少数陽性) |
| ≥ 36% | 2 | 45 | 4.3% | 極端な不均衡 |
同じデータでも、 閾値 28% なら「陽性を当てるのは簡単(85% が陽性)」、 36% なら「陽性 2 県を見つける難問」に化けます。 閾値は分析を始める前に業務根拠で固定し、 後から精度が良く出る値に変えてはいけません(HARKing / 事後選択バイアス)。 全国平均は 31.59%、 中央値 31.78%、 最小 22.75%(東京)〜 最大 39.06%(秋田)で、 多くの県が境界の 31〜32% 付近に密集している点にも注意します。
閾値 36%(陽性 4.3%)では、 全県を「陰性」と予測するだけで正解率 95.7% に達します(本文「⚖️ クラス不均衡を作って…」の実演と一致)。 しかし陽性 F1 は 0.000。 不均衡下では 正解率単独は無意味で、 適合率・再現率・F1・PR-AUC を併記します。 詳細は クラス不均衡 ページへ。
既定の 0.5 は「事前確率が均衡・誤りコストが左右対称」という強い仮定に依存します。 見逃し (FN) のコストが高いなら閾値を下げ、 誤検知 (FP) のコストが高いなら上げる。 全閾値を横断評価するのが ROC 曲線/AUC と 適合率・再現率曲線です。 上の「🎮 触って理解する」ウィジェット② で、 閾値を動かすと適合率↑・再現率↓のトレードオフが即座に見えます。 さらに、 高齢化率 31.6% 付近に県が密集するため、 境界近傍の県はモデルの確率が 0.5 前後で揺れやすく、 わずかな特徴量差やシードで予測が反転します。 境界付近の予測は「自信度が低い」と明示するのが誠実な報告です。
| 指標 | 見ているもの | 向いている場面 |
|---|---|---|
| Accuracy | 全体の的中率 | クラスが均衡しているときのみ |
| Precision | 陽性予測の的中率 | 誤検知コスト大(スパム判定など) |
| Recall | 真陽性の取りこぼしの裏 | 見逃しコスト大(疾病検出など) |
| F1 | P と R の調和平均 | 両者のバランスを 1 値で |
| ROC-AUC | 全閾値での順位性能 | 閾値非依存で総合比較 |
| PR-AUC | 不均衡下の陽性検出力 | 陽性が希少なとき ROC より鋭敏 |
不均衡が強いほど ROC-AUC は楽観的に見えがちなので、 PR-AUC を主指標に据えるのが安全です。 体系的な整理は 評価指標・混同行列 ページへ。
出力確率「0.7」が実際の陽性頻度 70% に対応するとは限りません(この対応が取れている状態を較正が取れていると言います)。 ロジスティック回帰は比較的較正が良い一方、 SVM や決定木・ブースティングは歪みやすい。 Platt スケーリング(シグモイド較正)や Isotonic 回帰(単調較正)で補正し、 信頼度図 (reliability diagram) や Brier スコアで確認します。 確率をそのまま意思決定閾値やコスト計算に使うなら、 較正は精度と同等に重要です(※現時点で較正の専用用語ページは未整備のためテキストで補足)。
「どの県が苦手か」を見たいなら macro、 「全体の当たり具合」なら micro。 本文の多クラス実演では macro avg と weighted avg を併記していますが、 どの平均で報告したかを明示しないと数字が独り歩きします。
fit_transform(標準化・特徴選択)してから分割すると、 テスト情報が漏れる。 scikit-learn の Pipeline で fold ごとに fit する。TimeSeriesSplit を使う。いずれも「テスト時に本来知り得ない情報」が訓練に混入する現象。 詳細は データリーク ページへ。
📝 補足(既存「🌐 関連手法・派生」の追記深化。 代表分類器の特徴を横並びで整理します)。
| 手法 | 決定境界の形 | 確率出力 | 長所 / 注意 |
|---|---|---|---|
| ロジスティック回帰 | 線形(超平面) | 良好(較正されやすい) | 係数=log-odds で解釈容易 / 非線形は苦手 |
| 決定木 | 軸に平行な階段状 | 粗い(葉の頻度) | ルール可読 / 単体は過学習しやすい |
| SVM | 線形〜カーネルで曲線 | 要 Platt 較正 | マージン最大化で頑健 / スケール敏感・要標準化 |
| k近傍法 | 局所的・非線形 | 近傍の多数決比率 | 学習不要 / 高次元と距離スケールに弱い |
| ランダムフォレスト | 階段状の集合(滑らか化) | 中〜良 | 高精度・頑健 / 解釈は重要度・SHAPで補強 |
| 勾配ブースティング(XGBoost 等・木アンサンブル) | 弱学習器を逐次加算した複雑境界 | 中(較正推奨) | 表形式で最強クラス / 過学習と調整コスト |
「線形で足りるか(ロジスティック回帰)」→「非線形が要るか(木・カーネル)」→「精度最優先か(ブースティング)」の順に検討し、 解釈可能性と精度のトレードオフを業務要件から決めます。 距離・マージン系(SVM・kNN)は必ず標準化をパイプラインに入れる点に注意。
クラスが少なく確率較正を重視するなら multinomial、 2値分類器の資産を流用したいなら OvR、 という選び分けが実務的です。
分類の価値は「ラベル」より「確率」にあることが多い ── 確率があれば閾値もコストも後から最適化できます。 誤りのコストが非対称なとき(例:疾病見逃し $C_{FN}$ ≫ 誤検知 $C_{FP}$)は、 次のいずれかでコスト考慮学習 (cost-sensitive learning) を行います。
class_weight='balanced' 等で少数クラスの損失を重くする。 まず試す一行の対策。重み・リサンプリングは確率を歪めるため、 最後に較正し直すのが定石。 「①確率をきちんと出す → ②較正する → ③業務コストで閾値を決める」の 3 段構えが、 現代的な分類運用の型です。