2026年10月8日にscikit-learn 1.9.1のLDA/QDA、確率モデル、共分散推定、交差検証本文を再確認した。LDAはクラス間で共分散を共有し線形境界、QDAはクラスごとの共分散で二次境界を置く分類モデルで、事前確率・正則化・スケール・クラス不均衡で結果が変わる。確率出力や閾値を未見データで評価し、精度だけで解約介入や因果を決めない。
同じ2つの平均でも、分散や事前確率が違えば分類境界は変わります。LDAはクラスごとに共通の共分散、QDAはクラス別の共分散を使うGaussianモデルです。「曲がって見えるからQDA」と選ぶ前に、各クラスで共分散を推定できるだけのデータがあるか、未見データで何を評価するかを確認します。
30秒で要点
- LDAは共有共分散によって、2クラス間の得点差が説明変数の一次式になります。QDAは二次式となりえます。
- 事前確率と誤分類費用は別です。クラス比率を変えることと、見逃しを避けるしきい値の選択を混同しません。
- 2変数に対してあるクラスが2件だけなら、そのクラスの標本共分散は最大階数1。通常のQDAに十分とはいえません。
- 学習時の得点と未見評価を分け、確率の順位・しきい値での判定・校正をそれぞれ確かめます。
平均と共分散は何を表すか
平均はクラスの中心、共分散は各変数の広がりと組み合わせを表します。年齢と支出なら、それぞれのばらつきだけでなく、両者が一緒に動く方向も関わります。
表が収まらない場合は、横にスクロールできます
| 要素 | モデル内の役割 | 別途確かめること |
|---|---|---|
| 平均ベクトル | クラスの中心 | データ収集や対象者の違い |
| 共分散行列 | 広がりと変数間の関係 | 階数・標本数・外れ値・数値条件 |
| 事前確率 | 観測前のクラス比率 | 運用対象の母集団との一致 |
| 判別得点 | クラスを比較する量 | 同じ仮定で計算した得点か |
| 判定しきい値 | 行動を分けるルール | 見逃し・過剰対応の費用や処理能力 |
特徴量がp個ある場合、各クラスの標本共分散の階数は最大でmin(p, クラス別件数 - 1)です。pより多い件数があっても、特徴量の重複などで特異になることがあります。件数だけで安定した推定を保証するものではありません。
Gaussianの得点式からLDAとQDAを読む
クラスkの平均をμ_k、共分散をΣ_k、事前確率をπ_kとすると、クラス間で共通の定数を省いた得点は次の形です。
δ_k(x) = log(π_k) - log|Σ_k|/2 - (x - μ_k)ᵀΣ_k⁻¹(x - μ_k)/2
最後の項は共分散を考慮した距離、log determinantの項は分布の広がり、最初の項は事前確率を反映します。共通のΣを使うLDAでは、得点差の二次項が打ち消し合います。クラス別Σを使うQDAでは二次項が残ることがあります。これはGaussianの仮定から得た形であり、QDAが任意の非線形関係を表すという意味ではありません。scikit-learnのLDA/QDA解説
2クラスの同一モデル内では、クラス1の事後確率は 1 / (1 + exp(-(δ_1 - δ_0))) と書けます。モデルの確率が実際の頻度と合っているかは、別の評価が必要です。
架空例:共通分散なら境界は1つ
以下は既知の分布パラメータから計算する架空教材で、顧客データへの学習結果ではありません。クラス0の平均0、クラス1の平均2、両方の分散1、事前確率が各0.5とします。
得点差はδ_1 - δ_0 = 2x - 2となり、等しい誤分類費用で大きい得点を選ぶ境界はx=1です。事前確率を0.8/0.2へ変えると得点差にlog(0.2/0.8)が加わり、境界は約1.6931へ移ります。
表が収まらない場合は、横にスクロールできます
| 架空の設定 | 境界 | x=1でのクラス1確率 |
|---|---|---|
| 分散1/1、事前確率0.5/0.5 | 1 | 0.5 |
| 分散1/1、事前確率0.8/0.2 | 1.693147 | 0.2 |
事前確率を変えると母集団についてのモデルの想定が変わります。見逃しを減らしたいからという理由だけで比率を変更する前に、費用を反映した判定しきい値との違いを整理します。
分散を変えると、境界が2つになる例
平均0と2、事前確率各0.5はそのままに、分散をクラス0で1、クラス1で4とします。得点差は 3x²/8 + x/2 - 1/2 - log(2) です。ゼロになる点は約-2.5709と1.2376。間ではクラス0、両端側では分散の広いクラス1の得点が高くなります。
表が収まらない場合は、横にスクロールできます
| x | 共通分散1/1の得点差 | 別分散1/4の得点差 | 得点最大で選ぶクラス:LDA / QDA |
|---|---|---|---|
| -3 | -8 | 0.681853 | 0 / 1 |
| 0 | -2 | -1.193147 | 0 / 0 |
| 1.2 | 0.4 | -0.053147 | 1 / 0 |
| 2 | 2 | 1.306853 | 1 / 1 |
この形は分散と事前確率を固定した例です。QDAなら常に境界が2つ、常にLDAより正確、という一般則ではありません。
Python:訓練・確率出力・未見評価を分ける
次はscikit-learn 1.5.2を対象に、2変数の架空Gaussianデータを各クラス200件作り、層化して分割する例です。LDA/QDAの比較方法を示すための教材で、解約施策の効果や本番性能を表しません。設定を選ぶ評価用データと、最後に一度評価するテストデータは、実務ではさらに分離します。
import numpy as np
import sklearn
from sklearn.discriminant_analysis import (
LinearDiscriminantAnalysis, QuadraticDiscriminantAnalysis,
)
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, classification_report
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
assert sklearn.__version__ == "1.5.2", "This example specifies scikit-learn 1.5.2"
rng = np.random.default_rng(42)
X0 = rng.multivariate_normal([0, 0], [[1, 0.2], [0.2, 1]], size=200)
X1 = rng.multivariate_normal([1.5, 1], [[1.8, -0.3], [-0.3, 0.7]], size=200)
X = np.vstack([X0, X1])
y = np.repeat([0, 1], 200)
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y,
)
for label in [0, 1]:
covariance = np.cov(X_tr[y_tr == label], rowvar=False)
print("class/rank:", label, np.linalg.matrix_rank(covariance))
assert np.linalg.matrix_rank(covariance) == X.shape[1]
models = {"LDA": LinearDiscriminantAnalysis(),
"QDA": QuadraticDiscriminantAnalysis()}
for name, estimator in models.items():
model = make_pipeline(StandardScaler(), estimator)
model.fit(X_tr, y_tr)
proba = model.predict_proba(X_te)[:, 1]
prediction = (proba >= 0.5).astype(int)
print(name, "AUC", roc_auc_score(y_te, proba))
print(classification_report(y_te, prediction, zero_division=0))
標準化は訓練データで学習し、同じ変換をテストに適用します。ここでは処理順を示すために含めており、標準化だけで判別性能が上がることを示してはいません。理想的な非正則化モデルの座標変換と、数値計算・正則化の効果も分けて考えます。データ漏洩を避ける手順
旧教材の8件・少数クラス2件では、2変数のクラス別共分散を通常のQDAで安定して扱えませんでした。例を増やしただけで現実の妥当性が保証されるわけではなく、ここでも階数を確認し、異なるデータで評価する役割を示しています。
評価で答えたい問いを分ける
表が収まらない場合は、横にスクロールできます
| 問い | 確認するもの | それだけではわからないこと |
|---|---|---|
| 陽性を高い得点に並べられる? | ROC-AUC、目的に応じたPRの評価 | 特定しきい値での件数・費用、確率校正 |
| 見逃しや過剰対応は何件? | 混同行列、Recall、Precision | 別期間・別顧客層でも同じか |
| 予測確率0.2は約20%に対応する? | 未見データでの校正の確認 | 介入した結果や因果効果 |
| フォロー対象をどう選ぶ? | 検証データ上の費用・処理能力 | フォローそのものの効果 |
警告を消すためにtolだけを変えても、データが増えたり共分散が改善したりするわけではありません。階数、共線性、各クラスの件数、適切な正則化を検討します。縮小推定の選択肢はsolverや実装版で異なるため、仕様を確認します。QDA API
解約・継続のケースでは、予測時点を固定する
「翌月の解約を、その月が始まる前に予測する」という問いなら、予測時点までに取得できた特徴だけを使います。解約後の処理やフォロー実施の結果を学習特徴へ混ぜると、実際の予測時には使えない情報が入ります。
前処理・特徴選択・再標本化は訓練側で行い、同じ顧客が複数行ある場合や将来運用を想定する場合は、顧客単位・時系列の分割を検討します。上の教材の無作為分割を、そのまま運用データの分割方法にはしません。
モデル比較後は、検証用データで見逃しと対応過多の費用を比べてしきい値を選び、別の最終評価へ進みます。再学習の頻度はデータの到着、ラベルの確定遅延、変化の速さ、監視結果から決めます。週次という頻度だけを一般的な正解にしません。
練習3問
1. 特徴量が多く、各クラスの件数が少ない場合は?
まず階数と特徴量の重複を確認します。特徴選択・PCA・正則化LDAなどを候補にできますが、変換や選択を訓練側で学習し、同じ検証手順で比べます。特徴を減らすと問いも変わるため、単に警告が消えればよいとはしません。
2. 少数クラスのRecallが低い場合は?
評価件数と不確実性、しきい値、費用、母集団比率を確認します。再標本化を使うなら訓練側だけで行い、運用時の比率での評価や確率の扱いも確かめます。事前確率を変えることだけで全問題が解決するわけではありません。
3. LDAとロジスティック回帰は同じ?
2クラスで線形境界になる点は共通しますが、LDAはクラス条件付き分布、ロジスティック回帰は条件付き確率の形から出発します。推定手順や仮定は異なり、同じ係数や確率を返すとは限りません。
5分診断:目的・データ・改善方法を決める
表が収まらない場合は、横にスクロールできます
| 問い | 未確定なら先に行うこと |
|---|---|
| 何を、いつ、どの行動のために予測する? | ラベル・予測時点・費用・対応能力を記録する |
| 各クラスのデータと共分散を確認した? | 件数・欠測・階数・データ収集過程を確認する |
| 未見評価と監視の仕組みがある? | 分割、しきい値選択、最終評価、再学習条件を分ける |
参照したい一次資料
- scikit-learn: LDA/QDA:Gaussian得点、共有共分散、solverとshrinkage
- scikit-learn: QDA API:共分散・事前確率・階数警告の仕様
- scikit-learn: common pitfalls:前処理の一貫性とデータ漏洩
- scikit-learn 1.5.2: cross-validation:モデル選択と最終評価の分離