論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
クラス不均衡
Class Imbalance
ML基礎
別称: 不均衡データ

🔖 キーワード索引

クラス不均衡Class ImbalanceSMOTEアンダーサンプリングオーバーサンプリングクラス重みF1PR-AUC焦点損失

本ページは クラス不均衡(Class Imbalance)を 12 のセクションで多角的に解説します。 上のチップは検索・関連語の手がかりです。 以下のリンクで各セクションに直接ジャンプできます:

💡 30秒結論📍 文脈🎨 直感📐 数式🔬 数式を言葉で読み解く🧮 実値計算🐍 Python 実装⚠️ 落とし穴🌐 関連手法🔗 関連用語📚 グループ教材

💡 30秒で分かる結論

🍰 まずはやさしく

データの数が大きく偏っている状態のことです。

正しい分析結果を出すために使います。

部活で1人だけ違う役割の人がいるような状態です。

まずは結論と直感的な意味を読みましょう。

クラス分布が偏っている問題

💡 30秒で分かる結論

📍 文脈 — どこで使う概念か

🍰 まずはやさしく

データの集まりに偏りがある問題のことです。

AIが正しく判断できるように調整するために使います。

スマホのアプリで不正な操作を見つける時に似ています。

データの変え方や評価の方法について読みましょう。

クラス不均衡は 分類タスクで各クラスのサンプル数が極端に偏る状況。 例:与信デフォルト(不良 2%)、 医療診断(陽性 1%)、 不正検知(不正 0.1%)。 単純な Accuracy では多数派ばかり予測する自明モデルが高得点を取るため、 評価指標と学習方法を不均衡向けに調整する必要がある。

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

このページは、 ジャストインタイム型データサイエンス教育の用語集の一部です。 本概念は、 統計学・データサイエンス・機械学習・AI の文脈で頻出する重要キーワードであり、 SSDSE-B-2026 都道府県データを使った実例とともに、 定義・直感・数式・実装・落とし穴・関連用語を体系的に学べる構成になっています。 まずは「30 秒で分かる結論」と「直感で掴む」セクションから読み、 必要に応じて数式・実装の詳細に進むことをおすすめします。

🔎 補足: クラス不均衡を「データ・指標・アルゴリズム」3 層で扱う

クラス不均衡 (class imbalance) は単一の魔法のような解決策がない問題で、 「データを変える」「指標を変える」「アルゴリズムを変える」という 3 つの層で同時に向き合う必要がある。 SSDSE-B-2026 を題材にすると、 たとえば「人口減少率が 5% 以上の都道府県」と「それ未満」の 2 値分類は約 6:41 の不均衡で、 47 都道府県のうち少数派クラスが 6 件しかない。 このような場面で各層の手筋を整理する。

1. データ層: リサンプリング戦略

少数派を増やす (oversampling)、 多数派を減らす (undersampling)、 合成する (SMOTE/ADASYN) の 3 系統がある。

2. 指標層: accuracy を捨てる

不均衡データでは accuracy が「多数派を全部正答するだけで高得点」になるため、 指標自体を入れ替える。

3. アルゴリズム層: クラス重み・閾値・アンサンブル

4. SSDSE-B-2026 での具体的フロー (47 都道府県 × 6:41 不均衡)

  1. EDA で 6:41 の比を確認、 accuracy では誤魔化されないと自覚する
  2. Stratified k-fold で fold ごとの少数派が崩れないようにする (例: k=3、 6 個を 2/2/2 に分割)
  3. LogisticRegression(class_weight='balanced') を baseline に
  4. F1 と PR-AUC を主要指標に、 ROC-AUC は補助
  5. SMOTE で訓練データのみ (test には触れない) を拡張して比較
  6. 閾値を 0.2 / 0.5 / 0.7 に変えて recall-precision の trade-off を業務側に提示

5. 落とし穴: test に SMOTE をかける

初心者がやりがちな最大の罠。 SMOTE は訓練データの合成なので、 test に適用するとデータリーケージで評価が水増しされる。 必ず pipeline で「fit → train だけ SMOTE → predict」の順を守る。 sklearn の Pipeline には imblearn の Pipeline が対応版として用意されている。

6. 検証: ベースラインを比較表に

不均衡対策の効果は、 必ず「何も対策しない baseline」と並べないと評価できない。 class_weight・SMOTE・EasyEnsemble など複数手法を試した結果を、 precision / recall / F1 / PR-AUC / 計算時間で比較する。 「F1 が 0.05 上がった代わりに precision が 0.2 落ちた」「計算時間が 10 倍になった」など、 トレードオフを正確に把握する。

7. 不均衡が「擬似的」に解消されたらまず疑う

急に F1 = 0.9 のような高い値が出たときは、 リーケージ・閾値の取り違い・ターゲット定義のミスを疑う。 SSDSE のような 47 件の小データでは、 たまたま少数派 6 件が訓練に多く出れば過大評価される。 必ず複数 seed で k-fold を回してばらつきを確認する。

8. 実装チェックリスト

9. まとめ

クラス不均衡は「データ × 指標 × アルゴリズム」の組み合わせ最適化。 銀の弾丸はないので、 業務コスト・データ規模・モデル特性を勘案して 3 層を同時に調整する。 47 都道府県のような小データでは、 過剰な合成より shrinkage や class_weight、 そして閾値調整の組み合わせが安全。

10. ケーススタディ: 詐欺検知の不均衡 (1:1000 規模) との対比

SSDSE-B-2026 の 47 都道府県 6:41 と、 産業界で頻繁に遭遇する詐欺検知 (約 1:1000、 1000 件中 1 件が陽性) を対比すると、 同じ「クラス不均衡」というラベルでも採るべき戦略がまったく異なることが分かる。 詐欺検知では絶対サンプル数が膨大なので、 多数派を 100 倍 undersampling しても 10 万件の正常サンプルが残り、 統計的に十分。 一方、 47 都道府県では 1 件失うだけで分散推定が壊れる。 規模が違えば対策の優先順位も変わる。 詐欺検知では「アルゴリズム層 (focal loss、 class_weight) + 指標層 (PR-AUC + コスト最小化)」が主、 都道府県データでは「指標層 (balanced accuracy + MCC) + アルゴリズム層 (class_weight) + データ層 (極控えめな SMOTE)」がバランス良い。 「不均衡対策」と一括りにせず、 規模・コスト・特徴量の質に応じて手筋を選ぶ目利きが重要。

11. なぜ accuracy は不均衡で破綻するのか — 数値例で理解する

47 都道府県の 6:41 の例で、 全件「多数派」と予測する単純モデルを考える。 このモデルは少数派 6 件を全て間違えるが、 多数派 41 件は全て正答するので accuracy = 41/47 ≈ 87.2% を達成する。 一見高得点だが、 少数派の recall = 0/6 = 0% で、 業務的にはまったく役立たない。 ここで PR-AUC を計算すると、 precision の平均が少数派比率 (≈ 0.128) に張り付くため、 約 0.13 という低い値しか得られない。 ROC-AUC は ±0.5 付近に止まる。 balanced accuracy は (recall_positive + recall_negative)/2 = (0 + 1)/2 = 0.5 となり、 ランダム予測と同等であることが暴露される。 accuracy 単独では「無策の多数派予測」が高得点に見えてしまうが、 balanced accuracy・F1・PR-AUC・MCC はいずれも 0 近辺を返し、 モデルの実態を正しく映す。

12. SMOTE の内部動作を丁寧に追う

SMOTE は少数派サンプル x_i を 1 つ選び、 その k 近傍 (通常 k=5) からランダムに 1 つ x_zi を選択し、 新サンプル x_new = x_i + λ × (x_zi - x_i) を生成する (λ は [0, 1] の一様乱数)。 これは「2 つの少数派サンプルを結ぶ線分上にランダムに点を打つ」操作に等しい。 連続値特徴量では自然な「中間サンプル」が生まれ、 決定境界を少数派側に押し広げる効果がある。 ただし注意点は、 (1) 高次元では近傍が信頼できなくなる (curse of dimensionality)、 (2) カテゴリカル特徴量にそのまま使うと「中間カテゴリ」という意味不明な値ができる、 (3) 外れ値が k 近傍に入ると合成サンプルも外れ値方向に伸び、 むしろ境界を歪めることがある。 (3) への対策として Borderline-SMOTE (境界付近の少数派のみを合成元にする) や ADASYN (誤分類しやすい少数派ほど多く合成する) が提案されている。

13. class_weight='balanced' の内部計算式

scikit-learn の class_weight='balanced' は、 各クラス c の重みを w_c = n / (K × n_c) で計算する。 ここで n は総サンプル数、 K はクラス数、 n_c はクラス c のサンプル数。 47 都道府県 6:41 の例では、 多数派の重み w_maj = 47 / (2 × 41) ≈ 0.573、 少数派の重み w_min = 47 / (2 × 6) ≈ 3.917。 つまり少数派 1 件の誤分類は多数派 1 件の約 6.8 倍のペナルティを受ける。 これは元の比率 41/6 ≈ 6.83 と一致しており、 直感的にも「数の少ないクラスを数の多いクラスと同じ強さで主張させる」加重になっている。 ロジスティック回帰の損失関数で言えば、 L = -Σ w_yi × [y_i log p_i + (1-y_i) log (1-p_i)] となり、 少数派サンプルの勾配が約 6.8 倍強く流れる。

14. 閾値調整の実践: PR 曲線を業務コストと結ぶ

確率予測モデルでは、 デフォルトの 0.5 閾値は数学的にも業務的にも最適とは限らない。 業務側が「少数派の取りこぼし (false negative) を絶対許さない、 過剰陽性 (false positive) のコストは小さい」というポリシーなら閾値を下げて recall を上げる。 逆に「false positive のコストが極端に高い (例: スパム判定で正規メールを誤分類すると顧客が離脱)」なら閾値を上げて precision を確保する。 業務側との議論で具体的な金銭コスト C_FN, C_FP が得られれば、 全閾値で総コスト = C_FN × FN + C_FP × FP を計算し最小値を取る閾値を採用する。 これがコスト感度学習 (cost-sensitive learning) の最終形。 SSDSE 都道府県データで「人口減少率 5% 以上を見逃すと政策介入が遅れる」という想定なら、 少数派の recall を最優先する閾値選択になる。

15. 不均衡対策の組み合わせ表 — どれを組むか

単独の手法より組み合わせの方が効くケースが多い。 代表的な組み合わせを紹介する。

16. 評価設定の落とし穴 — 訓練・検証・テストの分け方

不均衡データでの cross-validation は必ず stratified split を使う。 通常の k-fold だと少数派が特定 fold に偏り、 訓練 fold に 0 件、 検証 fold に全数といった病的状態が起きる。 sklearn の StratifiedKFold は各 fold でクラス比を保つ。 さらに、 (1) SMOTE は train fold のみに適用し validation/test には触れない、 (2) Pipeline (imblearn.pipeline.Pipeline) を使って前処理 → SMOTE → モデルを一連で fit させる、 (3) GridSearchCV と組み合わせる際も Pipeline 全体を渡す、 という 3 原則を守る。 これを守らないと「テスト accuracy 0.95、 デプロイ後 0.6」という典型的なデータリーケージ事故が起きる。

17. 不均衡対策が「効かない」ケース

すべての場面で不均衡対策が必要なわけではない。 (1) クラス比が 1:3 程度の軽い不均衡で、 accuracy ベースで業務問題がない、 (2) 少数派の特徴量分布が多数派と完全に重なって本質的に分離不能、 (3) 少数派サンプルが極端に少なく (例: 5 件以下) で統計的にも何もできない、 という状況では対策の効果が限定的。 特に (3) は SSDSE の 6:41 ですら境界線上で、 6 件の少数派の分布が安定しているとは限らない。 こうした場面では「予測ではなく説明・観察」に問題を切り替えるか、 ドメイン専門家の知識でルールベース判定を補助する。

18. 主要ライブラリ一覧

19. 用語の関係マップ

クラス不均衡という用語は単独で完結する概念ではなく、 周辺概念とのネットワークで理解する必要がある。 上位概念には「分類問題」「評価指標」「データ前処理」が、 並列概念には「異常検知」「半教師あり学習」「能動学習」が、 下位概念には「SMOTE」「focal loss」「class_weight」「閾値最適化」が位置する。 異常検知 (anomaly detection) は不均衡分類の極端なケース (1:10000 以上) であり、 ラベルなしで One-Class SVM や Isolation Forest を使うことが多い。 半教師あり学習はラベルなし多数派を活用するアプローチで、 少数派ラベルだけがあるときに有効。 能動学習は「次にラベル付けするべきサンプル」を選ぶ手法で、 少数派候補を効率的に集める。

20. 最終チェックリスト (拡張版)

21. 補足: 47 都道府県データでの実例計算 (人口減少率)

SSDSE-B-2026 から「人口減少率」を計算し、 5% 以上の県を少数派とする想定では、 秋田・青森・岩手・高知・山形・徳島の 6 件程度が該当する (実際の値は年度・指標定義で変動)。 ここで LogisticRegression(class_weight='balanced') を baseline に、 特徴量に SSDSE-B-2026 の実在列「総人口(A1101)」「65歳以上人口(A1303)」「出生数(A4101)」「転入者数(A5101)」などを使うとする。 baseline では F1・PR-AUC ともに 0.6 前後(あくまで目安)にとどまる。 SMOTE を追加すると F1 ≈ 0.62 に上がるが PR-AUC は ±0.05 で揺らぐ。 閾値を 0.5 → 0.35 に下げると recall が 0.67 → 0.83 まで上がり、 precision は 0.50 → 0.42 に下がる。 これを 3 通り業務側に提示し、 政策判断のコストと相談して採用する。 このように「F1 一発勝負」ではなく「trade-off の提示と業務側の選択」が現実の data science の進め方になる。

🔎 拡張補足: クラス不均衡の現代的対応

1. SMOTE バリアントの選び方

(1) SMOTE 基本版: 少数派 k 近傍の線形補間、 (2) Borderline-SMOTE: 境界サンプルのみ拡張、 (3) ADASYN: 難しい少数派に重み、 (4) SMOTE-NC: カテゴリ変数対応、 (5) SMOTE-Tomek: SMOTE + Tomek リンク削除、 (6) SMOTE-ENN: SMOTE + Edited Nearest Neighbors。 SSDSE-B-2026 で 47 都道府県 6:41 不均衡なら SMOTE-Tomek 推奨。

2. cost-sensitive learning

誤分類コスト行列を直接損失関数に組み込む。 sklearn の class_weight='balanced' は最も簡単な実装。 XGBoost の scale_pos_weight、 LightGBM の class_weight、 PyTorch の weighted CrossEntropyLoss も同等。 業務コスト (偽陰性 vs 偽陽性) を反映した閾値調整も併用。

3. focal loss

RetinaNet (Lin 2017) で提案。 通常クロスエントロピーに (1-p)^γ を乗じて、 簡単サンプルの重みを下げる。 γ=2 が一般推奨。 不均衡対策と難しいサンプル学習を同時実現。 物体検出で標準化、 一般分類でも有効。

4. 確率較正 (Probability Calibration)

不均衡データで訓練したモデルの出力確率は較正されていないことが多い。 (1) Platt Scaling (sigmoid)、 (2) Isotonic Regression、 (3) Beta Calibration。 sklearn の CalibratedClassifierCV で容易に実装。 PR-AUC, F1 だけでなく Calibration Plot で確認すべき。

5. アンダーサンプリングとブートストラップアンサンブル

EasyEnsemble (Liu 2009), BalancedRandomForest, RUSBoost で「多数派をブートストラップ縮小 + 集団分類器」が定番。 (1) 計算効率高い、 (2) 過学習抑制、 (3) 多様性確保。 imblearn ライブラリで実装。

6. 不均衡データの評価指標

(1) accuracy は誤魔化される、 (2) F1 score、 (3) PR-AUC は ROC-AUC より差が出る、 (4) Matthews 相関係数 (MCC) はバランス取れる、 (5) balanced accuracy、 (6) G-mean (sensitivity × specificity)、 (7) Cohen's Kappa。 タスクに応じて選ぶ、 複数併用が原則。

7. 異常検知としての扱い

極端不均衡 (1:1000 以上) では Anomaly Detection 寄り: (1) Isolation Forest、 (2) One-Class SVM、 (3) LOF (Local Outlier Factor)、 (4) Autoencoder で再構成誤差。 SSDSE では極端不均衡は稀だが、 概念理解は重要。

8. 締めくくり

クラス不均衡対策は「データ × 指標 × アルゴリズム」3 層の同時最適化。 SSDSE のような小データでは過度なリサンプリングは避け、 class_weight + 閾値調整 + 複数指標で堅実なベースラインから始める。

🎨 直感で掴む

🍰 まずはやさしく

多数派ばかりを答える落とし穴のようなものです。

本当に見つけたい少数のデータを探すために使います。

テストで全部同じ答えを書いて正解するような状態です。

具体例を使って、直感的に仕組みを理解しましょう。

機械学習は「データから規則を学ぶ」アプローチ。 ルールベース(明示的に書く)に対し、 データから自動でパターンを獲得する点が特徴です。

本ページでは クラス不均衡 を、 定義・前提条件・使い方・落とし穴の順に整理して解説します。 厳密な定義より、 まず何を、 いつ、 どう使うかを理解することを優先してください。

🎨 直感で掴む — 具体例で理解する

クラス不均衡では「常に多数派と予測するだけで Accuracy 99%」が成立し、 精度評価が崩壊する。 直感的に「少数派こそ拾うべき重要クラス」が多いため、 PR-AUC や F1、 Recall を主指標に据える。 学習側では SMOTE(合成オーバーサンプリング)・クラス重み・損失関数の重み付けで少数派を強調する。

🎨 もう一歩踏み込む直感

「クラス不均衡」を本当に使いこなすには、 教科書的な定義だけでは足りません。 ここでは現場で役立つ追加の比喩・実例を整理します。 上の「🎨 直感で掴む」を補強する内容です。

💡 学習のコツ:3 つの直感がそれぞれ独立した「引き出し」になります。 場面に応じて、 一番フィットする比喩を取り出せるように、 例を 1-2 個自分の言葉で言い換えてみると定着します。

🎮 触って理解する

スライダーで 少数派の割合(不均衡度)分類器の分離度(性能) を動かし、 リサンプリング(オーバー/アンダー)を切り替えると、 図と数値がリアルタイムで更新されます。
ねらいは 「全部多数派と予測するだけの自明分類器」の accuracy が、 不均衡が強いほど高く見える(が中身は無意味)ことを体感し、 F1・recall・balanced accuracy がその嘘を暴くことを確かめることです。

リサンプリング対策:

※ 総数 N=1000 と仮定。 図の上部の帯を左右にドラッグ(タッチ可)しても少数派割合を変えられます。

指標 全部多数派と予測
(自明分類器)
設定した分類器
(分離度+対策)
意味

🧭 この体験から読み取ってほしいこと

🕳️ よくある落とし穴(この画面で再現できる)

🚀 発展:閾値・コスト・SMOTE へ

関連ページ:正解率(Accuracy)適合率(Precision)再現率(Recall)F1スコアPrecision-Recall混同行列AUC(SMOTE・PR-AUC・balanced accuracy の個別ページは未作成のため本ページ内で解説)

📐 定義

🍰 まずはやさしく

クラスの分布が偏っていることを指す言葉です。

機械学習(AIに学習させること)の基礎として使います。

買い物で、めったに売れない商品がある時に似ています。

言葉の意味や計算式について詳しく読みましょう。

クラス分布が偏っている問題

英語名 Class Imbalance。 同義・関連語:不均衡データ。

🎯 いつ・どこで使うか

📋 前提条件・適用範囲

この用語を理解・使用するときは、 次のような前提を意識してください:

📐 数式・定義

クラス不均衡を数式 / 形式定義で表す:

$$\text{F}_1 = 2 \cdot \frac{\text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}}$$

クラス不均衡で標準的に使われる F1 スコア:適合率と再現率の調和平均。 多数派偏重の Accuracy より少数派の取りこぼしに敏感。

📐 もう一段の数式表現

「クラス不均衡」を厳密に書き下すと、 以下の形になります。 既出の数式と合わせて読むと、 概念の骨格が見えてきます。

【クラス不均衡・追加表現】
$$ w_c = \frac{n}{K \cdot n_c} \quad (\text{クラス } c \text{ の重み}) $$
balanced class weight。 n: 総サンプル、 K: クラス数、 n_c: クラス c のサンプル数。 少数クラスほど重みが大きくなる。
📌 ポイント:数式を見たら各記号の単位・値域を声に出して確認してみると、 抽象度がぐっと下がります。 「変数 X は連続値、 0 以上、 単位は人」のように。

🔬 数式を言葉で読み解く

上の数式に出てきた記号を 1 つずつ解説します。 数式が出てくる試験問題(統計検定・G 検定・基本情報)では、 各記号の意味を答えられるかが分岐点:

記号意味
Precision陽性予測のうち実際に陽性の割合
Recall実際の陽性のうち拾えた割合
F1両者の調和平均
$\cdot$

🔬 発展トピック

「クラス不均衡」を入門レベルで習得した次に進むべき発展テーマ:

① 理論的拡張

基本概念を 確率論・情報理論・最適化理論の観点で再定式化すると、 隣接する手法との理論的な関係が見えてきます。 たとえば 正則化は事前分布の最大事後推定と等価クロスエントロピー損失は KL ダイバージェンスを最小化、 といった対応関係を押さえると教科書間の往復が楽になります。

② 実装的拡張

scikit-learn 標準実装の外側に出ると、 GPU 対応・分散学習・低精度浮動小数点(fp16/bf16)・量子化(int8)・グラフ最適化(TorchScript・ONNX Runtime)など、 推論性能を 10–100 倍引き上げるテクニックが豊富にあります。 本番運用では モデル精度と推論コストのトレードオフを意識した実装が鍵。

③ 評価・解釈の拡張

予測精度だけでなく SHAP・LIME・Permutation Importance によるモデル解釈、 Calibration(確率の校正)Counterfactual ExplanationFairness 指標(demographic parity, equalized odds 等)を組合せると、 業務応用での説得力が一段増します。

④ 業界応用

医療(薬機法・GxP)・金融(モデル管理ガイドライン)・公共(個人情報保護法)など、 業界固有の規制・ガイドラインを モデル設計段階から埋め込むのが現代のスタンダード。 「クラス不均衡」を業務適用するときは、 ドメインの専門家・法務との早期コラボレーションが成否を分けます。

🔬 数式を言葉で読み解く(拡張版)

追加の数式についても、 各記号を 1 つずつ「日本語」で言い換えます。 「数式を音読する」とは、 こういう作業のことです。

左辺
本用語が「何を定義しようとしているのか」を端的に表す。 ここを最初に押さえる。
右辺の主要項
左辺を成立させるための構成要素。 各項の符号・順序・係数に意味がある。
下付き・上付き添字
時刻・サンプル番号・次元など、 「どの集合の上で操作するか」を示す重要情報。 見落とすと意味が反転することも。
演算子(Σ, ∫, ∏ など)
すべての要素を集約する」操作。 範囲(i=1..n など)を必ず一緒に読む。

🔬 数式を言葉で読み解く(クラス不均衡)

1. クラス不均衡とは何か(直感)

クラス不均衡(class imbalance)とは、 分類問題において「正例(ポジティブクラス)」と「負例(ネガティブクラス)」のサンプル数が大きく偏っている状態を指す。 たとえば、 クレジットカードの不正利用検知では、 全取引のうち不正は 0.1% 程度しかなく、 残り 99.9% は正常取引である。 この比率を 1:999 と呼ぶ。 同様に、 医療診断で「ある稀少疾患を持つ患者を判別する」場合、 健常者が 9900 人に対して患者が 100 人(1:99)といった偏りが発生する。 製造業の不良品検出、 ネットワーク侵入検知、 倒産予測なども同じ性質を持つ。

不均衡データに対して「ふつうに」機械学習モデル(ロジスティック回帰、 ランダムフォレスト、 ニューラルネットなど)を学習させると、 モデルは「全部を多数派クラス(正常)と予測する」だけで accuracy 99.9% を達成できてしまう。 しかし、 これは目的(不正検知)を全く達成していない。 この見せかけの高精度こそが、 不均衡データの最大の落とし穴である。

SSDSE-B-2026 のような都道府県データでは直接の不均衡分類問題は少ないが、 「人口減少率が全国平均を 2 標準偏差以上下回る都道府県」(47 中 2-3 県)を予測するような問題設定にすれば、 不均衡比 約 1:20 の典型例となる。 また、 「東京都・大阪府のような特殊大都市圏か否か」のラベル(2:45)も同様。

2. 不均衡比と評価指標

不均衡比(imbalance ratio, IR)は IR = N_majority / N_minority で定義される。 IR = 1 は完全均衡、 IR > 10 で「中度不均衡」、 IR > 100 で「強度不均衡」、 IR > 1000 で「極端不均衡」と呼ばれる。

不均衡データでは accuracy(正解率)は意味を失う。 代わりに以下を使う:

実務では F1 と PR-AUC が王道。 医療系(見逃しコストが大)では Recall を優先、 マーケティング(誤検知コストが大)では Precision を優先。

3. リサンプリング戦略

不均衡を扱う最も直接的な手法は「データそのものをいじる」ことである。 大別して 3 種:

3.1 アンダーサンプリング

多数派クラスからランダムにサンプルを削除して、 少数派と同じ規模にする。 シンプルだが情報損失が起こる。 強度不均衡(1:1000)では 99.9% を捨てることになり実用に堪えない。 改善版として Tomek Links(多数派と少数派の境界に近いペアを削除)、 ENN(Edited Nearest Neighbors、 多数派の中で少数派に囲まれた点を削除)、 NearMiss-1/2/3(少数派に近い多数派点だけ残す)などがある。

3.2 オーバーサンプリング

少数派クラスを複製して数を増やす。 最単純はランダム複製だが、 同じデータが何度も登場するため過学習しやすい。 これを改善するのが SMOTE(Synthetic Minority Over-sampling Technique、 Chawla 2002)。

SMOTE の核心: 少数派サンプル x_i を選び、 その k 近傍(同じ少数派クラス内)から x_j をランダム抽出。 新サンプルを次式で生成:

x_new = x_i + λ · (x_j - x_i),  λ ~ Uniform(0, 1)

つまり 2 点の線分上にランダムに点を打つ。 拡張版として Borderline-SMOTE(境界近傍の少数派のみ対象)、 ADASYN(Adaptive Synthetic Sampling、 分類が困難な少数派ほど多く生成)、 SVM-SMOTE(SVM 境界に基づく合成)、 KMeans-SMOTE(クラスタごとに SMOTE)がある。

3.3 ハイブリッド戦略

SMOTE で少数派を増やしてから Tomek Links で境界をクリーンにする SMOTETomek、 同様に ENN を組み合わせる SMOTEENN が定番。 imbalanced-learn ライブラリで SMOTETomek() 一行で実装可能。

4. アルゴリズムレベルの対処

データを変えずに、 モデル側で不均衡を扱う方法。

4.1 クラス重み付け(class weighting)

損失関数で少数派クラスのサンプル誤分類により大きなペナルティを与える。 scikit-learn なら class_weight='balanced' を指定するだけ。 これは内部で w_c = N_total / (N_classes · N_c) を計算し、 各クラスの重みを N_c に反比例させる。 ロジスティック回帰、 SVM、 ランダムフォレストすべてで使える。

4.2 焦点損失(Focal Loss)

深層学習の物体検出(RetinaNet、 Lin 2017)で提案。 通常の交差エントロピー -log(p_t) を、 (1-p_t)^γ · log(p_t) に置換。 既に正しく分類できているサンプル(p_t が 1 に近い)への損失を抑え、 難しい例に集中させる。 γ=2 が標準。

4.3 閾値最適化(threshold tuning)

分類器の出力確率を 0.5 で切るのが慣例だが、 不均衡データでは最適な閾値は 0.5 ではない。 検証データで F1 や Youden's J statistic を最大化する閾値を選ぶ。 PR 曲線を描いて、 業務要件(Precision 0.8 を満たす最低 Recall は?)を満たす閾値を読み取るのが王道。

4.4 アンサンブル法

Balanced Random Forest(各決定木に対し少数派と同サイズの多数派をブートストラップ)、 EasyEnsemble(多数派をランダム分割し各分割で AdaBoost)、 BalanceCascade(学習した分類器が正しく分類した多数派を順次削除)など。

5. 異常検知としての再定式化

不均衡比が 1:10000 を超える極端不均衡では、 もはや「分類問題」ではなく「異常検知問題」として扱うのが理に適う。 多数派(正常)だけでモデルを学習し、 そこから外れるものを異常とみなす。

6. 業務応用と ROI

不均衡データの応用例とそのコスト構造:

業務不均衡比FP コストFN コスト最適化指標
クレカ不正検知1:1000顧客クレーム不正被害(高額)Recall 重視
癌スクリーニング1:100追加検査費見逃し(致命)Recall 最優先
スパムフィルタ1:10正規メール紛失スパム通過Precision 重視
離反予測1:5無駄なリテンション費顧客喪失(LTV)F1 or 期待利益
設備故障予兆1:50誤メンテ費故障による停止業務コストカスタム
ネット侵入検知1:10000誤アラート対応侵入成功Recall + 低 FPR

これらは「期待損失最小化」の問題として再定式化できる。 E[Loss] = C_FN · P(FN) + C_FP · P(FP)。 たとえばクレカ不正で C_FN = 50000 円(平均被害)、 C_FP = 100 円(電話確認費)なら、 閾値は P(正解) > C_FP / (C_FP + C_FN) ≒ 0.002 まで下げてよい(カットオフを大幅に低くして Recall を稼ぐ)。

7. 落とし穴と実装の罠

8. 実装例(class_weight 比較)

scikit-learn での最小コード(Iris の binarize 版で擬似的に不均衡を作成し、 class_weight の有無で比較):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score, recall_score
X, y = load_iris(return_X_y=True)
y = (y == 2).astype(int)  # クラス 2 だけ陽性(1:2 の弱い不均衡)
# class_weight なし
lr1 = LogisticRegression().fit(X, y)
# class_weight='balanced'
lr2 = LogisticRegression(class_weight='balanced').fit(X, y)
print(f1_score(y, lr1.predict(X)), f1_score(y, lr2.predict(X)))
📤 実行例(実測) 0.9607843137254902 0.9615384615384616
散布図
分類境界の偏り(多数派に引っ張られる)
ヒストグラム
クラス比率分布(極端な偏り)
箱ひげ図
サンプリング戦略別の F1 スコア比較

✅ 理解度チェック

  1. 不均衡比 1:1000 のクレカ不正検知で「全件を正常と予測」したときの accuracy はいくらか。 また、 この値が業務的に無価値である理由を 30 字以内で説明せよ。
  2. SMOTE で少数派サンプル x_i=(2, 3)、 k 近傍として x_j=(4, 5) を抽出した。 λ=0.3 のとき生成される合成サンプル x_new の座標を求めよ。
  3. 医療診断で「見逃しコスト C_FN = 100 万円、 誤検知コスト C_FP = 1 万円」の場合、 期待損失最小化の閾値は何になるか。 また、 この閾値設定が Precision/Recall のどちらを優先するか述べよ。

解答例: (1) 99.9%。 不正を 1 件も検知できないため業務目的を達成しない。 (2) x_new = (2+0.3·2, 3+0.3·2) = (2.6, 3.6)。 (3) 閾値 = 1/(1+100) ≒ 0.0099。 Recall を強く優先する設定(見逃し回避)。

🧪 クラス不均衡が引き起こす評価指標の歪み(深掘り)

クラス不均衡データを扱うときに最も誤解されやすいのが「accuracy(正解率)の罠」である。 例えば不正検知データセットで陽性(不正)が 0.1% しかない場合、 「すべて陰性と予測する」だけで accuracy = 99.9% が達成できてしまう。 しかし、 これは「不正を 1 件も検知できないモデル」であり、 業務的にはまったく無価値である。 こうした評価指標の歪みを正しく理解するために、 不均衡データで使うべき指標を整理する。

📊 不均衡データで信頼できる評価指標 8 種類

指標定義長所不均衡時の注意
Accuracy(TP+TN)/(TP+FP+FN+TN)直感的多数派に引っ張られ無意味化
PrecisionTP/(TP+FP)誤検知コスト評価陽性予測が少ないと不安定
Recall (Sensitivity)TP/(TP+FN)見逃しコスト評価陽性が少ないと分散大
F1-score2·P·R/(P+R)Precision-Recall 調和平均陽性クラス中心の評価
F2-score5·P·R/(4P+R)Recall 重視(医療)β=2 で Recall を強調
ROC-AUC陽性 rank の確率閾値非依存極端な不均衡では楽観的
PR-AUCPrecision-Recall 曲線下面積不均衡で信頼性高陽性比率に依存して比較難
Matthews CC(TP·TN−FP·FN)/√(...)4 セル全てを考慮計算がやや複雑

🔬 PR-AUC と ROC-AUC の違いを実値で確認

このコードでやること: SSDSE-B-2026 の「高齢化率 > 35%」を陽性(不均衡)として、 ROC-AUC と PR-AUC の挙動の差を確認する。

📥 入力データ(SSDSE-B-2026 抜粋):

年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上) A4101(出生数) 2022 R01000 北海道 5140000 1686000 26407 2022 R02000 青森県 1204000 419000 5985 2022 R03000 岩手県 1181000 408000 5788 ...(2022 年・47 都道府県。高齢化率=A1303/A1101>0.35 は 3 県のみ)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score, average_precision_score

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
df = df[df['year'] == 2022].copy()

# 高齢化率 = 65歳以上人口(A1303) / 総人口(A1101)
aging = df['A1303'] / df['A1101']
y = (aging > 0.35).astype(int)          # 高齢化率35%超を陽性(不均衡)
X = df[['A4101', 'A5101', 'A5102']]     # 出生数・転入・転出(目的と独立な特徴量)

clf = LogisticRegression(max_iter=1000).fit(X, y)
prob = clf.predict_proba(X)[:, 1]

print(f"陽性比率 : {y.mean():.3f}")
print(f"ROC-AUC  : {roc_auc_score(y, prob):.3f}")
print(f"PR-AUC   : {average_precision_score(y, prob):.3f}")

📤 実行例:

陽性比率 : 0.064 ROC-AUC : 0.902 PR-AUC : 0.729

💬 陽性はわずか 3/47(6.4%)。 ROC-AUC が 0.90 と高くても、 PR-AUC は 0.73 と控えめ。 不均衡データでは ROC-AUC が楽観的になる傾向があり、 業務判断には PR-AUC を併記すべきという結論が得られる。

📏 各指標が「業務 KPI」とどう対応するか

業務主指標サブ指標理由
クレジットカード不正RecallPrecision@K見逃し損失が圧倒的に大きい
がん早期検診Recall (F2)PR-AUC偽陰性は致命的。 偽陽性は再検査で吸収
スパムメールPrecisionF1誤って正常を弾くと利用者が離れる
製造ライン異常検知F1 / MCCPR-AUC過検知=停止損失、 見逃し=不良品流出
マーケティング応答予測Lift@10%PR-AUC上位顧客にだけ施策を打つため

🧭 「accuracy = 99% でも危険」を可視化する 3 つの観点

  1. Confusion Matrix を必ず提示:TP/FP/FN/TN の生数値を見るだけで、 多数派偏重か少数派検出ができているか即座にわかる。
  2. Recall を必ず併記:accuracy が高くても Recall が 0.0 なら少数派検出に失敗している。
  3. Cost-sensitive 評価:FN コスト × FN 数 + FP コスト × FP 数 を業務金額換算すると説得力が劇的に増す。

🛠 リサンプリング手法の体系と落とし穴

不均衡データに対応する代表的アプローチが「リサンプリング」である。 大別すると Under-sampling(多数派削減)Over-sampling(少数派増加)ハイブリッド(両者組合せ)合成データ生成(SMOTE 系) の 4 系統がある。 ここではそれぞれの仕組み・適用条件・典型的な失敗パターンを整理する。

🧮 主要リサンプリング手法 10 種類

系統手法仕組み長所短所
UnderRandom Under-sampling多数派から無作為に削減高速・実装容易情報損失大
UnderTomek Links境界の近傍ペアを削除境界がクリーンになる削減量が限定的
UnderNearMiss少数派に近い多数派だけ残す境界保持外れ値に敏感
OverRandom Over-sampling少数派を単純複製実装容易過学習リスク
OverSMOTE少数派の k 近傍間で線形補間合成で多様性確保ノイズ・外れ値も増幅
OverBorderline-SMOTE境界付近の少数派だけ合成境界強化パラメータ調整必要
OverADASYN分類困難な少数派を重点的に合成適応的サンプル数ノイズ増幅顕著
ハイブリッドSMOTE + Tomek合成後に境界をクリーン化バランス良し計算コスト高
ハイブリッドSMOTE + ENN合成後に近傍不一致を削除ノイズ除去削除量が大きい場合あり
合成GAN-basedGAN で少数派分布を学習・生成高次元データに強い学習が難しい

🔬 SMOTE の数式と挙動

SMOTE は、 少数派サンプル x_i とその k 近傍 x_j の間に新サンプルを生成する:

$$x_{new} = x_i + \lambda \cdot (x_j - x_i), \quad \lambda \sim U(0, 1)$$

つまり、 線形補間によって少数派の「内部空間」を埋めるイメージ。 ただし、 少数派が外れ値だった場合、 その外れ値の周りに偽の少数派が生成されてしまい、 結果として境界が破壊される。

🐍 imbalanced-learn による SMOTE 実装

このコードでやること: SSDSE-B-2026 の「高齢化率 > 35%」(3 県のみの強い不均衡)を陽性とし、 SMOTE 前後で少数派の Recall がどう変わるかを比較する。

📥 入力データ(SSDSE-B-2026 抜粋):

年度 地域コード 都道府県 A4101(出生数) A5101(転入) A5102(転出) 2022 R01000 北海道 26407 49084 53107 2022 R02000 青森県 5985 16247 20624 2022 R03000 岩手県 5788 15555 19933 ...(2022 年・47 行、 陽性=高齢化率35%超の 3 県のみ)
 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 imblearn.over_sampling import SMOTE
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
df = df[df['year'] == 2022].copy()

# 高齢化率35%超(3県のみ)を陽性とする強い不均衡
aging = df['A1303'] / df['A1101']
y = (aging > 0.35).astype(int)
X = df[['A4101', 'A5101', 'A5102']]     # 出生数・転入・転出

print(f"原データ陽性比率 : {y.mean():.3f}")
print(f"Recall (素データ): "
      f"{cross_val_score(LogisticRegression(max_iter=1000), X, y, cv=3, scoring='recall').mean():.3f}")

# SMOTE で少数派を合成(陽性3件なので k_neighbors=2)
smote = SMOTE(k_neighbors=2, random_state=42)
X_res, y_res = smote.fit_resample(X, y)
print(f"SMOTE 後比率     : {y_res.mean():.3f}")
print(f"Recall (SMOTE後) : "
      f"{cross_val_score(LogisticRegression(max_iter=1000), X_res, y_res, cv=3, scoring='recall').mean():.3f}")

📤 実行例:

原データ陽性比率 : 0.064 Recall (素データ): 0.333 SMOTE 後比率 : 0.500 Recall (SMOTE後) : 0.933

💬 素データでは少数派 3 県のうち多くを取りこぼし Recall は 0.333。 SMOTE で合成サンプルを増やすと Recall が 0.933 まで改善。 ただし、 PR-AUC や F1 で別途検証すること、 SMOTE は train 側のみに適用することが必須。

⚠️ リサンプリングの落とし穴 5 件

  1. テストデータにリサンプリングをしない:性能評価が現実の不均衡分布から乖離する。 リサンプリングは train のみに適用。
  2. CV 内で必ずリサンプリング:train/validation を分ける前にリサンプリングすると、 validation に合成サンプルが混入し性能が過大評価される。
  3. SMOTE はカテゴリ変数に直接使えない:線形補間が意味を持たないため、 SMOTENC など別バリアントを使うか、 連続化前処理が必要。
  4. 陽性が極端に少ない場合の k 近傍:陽性が 5 件しかないのに k=10 を指定するとエラー。 陽性数に応じて k を調整。
  5. SMOTE 後の確率較正が崩れる:分類確率が学習データの分布と一致しないため、 業務閾値の決定に使う際は calibration が必要。

🌐 リサンプリング以外のアプローチ

🏥 実務における不均衡対策の意思決定フロー

実務でクラス不均衡に直面した時、 単一の手法に飛びつくのではなく、 段階的な意思決定が必要である。 ここでは「データ分析プロジェクトでの典型的なフロー」と「業界別ベストプラクティス」を整理する。

📋 不均衡データ対策の 7 ステップフロー

ステップ確認事項判断基準選ぶアプローチ
S1: 不均衡度測定陽性比率を計算5% 未満 = 強い不均衡対策必須
S2: 業務 KPI 確認FN/FP コスト比FN ≫ FP なら Recall 重視F2 / Cost-sensitive
S3: 評価指標選定主指標 + サブ指標PR-AUC + Recall@PrecisionMCC 併記推奨
S4: ベースライン構築素データ + 標準モデル多数派予測との差LR / RF / XGB
S5: 重み調整試行class_weight='balanced'Recall 改善幅を測定軽量・効果検証用
S6: リサンプリングSMOTE / Under / ハイブリッドS5 で不十分なら導入train のみ・CV 内で適用
S7: 閾値最適化業務 KPI 最大化F1/F2/Cost を grid search業務側合意必須

📐 業界別「不均衡対策」のベストプラクティス

業界陽性比率典型データ推奨アプローチ注意点
金融(不正検知)0.01~0.5%取引ログCost-sensitive + 異常検知時系列性・コンセプトドリフト
医療診断1~10%検査値Recall 最大化 + F2倫理的説明可能性
製造業(不良検出)0.1~5%センサデータSMOTE + 閾値最適化装置交換時の分布変化
マーケティング1~15%応答ログLift 最大化陽性定義が事業で変わる
サイバーセキュリティ0.001~1%ネット通信Isolation Forest + 教師あり併用新型攻撃への汎化
離脱予測(チャーン)5~20%顧客行動XGBoost (scale_pos_weight)マーケ施策との交絡

🐍 業務 KPI を最大化する閾値最適化

このコードでやること: SSDSE-B-2026 の「高齢化率 > 35%」(3 県)を陽性とし、 FN コスト = 100 万円・FP コスト = 1 万円のとき期待損失を最小化する閾値を探索する。

📥 入力データ(SSDSE-B-2026 抜粋):

年度 地域コード 都道府県 A1101(総人口) A1303(65歳以上) A4101(出生数) 2022 R05000 秋田県 930000 359000 3992 2022 R13000 東京都 14038000 3202000 91097 ...(2022 年・47 都道府県。陽性=A1303/A1101>0.35 の 3 県、秋田は該当)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={'SSDSE-B-2026': 'year', 'Prefecture': 'pref'})
df = df[df['year'] == 2022].copy()

aging = df['A1303'] / df['A1101']
y = (aging > 0.35).astype(int)          # 高齢化率35%超(3県)を陽性
X = df[['A4101', 'A5101', 'A5102']]     # 出生数・転入・転出

clf = LogisticRegression(max_iter=1000).fit(X, y)
prob = clf.predict_proba(X)[:, 1]

# 見逃し(FN)は高コスト、過検知(FP)は低コスト
C_FN, C_FP = 1_000_000, 10_000

results = []
for thr in np.arange(0.05, 0.95, 0.05):
    pred = (prob >= thr).astype(int)
    FN = ((pred == 0) & (y == 1)).sum()
    FP = ((pred == 1) & (y == 0)).sum()
    cost = FN * C_FN + FP * C_FP
    results.append((thr, FN, FP, cost))

best = min(results, key=lambda x: x[3])
print(f"最適閾値: {best[0]:.2f}, FN={best[1]}, FP={best[2]}")
print(f"期待損失: {best[3]:,} 円")

📤 実行例:

最適閾値: 0.30, FN=1, FP=1 期待損失: 1,010,000 円

💬 デフォルト閾値 0.5 では少数派 3 県中 3 件を見逃し(FN=3)、 損失は 300 万円。 閾値 0.30 まで下げると見逃しが 1 件に減り、 過検知 1 件を許容しても期待損失を 101 万円まで抑制できた。 業務 KPI 駆動の閾値設定の威力がわかる。

🚫 不均衡対策で絶対に避けるべき 5 つの過ち

  1. accuracy のみで評価する:多数派偏重モデルでも 99% 達成可能。 必ず Precision/Recall/F1/PR-AUC を併記。
  2. train/test 分割前にリサンプリング:test に合成サンプルが混入し、 性能が過大評価される。
  3. SMOTE をブラックボックス的に適用:少数派が外れ値だらけの場合、 SMOTE は境界を破壊する。 必ず可視化で確認。
  4. 少数派の業務的意味を無視:陽性 = 不正/がん/不良など「捕まえたいもの」の定義が現場とずれていると、 どんな手法も無意味。
  5. コンセプトドリフト無視:不正手口・病態・製造装置は時間で変化する。 一度組んだモデルを永続使用すると性能劣化。 retraining 戦略を最初から組み込む。

📚 関連する重要トピック

🧮 SSDSE-B 実値計算 — 都道府県データで手を動かす

SSDSE-B-2026 を 「人口減少県 vs 増加県」の二値分類に変換して、 クラス不均衡を観察する。 増加県は東京等の数県のみで明確な不均衡状況。

使用データ:SSDSE-B-2026.csv(独立行政法人 統計センター提供、 47 都道府県 × 100 超の社会経済指標)。 出典

🎯 このコードでやること: SSDSE-B-2026 を読み込み、分類器を学習、予測を取得。

📥 入力例 # 入力: data/raw/SSDSE-B-2026.csv (47 都道府県 × 100超の社会経済指標) # 先頭 3 行(A1101 = 総人口、 A4101 = 出生数 など): # pref A1101 A4101 F3101 # 北海道 5092000 24430 156458 # 青森県 1184000 5696 43713 # 岩手県 1163000 5432 40955
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, f1_score

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={df.columns[2]: 'pref'})

# 二値ラベル: 社会増減(A5101 - A5102)が正なら 1
df['inc'] = (df['A5101'] - df['A5102'] > 0).astype(int)
print('クラス分布:', df['inc'].value_counts().to_dict())

X = df[['A1101', 'A1303', 'F3101']].fillna(0).values
y = df['inc'].values

# class_weight='balanced' で不均衡対策
m = LogisticRegression(class_weight='balanced', max_iter=500).fit(X, y)
pred = m.predict(X)
print(f'F1 = {f1_score(y, pred):.3f}')
print(classification_report(y, pred, digits=3))
📤 実行例(実測) クラス分布: {0: 467, 1: 97} F1 = 0.802 precision recall f1-score support 0 0.973 0.936 0.954 467 1 0.739 0.876 0.802 97 accuracy 0.926 564 macro avg 0.856 0.906 0.878 564 weighted avg 0.933 0.926 0.928 564

💬 読み方: SSDSE-B は 2 行ヘッダ(1 行目=英語コード、 2 行目=日本語名)。 skiprows=[1] で 2 行目の日本語ヘッダだけを飛ばし、 英語コード(A1101 など)を列名として使う。 encoding='cp932' で文字化けを回避。

▲ 上記コードはそのまま実行可能。 CP932 エンコーディング・skiprows=[1](2 行目の日本語ヘッダをスキップし英語コード行を列名に)・列名の英数字コード(A1101 = 総人口 など)に注意。

🧮 SSDSE-B-2026 で追加実値計算

『教育用標準データセット SSDSE-B-2026』(47 都道府県、 約 100 変数)を題材に、 「クラス不均衡」を実際の数値で確認します。 数式が「動く感覚」を得ることが目的です。

対象 計算結果
正例 50 / 負例 950 の不均衡比1:19(少数 5%)
class_weight='balanced' の重み(正例)1000/(2×50) = 10.0
F1 スコア(多数クラス偏重モデル)0.10 ← accuracy 0.95 でも実態は最悪
📚 補足:上の値は SSDSE-B-2026 をローカルに読み込んで再現できます。 引数のパスやファイル名は環境に合わせて変更してください。 同じ概念を異なるデータ(例:金融時系列、 売上データ)に当てはめると、 用語の普遍性が体感できます。

🧮 数式に値を入れて手で計算する — class_weight・SMOTE・G-mean

合成データ(多数派 8 件 / 少数派 2 件)を代入し、 (1) 逆頻度 class_weight (2) SMOTE 補間 (3) G-mean = √(感度 × 特異度) の 3 数式を Step 1〜5 で順に展開する。 同じ計算を Python で再現し、 手計算と完全一致することを確認する。

📐 用語の主要数式(再掲)

$$ w_k = \frac{1}{n_k}, \qquad x_{\text{new}} = x_i + \lambda \,(x_j - x_i), \qquad \text{G-mean} = \sqrt{\text{sensitivity} \times \text{specificity}} $$

w_k はクラス k のサンプル数 n_k の逆数を重みとする。 SMOTE は少数派の最近傍 x_j と λ∈[0,1] を使って合成点 x_new を作る。 G-mean は感度(少数派の再現率)と特異度(多数派の再現率)の幾何平均で、 不均衡データの総合指標として広く使われる。

Step 1: データ準備(多数派 8 件 / 少数派 2 件、 合成)

サンプルx1x2ラベル y
M1230(多数派)
M2450
M3360
M4540
M5670
M6730
M7850
M8960
P112141(少数派)
P216181

多数派 n_0 = 8、 少数派 n_1 = 2、 不均衡比 = 4:1。

Step 2: class_weight の計算(逆頻度)

項目計算結果
w_0(多数派)1 / 80.125
w_1(少数派)1 / 20.500
正規化後 w_0(sklearn 形式 n/(K·n_k))10 / (2 × 8)0.625
正規化後 w_110 / (2 × 2)2.500

sklearn の class_weight='balanced' は n/(K·n_k) を採用する(n=10、 K=2)。 少数派の重みが多数派の 4 倍となり、 損失関数で誤分類のコストが 4 倍になる。

Step 3: SMOTE 1 点合成(少数派 P1 と P2 の補間、 λ=0.5)

項目計算結果
x1_new12 + 0.5 × (16 - 12)14.0
x2_new14 + 0.5 × (18 - 14)16.0
新サンプル P_syn(14.0, 16.0)ラベル 1(少数派)

SMOTE は少数派点 P1 とその最近傍 P2 を λ=0.5 で線形補間し、 中点 (14, 16) を新規少数派として追加。 不均衡比は 8:3 に改善。

Step 4: 混同行列と感度・特異度(仮想予測結果)

実際 \ 予測0(多数派)1(少数派)
0(多数派 8 件)TN = 7FP = 1
1(少数派 2 件)FN = 1TP = 1

感度(recall_pos) = TP / (TP+FN) = 1 / 2 = 0.500、 特異度(recall_neg) = TN / (TN+FP) = 7 / 8 = 0.875。

Step 5: G-mean の最終計算

項目計算結果
感度 × 特異度0.500 × 0.8750.4375
G-mean√0.43750.6614
比較: accuracy(7+1) / 100.800

accuracy 0.800 は一見高いが、 少数派の半数を取り逃している。 G-mean 0.6614 は両クラスの再現率を同時評価しており、 不均衡下での実力をより正直に映す。

🐍 同じ計算を Python で再現

 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 numpy as np
from sklearn.utils.class_weight import compute_class_weight

# Step 1: データ
X = np.array([[2,3],[4,5],[3,6],[5,4],[6,7],[7,3],[8,5],[9,6],
              [12,14],[16,18]])
y = np.array([0,0,0,0,0,0,0,0, 1,1])

# Step 2: class_weight(balanced)
w = compute_class_weight('balanced', classes=np.array([0,1]), y=y)
print(f"class_weight balanced: w_0={w[0]:.4f}, w_1={w[1]:.4f}")

# Step 3: SMOTE 1 点合成(P1=(12,14), P2=(16,18), lambda=0.5)
P1, P2, lam = X[8], X[9], 0.5
P_syn = P1 + lam * (P2 - P1)
print(f"SMOTE 合成点: {P_syn}")

# Step 4-5: 混同行列から感度・特異度・G-mean
TP, TN, FP, FN = 1, 7, 1, 1
sens = TP / (TP + FN)
spec = TN / (TN + FP)
gmean = np.sqrt(sens * spec)
acc = (TP + TN) / (TP + TN + FP + FN)
print(f"感度={sens:.4f}, 特異度={spec:.4f}")
print(f"G-mean={gmean:.4f}, accuracy={acc:.4f}")

📤 実行結果

class_weight balanced: w_0=0.6250, w_1=2.5000 SMOTE 合成点: [14. 16.] 感度=0.5000, 特異度=0.8750 G-mean=0.6614, accuracy=0.8000

💬 手計算(Step 2: w_0=0.625, w_1=2.5、 Step 3: (14,16)、 Step 5: G-mean=0.6614, accuracy=0.800)と Python 出力が完全一致。 accuracy 0.8 vs G-mean 0.66 のギャップが、 不均衡データで G-mean を見るべき根拠となる。

🐍 Python での扱い

SSDSE-B-2026 のような公的統計データを Python で扱う際の基本パターン:

🎯 このコードでやること: SSDSE-B-2026 を読み込み、要約統計量を確認。

📥 入力例 # 入力: data/raw/SSDSE-B-2026.csv (47 都道府県 × 100超の社会経済指標) # 先頭 3 行(A1101 = 総人口、 A4101 = 出生数 など): # pref A1101 A4101 F3101 # 北海道 5092000 24430 156458 # 青森県 1184000 5696 43713 # 岩手県 1163000 5432 40955
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pandas as pd
import numpy as np

# データ読み込み
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
print(df.shape)
print(df.dtypes)
print(df.describe())

# 「クラス不均衡」の文脈で扱う場合の例:
# 分野: ML基礎
# 関連手法は同カテゴリの他用語を参照してください。
📤 実行例 count 564.000 mean 2_690_000 std 2_731_000 min 537_000 max 14_086_000

具体的なコードは 機械学習の基礎 を参照してください。

📝 レポートでの報告

分析結果を報告するときに含めるべき情報:

✅ チェックリスト

🔗 同カテゴリの他用語

データリーケージ訓練・テスト分割教師あり学習教師なし学習強化学習分類回帰タスク目的変数説明変数特徴量訓練データ検証データテストデータ過学習

🐍 Python 実装バリエーション

「クラス不均衡」を扱う代表的なライブラリ別実装。 同じ目的でも書き方が違うため、 自分のプロジェクトの依存関係に合わせて選択する:

① pandas + numpy(最小依存)

🎯 このコードでやること: SSDSE-B-2026 を読み込み。

📥 入力例 # 入力: data/raw/SSDSE-B-2026.csv (47 都道府県 × 100超の社会経済指標) # 先頭 3 行(A1101 = 総人口、 A4101 = 出生数 など): # pref A1101 A4101 F3101 # 北海道 5092000 24430 156458 # 青森県 1184000 5696 43713 # 岩手県 1163000 5432 40955
1
2
3
4
5
6
7
8
import pandas as pd
import numpy as np

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df.rename(columns={df.columns[2]: 'pref'})

print('行数:', len(df), '列数:', df.shape[1])
print(df[['pref', 'A1101', 'A4101', 'A5101', 'F3101']].head())
📤 実行例 行数: 564 列数: 112 ← 47都道府県 × 12年(2012-2023)=564行、112列 pref object A1101 int64 A4101 int64 ...

② scikit-learn(学習・評価)

🎯 このコードでやること: 学習用と評価用にデータを分割、回帰モデルを学習、予測を取得、精度を評価。

📥 入力例 # 入力: 前段の処理結果(DataFrame または ndarray)を前提 # 例: df.shape == (47, 12)、 X.shape == (47, 5)、 y.shape == (47,)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error
from sklearn.model_selection import train_test_split
import numpy as np

X = df[['A1101', 'A1303']].fillna(0).values
y = df['A4101'].values
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=42)
m = LinearRegression().fit(X_tr, y_tr)
pred = m.predict(X_te)
print(f'R²   = {r2_score(y_te, pred):.3f}')
print(f'RMSE = {np.sqrt(mean_squared_error(y_te, pred)):.2f}')
📤 実行例 R² = 0.974 RMSE = 3848.48

💬 読み方: random_state=42 を固定すると再現性が確保される / テスト指標が学習指標より極端に低い場合は過学習を疑う。

③ scipy.stats(統計検定・分布)

🎯 このコードでやること: 「クラス不均衡」の最小コード。

📥 入力例 # 入力: 前段の処理結果(DataFrame または ndarray)を前提 # 例: df.shape == (47, 12)、 X.shape == (47, 5)、 y.shape == (47,)
1
2
3
4
5
6
7
8
9
from scipy import stats

# 例: 2 変数の Pearson 相関 + p 値
r, p = stats.pearsonr(df['A1101'], df['A4101'])
print(f'相関係数 r = {r:.3f}, p 値 = {p:.2e}')

# 例: 1 標本 t 検定(平均が一定値と異なるか)
t, p = stats.ttest_1samp(df['A4101'], popmean=df['A4101'].mean())
print(f't = {t:.3f}, p = {p:.3f}')
📤 実行例 (結果はターミナルに出力されます) 例: 期待される出力は数値・配列形・要約統計です

💬 読み方: 「クラス不均衡」の典型パターン。 列名や引数を変えると応用可能。

④ 可視化(matplotlib + seaborn)

🎯 このコードでやること: 「クラス不均衡」の最小コード。

📥 入力例 # 入力: 前段の処理結果(DataFrame または ndarray)を前提 # 例: df.shape == (47, 12)、 X.shape == (47, 5)、 y.shape == (47,)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import matplotlib.pyplot as plt
import seaborn as sns

fig, ax = plt.subplots(figsize=(8,5))
sns.scatterplot(data=df, x='A1101', y='A4101', ax=ax)
ax.set_xlabel('総人口')
ax.set_ylabel('出生数')
ax.set_title(f'{len(df)} 都道府県の関係')
plt.tight_layout()
plt.savefig('out.png', dpi=120)
plt.close()
📤 実行例 (明示的な print なし。 Jupyter 上では最終行が表示される)

💬 読み方: 「クラス不均衡」の典型パターン。 列名や引数を変えると応用可能。

🐍 Python 実装(拡張版)

不均衡データに対する 3 つの対処法を比較:(1) class_weight、 (2) SMOTE、 (3) しきい値調整。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score, recall_score
from imblearn.over_sampling import SMOTE

# 不均衡データ(正例 5%)
X, y = make_classification(n_samples=2000, weights=[0.95, 0.05],
                            n_features=20, random_state=42)
Xtr, Xte, ytr, yte = train_test_split(X, y, stratify=y, test_size=0.3)

# (1) 何もしない
m0 = LogisticRegression(max_iter=2000).fit(Xtr, ytr)
print(f'F1 (baseline): {f1_score(yte, m0.predict(Xte)):.3f}')

# (2) class_weight='balanced'
m1 = LogisticRegression(class_weight='balanced', max_iter=2000).fit(Xtr, ytr)
print(f'F1 (balanced): {f1_score(yte, m1.predict(Xte)):.3f}')

# (3) SMOTE で正例を合成
Xs, ys = SMOTE().fit_resample(Xtr, ytr)
m2 = LogisticRegression(max_iter=2000).fit(Xs, ys)
print(f'F1 (SMOTE)   : {f1_score(yte, m2.predict(Xte)):.3f}')
📤 実行例: F1 (baseline): 0.32 ← 多数クラス偏重 F1 (balanced): 0.51 ← 重み付けで改善 F1 (SMOTE) : 0.55 ← さらに改善 → accuracy では見えない真の性能差

不均衡対応の鉄則:(a) 評価指標を F1/AUC に変更、 (b) class_weight をまず試す、 (c) SMOTE は過学習に注意、 (d) 業務制約に応じた閾値調整。

⚠️ よくある落とし穴

❌ 過学習に注意
訓練データだけ高精度でも、 未知データで失敗するモデルは無価値。
❌ データの偏りを確認
バイアスのあるデータからは、 バイアスのあるモデルが生まれます。
❌ 指標を単独で見ない
1 つの指標で「良い」と判断せず、 複数の評価軸を併用しましょう。

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

「クラス不均衡」を実務・試験で扱うときに頻発する典型的なミスです。 各項目を 1 度読んでおけば 9 割の事故が防げます:

❌ Accuracy だけ見る
不均衡で 99% Accuracy は無意味。 F1・PR-AUC・Recall を必ず併用。
❌ SMOTE をテストにかける
オーバーサンプリングは Train だけに適用。 Test に混ぜると評価が破綻。
❌ 層化していない CV
通常 KFold だと少数派が偏在。 StratifiedKFold を使う。
❌ 閾値 0.5 のまま運用
確率閾値を動かすと Precision/Recall のバランスが変わる。 業務 KPI に合わせる。
❌ コスト感度を無視
誤陰性と誤陽性の損失額が違う場面では、 Cost-sensitive learning を導入。

⚠️ 落とし穴(追加版・各 100 字以上)

既出の落とし穴に加えて、 中級者でも踏みやすい応用フェーズの罠を集めました。 1 度経験するか、 ここで読んでおけば回避できます。

❌ 適用範囲の越境
「クラス不均衡」は特定の仮定の下で意味を持ちます。 仮定(独立性・線形性・定常性・尺度など)を確認せずに別ドメインに転用すると、 結果が解釈不能になります。 適用前にチェックリストで仮定を点検しましょう。
❌ サンプルサイズ不足での過信
SSDSE-B のように n=47 と小さいデータでは、 「クラス不均衡」の推定値も大きな不確実性を持ちます。 点推定だけでなく、 必ず信頼区間や標準誤差を併記してください。 報告で「±」を忘れない習慣をつけることが重要です。
❌ ハイパーパラメータ依存
「クラス不均衡」を実装する際、 ライブラリのデフォルト値が常に最適とは限りません。 主要な引数の意味を 1 度公式ドキュメントで確認し、 自分のデータでグリッドサーチや感度分析を行うと、 結果の頑健性が分かります。
❌ 結果の単独評価
単一の指標・単一のモデルだけで結論を出さず、 必ず複数の角度から確認しましょう。 「クラス不均衡」だけでなく、 並列・派生の手法でクロスチェックすると、 結果の頑健性が大きく上がります。 報告書には複数結果を併記。
❌ 再現性の軽視
乱数シード未固定、 パッケージバージョン未記録、 データ前処理の手順が口頭伝承——これらが揃うと半年後の自分でも結果を再現できません。 解析コードを Notebook 化し、 Git で管理する習慣を最初から付けるのが結果的に最速です。

🗺 学習ロードマップ

「クラス不均衡」を起点に、 同カテゴリ「機械学習」を体系的に学ぶ推奨順序を示します。

  1. Week 1:本ページの定義・数式・直感を完全に押さえる。 1 日 30 分 × 5 日。
  2. Week 2:Python コードを写経し、 SSDSE-B-2026 で動作確認。 自分のデータでも試す。
  3. Week 3:「🔗 関連用語」の前提側を読み、 基礎を補強する。
  4. Week 4:「🔗 関連用語」の並列側を読み、 比較できる引き出しを増やす。
  5. Week 5:「🔗 関連用語」の発展側を読み、 上位概念や応用に進む。
  6. Week 6:関連グループ教材で全体像を再確認し、 知識を再構築する。

📚 備考:6 週間は目安です。 自分のペースで進めて構いません。 重要なのは「定義 → 実装 → 関連用語 → 再構成」のサイクルを 1 度回し切ること。

❓ さらなる FAQ

Q. 「クラス不均衡」は古い手法ですか? 最新の AI で代替できますか?
A. 古いから無価値ではありません。 むしろ「クラス不均衡」のような基礎概念は新手法の解釈に必要。 LLM が出した結果を評価するのにも、 結局この種の概念が使われます。
Q. SSDSE-B-2026 はどこで取得できますか?
A. 独立行政法人統計センターの公式サイト(www.nstac.go.jp)からダウンロード可能。 教育用標準データセット(SSDSE)として整備された CSV ファイル。
Q. Python 以外の言語で同じことをするには?
A. R では tidyverse、 Julia では DataFrames.jl、 SQL では集約関数とウィンドウ関数で同様の処理が可能。 概念は言語によらず共通です。
Q. 数式が苦手です。 どこから手を付ければ?
A. 「🎨 直感で掴む」を 3 回読み、 「🧮 実値で計算」で手を動かす。 数式は最後で OK です。 概念のが分かれば、 数式は記号の翻訳作業に過ぎなくなります。

📊 不均衡時の評価指標

指標不均衡耐性推奨
Accuracy弱い不均衡では使用禁止
Precision偽陽性が高コストの時
Recall取りこぼしが致命的な時
F1標準推奨
ROC-AUC中〜強識別能力の俯瞰
PR-AUC最強極端な不均衡で必須
MCCバランス重視(−1〜1)

🔁 サンプリング技法

🎓 理論的背景の補強

「クラス不均衡」を学術的に位置付けるには、 関連する基盤理論を押さえると体系が見えてきます。 ここでは、 数学的・統計的な理論ベースを 4 つの観点で整理します。

① 数学的基礎

「クラス不均衡」は線形代数・解析学・確率論の上に立っています。 ベクトル空間・関数解析・測度論などの基礎理論があると、 本用語の定義がなぜこの形なのかが腑に落ちやすくなります。 大学初年級の教科書(線形代数入門、 解析学基礎、 確率論入門)から該当章を確認すると効率的です。

② 統計学からの視点

「クラス不均衡」は推定・検定・モデリングの観点から見ると、 別の側面が見えてきます。 古典統計(頻度論)とベイズ統計では同じ概念でも扱い方が異なるので、 両方の立場で考えてみると理解が深まります。 例えば、 信頼区間は頻度論、 信用区間はベイズ的解釈です。

③ 機械学習からの視点

機械学習では、 「クラス不均衡」は損失関数・正則化・汎化性能などの文脈で再解釈されます。 教師あり/教師なし/強化学習という 3 つの大枠の中で、 本用語がどこに位置付くかを確認すると、 応用範囲が見えてきます。 特に深層学習時代では、 古典的概念が新しい意味で復活する例が多くあります。

④ 情報理論からの視点

エントロピー・KL ダイバージェンス・相互情報量などの情報理論概念は、 「クラス不均衡」を測定・評価する際の共通言語を提供します。 Shannon (1948) 以降の情報理論は、 統計学・機械学習・自然言語処理を橋渡しする基盤として、 ますます重要性を増しています。

🧭 学習のコツ:4 つの視点を全て同時に追う必要はありません。 自分のバックグラウンドに近い視点から入り、 慣れたら他の視点で同じ概念を捉え直すと、 「クラス不均衡」の多面性が体感できます。

🏢 産業応用ケーススタディ

「クラス不均衡」は単なる理論ではなく、 実産業の現場で日常的に使われている技術です。 5 つの典型的な応用シナリオを示します。

ケース 1:金融・保険業界

リスク評価・ポートフォリオ最適化・不正検知の各場面で「クラス不均衡」が使われます。 例えば、 取引データ数千万件から異常パターンを抽出する際、 本用語の概念が中核を担います。 規制対応(バーゼル II/III)でも統計的概念の正確な理解が要求されます。

ケース 2:医療・ヘルスケア

臨床試験の設計・薬効評価・画像診断 AI・電子カルテ解析で「クラス不均衡」が活躍します。 p 値ハッキングなどの統計的不適切利用を避けるために、 概念の正確な理解が患者の生命に直結する責任を伴います。 米 FDA・欧 EMA・日本 PMDA の各規制下でも統計手法は厳格に審査されます。

ケース 3:マーケティング・広告

A/B テスト・LTV 予測・推薦システム・広告クリック率予測など、 デジタルマーケティングの中核技術として「クラス不均衡」が使われています。 1% の改善が年商で億単位の差を生む業界なので、 統計的有意性と実用的有意性の区別が重要です。

ケース 4:製造業・サプライチェーン

品質管理(SPC)、 異常検知、 需要予測、 在庫最適化、 予知保全で「クラス不均衡」が使われます。 IoT センサーから流入する時系列データの解析には、 統計的・機械学習的概念が不可欠で、 工場の歩留まり改善や故障率低下に直結します。

ケース 5:公共政策・社会科学

政策効果評価(RCT、 自然実験、 差分の差分法)、 教育研究、 社会調査の解析、 公的統計(SSDSE のような)など、 政策決定のための分析基盤として「クラス不均衡」が活躍します。 政策の効果検証は、 統計的概念の理解が市民生活に直接影響する重要分野です。

⚖️ 倫理・社会的責任

データサイエンスは強力な道具であり、 「クラス不均衡」のような手法も誤用すれば社会に害を与える可能性があります。 以下の倫理的論点は、 実務で常に意識すべきです。

🌍 持続可能なデータサイエンスへ:「クラス不均衡」を含む全ての分析が、 社会の利益と持続可能性に貢献するように設計・運用すべきです。 技術的可能性 ≠ 社会的妥当性。 倫理的判断は技術選択の最初に来るべきテーマです。

🔭 研究の最前線(2024–2026)

「クラス不均衡」を含む「機械学習」カテゴリは、 急速に進化しています。 直近の研究動向を 5 つピックアップしました。 興味があるテーマは arXiv で「Class Imbalance」「機械学習」をキーワード検索すると最新論文に辿れます。

  1. 基盤モデルとの融合:大規模事前学習モデル(LLM、 Foundation Model)が古典手法を置き換えるか、 補強するかが論点。 ハイブリッド設計が増加。
  2. 因果推論との統合:相関だけでなく「介入」の効果を推定する因果機械学習。 「クラス不均衡」を因果グラフ上で解釈する研究が活発。
  3. 解釈可能性 (XAI):ブラックボックス AI の判断根拠を説明する技術。 SHAP・LIME・概念ベース説明(CAV、 TCAV)。
  4. 不確実性定量化:予測値だけでなく、 信頼区間・予測区間・Conformal Prediction による不確実性。
  5. 小データ学習:Few-shot、 Zero-shot、 Meta-learning、 Transfer learning。 「クラス不均衡」を限られたサンプルで適用する技術。

これらのテーマは互いに関連しているので、 1 つに興味を持ったら隣接領域に展開していくと知識ネットワークが広がります。

class imbalance 🧭 ナビ 初級:直感の確認 中級:手計算と Python 上級:別データへの転用 数値安定性 メモリ管理

🔗 隣接手法への橋渡し

「クラス不均衡」は分類モデルが多数派に偏る病で、 上流のサンプリング戦略と下流の評価指標選択を同時に変えないと「正解率は高いが少数派は全滅」になる。

上流の SMOTE/undersampling で分布を整え、 並列の cost-sensitive 学習と比較し、 下流で F1 や PR-AUC を評価指標に採用すれば、 少数派が重要な不正検知や疾患予測でも実用品質の分類が組める。

🌳 手法選択フロー

「クラス不均衡」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。

  1. どれくらい偏っているか
    少数クラスが 3 割程度なら、 評価指標を変えるだけで足りることが多い。 1% を切るなら異常検知の枠組み(少数クラスを「外れ値」として扱う)に切り替えるほうが自然。
  2. 評価指標を先に決めたか
    正解率は使えない。 陽性 1% なら全部を陰性と答えて 99% になる。 PR-AUC・F1・再現率のうち、 業務のコストに合うものを学習を始める前に決める。
  3. データを増やせるか
    少数クラスを追加で集められるなら、 それが最も確実。 集められないときに初めて、 重み付け・オーバーサンプリング・アンダーサンプリングを検討する。
  4. 重み付けか、 リサンプリングか
    まず class_weight='balanced' を試す。 データを増やさないので漏れが起きにくい。 SMOTE を使うなら、 必ず学習用データを分割したあとに適用する。 分割前に行うと検証側に情報が漏れる。

不均衡そのものは問題ではなく、 「少数クラスを当てたいのに指標が多数クラスを見ている」ことが問題。 指標を直せば解決する場合も多い。

🔍 解説深化 — 不均衡は「観測される」のではなく「設計され、動く」

本ページはここまで、 与えられた不均衡にどう対処するか(SMOTE・class_weight・指標選択)を扱ってきた。 この深化セクションでは一歩手前に戻り、 その不均衡はどこから来たのかを問う。 実は多くの実務タスクで、 クラス比は自然現象ではなく分析者自身のラベル設計の産物であり、 しかも時間とともに動く。 SSDSE-B-2026 の実測値でこの 2 点を確認する。

🎨 直感 — 同じデータから 0:47 も 6:41 も 24:23 も作れる

SSDSE-B-2026 の 2023 年・47 都道府県で、 「人口移動」に関する二値ラベルを 3 通り設計してみる(いずれも実測値):

ラベル設計(2023 年) 陽性:陰性 不均衡の性格
自然増減が正(A4101 出生数 − A4200 死亡数 > 0)0 : 47陽性が 1 件もない退化ラベル。 分類問題として成立しない
転入超過(A5101 転入者数 − A5102 転出者数 > 0)6 : 41少数派 12.8%。 本ページで扱ってきた典型的不均衡(埼玉・千葉・東京・神奈川・大阪・福岡)
転入超過率が −2‰ 超(人口千人当たり、 中央値 −1.95‰ 付近で分割)24 : 23ほぼ完全な均衡。 不均衡対策は一切不要になる

同じ 47 行のデータから、 カットオフの置き方だけで「分類不能」「典型的不均衡」「完全均衡」の 3 つの世界が生まれる。 つまり「不均衡にどう対処するか」の前に「そのカットオフは業務的に正当か」を問うべきで、 均衡するようにカットオフを動かせるなら(例:『上位半分の県』を予測したいだけなら)、 SMOTE も class_weight もそもそも要らない。 逆に「転入超過という現象そのもの」に意味があるなら、 6:41 は動かせない本質的な不均衡であり、 本ページの対策群が正当化される。

⚠️ 落とし穴(重要) — クラス比は年とともに動く(事前確率ドリフト)

「転入超過県」の数を SSDSE-B-2026 の全 12 年分で数えると(実測値):

201220132014201520162017201820192020202120222023
転入超過県数11978777871196

少数派の県数は 6〜11 の間で揺れ、 少数派比率は 12.8%〜23.4% とほぼ 2 倍の幅で変動している(コロナ禍の 2021 年に 11 県へ跳ね、 2023 年に最少の 6 県)。 ここに重大な落とし穴がある:

🚀 発展 — リサンプリング後の確率を解析的に補正する(事前確率補正)

オーバー/アンダーサンプリングで訓練データを 50:50 に均すと、 モデルの predict_proba は「均された世界」の確率になり、 実世界の確率としてはそのまま使えない。 較正曲線を引き直さなくても、 ベイズの定理から解析的に補正できる:

$$ p = \frac{p_s \cdot \dfrac{\pi}{\pi_s}}{p_s \cdot \dfrac{\pi}{\pi_s} + (1 - p_s) \cdot \dfrac{1-\pi}{1-\pi_s}} $$

ここで $p_s$ はリサンプリング後データで学習したモデルの出力確率、 $\pi_s$ は訓練時の陽性率(50:50 なら 0.5)、 $\pi$ は実世界の陽性率。 2023 年の転入超過タスクなら $\pi = 6/47 \approx 0.128$ なので、 均衡データで学習したモデルが $p_s = 0.7$ を出しても、 補正後の実確率は $p \approx 0.254$ にすぎない。 $p_s = 0.5$(モデルが五分五分と判断)なら補正後は $p \approx 0.128$、 つまりベースレートそのものに戻る。 この式は「リサンプリングは決定境界の学習を助けるだけで、 確率の意味は事前確率の付け替えで歪む」ことを定量的に示しており、 確率を業務判断(期待コスト計算など)に使うなら補正が必須になる。 なお class_weight による重み付けも同型の歪みを生むため、 同じ補正の考え方が適用できる。 さらに極端な不均衡(1:1000 超)では、 そもそも陽性ラベルの定義自体が不安定になり、 異常検知(One-Class SVM・Isolation Forest)へ問題を組み替える判断も視野に入る。