ベースライン|機械学習の問題設定と評価分割
このページはプロモーション(広告)を含みます。
機械学習の問題設定と評価分割(中級・読む30分+演習35分)
この授業のゴール
- 分類・回帰・時系列のそれぞれで、多数派・平均・単純な規則・前回値などのベースラインを作れる
- ベースラインとモデルを、同じ評価データ・同じ指標で比べ、改善幅を報告できる
- 正解率が高くても、多数派の基準や事業上の損益と比べると価値がない場合を見抜ける
- ベースラインを訓練データだけで作り、評価データの情報を使っていないことを確認できる
仕事でどう使うか
「解約予測モデルの正解率は79%です」と言われたら、良いのか悪いのか判断できますか? 解約率が21%なら、全員を「継続」と予測するだけで正解率79%になります。数字の価値は、比べる相手があって初めて決まります。この比べる相手がベースライン(基準)です。
| 路線 | ベースラインが使われる成果物・意思決定 |
|---|---|
| DS | 分析報告の比較表。「多数派・単純な規則・現行運用・モデル」を同じ指標で並べ、改善幅で採用を判断する |
| ML | 実験管理の最初の行。パイプラインの不具合(列のずれ・漏洩)は、ベースラインと比べて「良すぎる/悪すぎる」で気づける |
| DX | 投資判断。単純な規則や現行の業務ルールで十分なら、モデル開発・運用の費用をかけない判断もできる |
| RS | 論文の比較実験。提案手法の効果は、適切に調整した既存手法・単純な手法との差で示す |
この授業では、目的変数と利用時点 で定義した解約予測を例に、正解率・適合率・再現率と、電話施策の損益の両方でベースラインと比べます。
前提
次の言葉を使います。
- 目的変数・予測時点・ラベル窓 → 目的変数と利用時点
- train / valid / test の役割(この授業では train で作り valid で比べる)→ 「学習と評価の分割」(有料版)
- 混同行列・適合率・再現率 → 「指標と交差検証」(有料版)。この授業でも式を確認します
- 標準誤差(推定値のばらつきの大きさ)→ 「標準誤差」(有料版)
- 基準モデル(PY11で
DummyClassifierとして登場)→ 「Pipeline」(有料版)
churn.csv には split 列があり、train 1800人・valid 600人・test 600人に分かれています。この授業では test を使いません(理由は 訓練・検証・テスト)。
身近な状況:「正解率79%」の報告
外部の分析会社から、解約予測の結果報告が届きました。
検証データ600人で正解率79.8%を達成しました。
あなたは検証データの中身を数えてみました。
| 人数 | 割合 | |
|---|---|---|
| 実際に解約(1) | 126人 | 21.0% |
| 継続(0) | 474人 | 79.0% |
| 合計 | 600人 | 100% |
「全員継続」と予測すると、474人が正解なので正解率は $474 \div 600 = 0.790$(79.0%)です。報告の79.8%との差は0.8パーセントポイント(%で表した2つの値の差。79.8%−79.0%)しかありません。
さらに、サポートチームが今使っている「問い合わせが3回以上の人に電話する」という現行の規則とも比べないと、モデルを導入する理由は説明できません。「モデルの数字」だけを見るのではなく、何もしない予測・単純な規則・現行運用を同じ表に並べることが、この授業の目標です。
直感的な説明:ものさしを先に置く
ベースラインは、モデルの性能を測るものさしのゼロ点です。健康診断で「体重60kg」と言われても、身長や前回の値がなければ良し悪しがわからないのと同じです。
ベースラインには「弱い順」に次のような段階があります。
- 何も考えない予測:全員に一番多いクラス(多数派)、全日に平均値。「このデータの難しさ」の最低ライン。
- 単純な規則・1列だけの予測:「問い合わせ3回以上なら解約」「7日前と同じ販売数」。業務の人が手作業でもできる水準。
- 現行の運用・前回のモデル:今すでに使っている方法。新しいモデルが置き換える相手。
モデルは少なくとも1〜2を超え、導入するなら3を超える必要があります。1を超えないモデルは、何かが壊れている(列のずれ、ラベルの誤り)可能性があります。逆に、1や2を大きく超えすぎる場合は、未来の情報が入る漏洩を疑います(漏洩の検出)。ベースラインは、良さだけでなく異常の検知器でもあります。
正確な定義:代表的なベースラインと評価指標
ベースラインとは、学習の工夫をほとんど使わずに作れる予測方法で、モデルと同じ訓練データで作り、同じ評価データ・同じ指標で評価するものです。
| 問題 | ベースライン | 作り方(訓練データだけを使う) |
|---|---|---|
| 分類 | 多数派 | 訓練で最も多いクラスを全員に予測(DummyClassifier(strategy='most_frequent')) |
| 分類(確率) | 事前確率 | 訓練の陽性割合(例:0.207)を全員の確率にする(strategy='prior') |
| 分類 | 単純な規則 | 業務知識による1〜2条件(例:問い合わせ回数 ≥ 3) |
| 回帰 | 平均・中央値 | 訓練の目的変数の平均(または中央値)を全件に予測 |
| 時系列 | ナイーブ予測 | 前日の実績(1日前)、または先週同じ曜日の実績(季節ナイーブ、7日前) |
| 共通 | 現行運用 | 今の業務ルール・前回のモデル |
分類の指標を、混同行列の記号で確認します。TP(真陽性:解約と予測して実際に解約)、FP(偽陽性:解約と予測したが継続)、FN(偽陰性:継続と予測したが解約)、TN(真陰性)を人数とします。
$$\text{正解率}=\frac{TP+TN}{TP+FP+FN+TN},\quad \text{適合率}=\frac{TP}{TP+FP},\quad \text{再現率}=\frac{TP}{TP+FN}$$
数値を代入します。規則「問い合わせ3回以上」は検証600人中70人に電話し、そのうち31人が実際に解約しました(TP=31、FP=39)。解約者は126人なので FN=126−31=95、TN=474−39=435 です。
- 正解率 $=(31+435)/600=0.777$
- 適合率 $=31/70=0.443$(電話した人の44%が本当に解約予定)
- 再現率 $=31/126=0.246$(解約予定者の25%に電話できた)
回帰では平均絶対誤差(MAE:Mean Absolute Error)をよく使います。$y_i$ を実績、$\hat{y}_i$ を予測、$n$ を件数として、
$$\text{MAE}=\frac{1}{n}\sum_{i=1}^{n}|y_i-\hat{y}_i|$$
例:実績が 100, 120, 80 個、予測がすべて 100 個なら、$(0+20+20)/3 \approx 13.3$ 個です。単位は目的変数と同じ(個)です。
段階付き例題:解約予測をベースラインと比べる
ステップ1:指標で比べる。多数派・規則・ロジスティック回帰を、同じ検証データ600人で評価します。report は予測(0/1の配列)を受け取って3つの指標と電話人数を表示する自作関数です。
import pandas as pd
from sklearn.dummy import DummyClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, precision_score, recall_score
df = pd.read_csv('/data/churn.csv')
cols = ['tenure_months', 'monthly_fee', 'support_calls', 'usage_hours']
tr = df[df['split'] == 'train']
va = df[df['split'] == 'valid']
y_va = va['churned']
def report(name, pred):
print(f"{name:<16} 正解率={accuracy_score(y_va, pred):.3f} "
f"適合率={precision_score(y_va, pred, zero_division=0):.3f} "
f"再現率={recall_score(y_va, pred):.3f} 電話する人数={int(pred.sum())}")
# 基準1:多数派(訓練で一番多いクラスを全員に予測)
dummy = DummyClassifier(strategy='most_frequent').fit(tr[cols], tr['churned'])
report('多数派', dummy.predict(va[cols]))
# 基準2:単純な規則(問い合わせ3回以上なら解約と予測)
report('規則 calls>=3', (va['support_calls'] >= 3).astype(int).values)
# モデル:ロジスティック回帰(確率0.5以上を解約と予測)
lr = LogisticRegression(max_iter=1000).fit(tr[cols], tr['churned'])
report('ロジスティック', lr.predict(va[cols]))
print('検証データの解約率', round(y_va.mean(), 3), '件数', len(va))
出力:
多数派 正解率=0.790 適合率=0.000 再現率=0.000 電話する人数=0
規則 calls>=3 正解率=0.777 適合率=0.443 再現率=0.246 電話する人数=70
ロジスティック 正解率=0.798 適合率=0.571 再現率=0.159 電話する人数=35
検証データの解約率 0.21 件数 600
正解率では多数派(0.790)が規則(0.777)より上です。しかし多数派は誰にも電話しないので、施策としては何もしないのと同じです。モデルは正解率0.798ですが、多数派との差0.008は、正解率の標準誤差 $\sqrt{0.79\times0.21/600}\approx0.017$ より小さく、偶然の範囲と区別できません。
ステップ2:お金で比べる。施策の前提を置きます(架空の値)。
| 記号 | 意味 | 値 |
|---|---|---|
| $V$ | 解約1件で失う粗利(売上から原価を引いた利益。売上そのものではない) | 12,000円 |
| $s$ | 電話した解約予定者を引き留められる割合 | 0.3 |
| $c$ | 電話1件の費用(人件費) | 500円 |
電話する人数を $N$、そのうち実際の解約予定者を $TP$ とすると、何もしない場合と比べた期待利益は $TP \times s \times V - N \times c$ です。規則なら $31 \times 0.3 \times 12000 - 70 \times 500 = 111600 - 35000 = 76600$ 円です。
import pandas as pd
from sklearn.linear_model import LogisticRegression
df = pd.read_csv('/data/churn.csv')
cols = ['tenure_months', 'monthly_fee', 'support_calls', 'usage_hours']
tr = df[df['split'] == 'train']; va = df[df['split'] == 'valid']
y = va['churned'].values
lr = LogisticRegression(max_iter=1000).fit(tr[cols], tr['churned'])
p = lr.predict_proba(va[cols])[:, 1]
V, s, c = 12000, 0.3, 500 # 解約1件で失う粗利(円)、引き留め成功率、電話1件の費用(円)
def profit(call): # call: 電話する人を1とした0/1配列
tp = int(((call == 1) & (y == 1)).sum()) # 電話した人のうち実際に解約する予定だった人
n_call = int(call.sum())
return tp * s * V - n_call * c, n_call, tp
for name, call in [('誰にも電話しない', (y * 0)),
('全員に電話', (y * 0 + 1)),
('規則 calls>=3', (va['support_calls'].values >= 3).astype(int)),
('モデル 確率>=0.5', (p >= 0.5).astype(int)),
('モデル 確率>=0.2', (p >= 0.2).astype(int))]:
yen, n, tp = profit(call)
print(f'{name:<14} 電話{n:>3}人 うち解約予定{tp:>3}人 期待利益 {yen:>8,.0f} 円')
出力:
誰にも電話しない 電話 0人 うち解約予定 0人 期待利益 0 円
全員に電話 電話600人 うち解約予定126人 期待利益 153,600 円
規則 calls>=3 電話 70人 うち解約予定 31人 期待利益 76,600 円
モデル 確率>=0.5 電話 35人 うち解約予定 20人 期待利益 54,500 円
モデル 確率>=0.2 電話235人 うち解約予定 83人 期待利益 181,300 円
結果の意味:確率0.5で区切ったモデルは、全員に電話するという単純な基準にも、現行の規則にも負けます。電話1件の費用(500円)に比べて引き留めの価値($0.3\times12000=3600$ 円)が大きいので、多めに電話するほうが得だからです。区切りを0.2に下げると181,300円になり、全員に電話(153,600円)を上回ります。どの基準と比べ、どの区切りで使うかで、同じモデルの価値が変わります。
操作して理解する:前提を変えて結論が変わるか
ステップ2のコードの前提を書き換えて、結論がどう変わるか予想してから実行してください。
- 電話費用
c = 500をc = 3000にすると? → 全員に電話すると $126\times3600-600\times3000=-1{,}346{,}400$ 円の大赤字になり、「誰にも電話しない」(0円)や、絞り込む規則・モデルの価値が上がります。 - 引き留め成功率
s = 0.3を0.05にすると? → 引き留め1件の価値が600円になり、どの方法でもほとんど利益が出ません。モデルを良くするより、施策自体を見直すべきという判断になります。 - 区切りを
0.2から0.14付近に変えると? → 電話の損益がちょうどゼロになる確率は $c/(sV)=500/3600\approx0.139$ です。確率がこれより高い人に電話すると、平均して得をします。
このように、ベースラインとの比較は指標と事業の前提の両方で行います。報告書には次の形の表を入れます。
| 方法 | 正解率 | 再現率 | 電話人数 | 期待利益 |
|---|---|---|---|---|
| 何もしない(多数派) | 0.790 | 0.000 | 0 | 0円 |
| 全員に電話 | 0.210 | 1.000 | 600 | 153,600円 |
| 現行規則 | 0.777 | 0.246 | 70 | 76,600円 |
| モデル(区切り0.2) | — | — | 235 | 181,300円 |
(モデルの区切り0.2の正解率・再現率は、上のコードに report を追加して自分で確かめてください。)前提($V, s, c$)は推定値なので、報告では値を変えた場合の結果も並べます。
発展:強い基準・確率の基準・差の大きさ
- 強い基準を使う:研究や実務の比較では、弱い基準だけを超えても説得力がありません。表データなら「訓練データで少し調整したロジスティック回帰」が良い基準になります。提案手法を丁寧に調整し、基準を既定値のまま比べるのは不公平です(調整の回数をそろえる)。
- 確率の基準:確率そのものを評価する場合、全員に訓練の陽性割合 $\bar{y}$ を出す予測が基準です。確率の誤差の2乗平均(ブライアスコア)は、この基準では $\bar{y}(1-\bar{y})$ に近い値になります。解約率0.21なら約0.166で、モデルはこれより小さくなければ確率として役に立っていません。
- 差の大きさを不確かさとともに示す:600人の評価で正解率の標準誤差は約0.017でした。0.8ポイントの差は「改善した」とは言えません。同じ評価データ上の2つの方法の比較なら、同じ人に対する正誤の違いを使う方法(ブートストラップなど)でより正確に評価できます。
- ベースラインが強すぎる問題:時系列では季節ナイーブが非常に強いことが多く、複雑なモデルが勝てないこともあります。それ自体が重要な発見で、「単純な方法で運用する」という結論も正当です。
よくある失敗
失敗1:不均衡なデータで、正解率だけを見て「高精度」と判断する
解約率21%のデータで「正解率79.8%」を成果として報告するのは誤りです。
| 方法 | 正解率 | 再現率 |
|---|---|---|
| 全員「継続」(多数派) | 0.790 | 0.000 |
| モデル | 0.798 | 0.159 |
陽性(解約)が少ないデータでは、陽性を1人も当てなくても正解率は高くなります。直し方:①最初に多数派の正解率(=多数クラスの割合)を計算して表の1行目に置く。②施策に関係する指標(再現率・適合率・期待利益)を並べる。③差が標準誤差より大きいかを確認する。
失敗2:ベースラインとモデルを、別のデータや別の指標で比べる
「モデルの正解率は検証データで0.798、規則の正解率は先月の全会員で0.75だった」のように、評価した会員も期間も違う数字を並べるのは誤りです。解約率が違う集団では、多数派の正解率そのものが変わるからです。
誤り:モデル=検証600人(解約率21.0%)、規則=全会員3000人(解約率20.4%)
正しい:モデルも規則も、同じ検証600人で計算する
同様に、モデルは再現率、規則は正解率、のように違う指標で比べるのも意味がありません。直し方:比較表のすべての行を、同じ評価データ・同じ指標・同じ前提(費用など)で計算する。評価データの行数と陽性割合を表の下に書く。
失敗3:ベースラインを評価期間のデータで作ってしまう
日別販売数の予測で、「評価期間の平均値を全日に予測する」基準を作ると、未来の水準を知っていることになります。
import pandas as pd, numpy as np
d = pd.read_csv('/data/demand.csv')
train, test = d.iloc[:-56], d.iloc[-56:] # 最後の56日(8週間)を評価期間にする
mae = lambda y, p: float(np.mean(np.abs(y - p)))
print('訓練の平均で予測(正しい):', round(mae(test['sales'], train['sales'].mean()), 2))
print('評価期間の平均で予測(誤り):', round(mae(test['sales'], test['sales'].mean()), 2))
print('訓練の平均', round(train['sales'].mean(), 1), '/ 評価期間の平均', round(test['sales'].mean(), 1))
出力:
訓練の平均で予測(正しい): 27.36
評価期間の平均で予測(誤り): 17.74
訓練の平均 149.8 / 評価期間の平均 172.8
評価期間(11〜12月)は販売数が多い時期で、その平均を使うと誤差が大きく下がります。この「強すぎる基準」と比べると、正しく作ったモデルが不当に悪く見えます。逆に、モデル側に同じ誤りがあれば不当に良く見えます。直し方:平均・中央値・陽性割合・規則のしきい値など、ベースラインの値も訓練データだけで決める(DummyClassifier も訓練データで fit する)。
まとめ
- ベースラインはモデルの価値を測るものさし。何も考えない予測・単純な規則・現行運用の順に置く。
- ベースラインも訓練データだけで作り、モデルと同じ評価データ・同じ指標で比べる。
- 不均衡なデータでは多数派の正解率が高い。再現率・適合率・期待利益を並べて判断する。
- 時系列では季節ナイーブなど強い基準があり、最も強い基準と比べるのが公平。
- 基準より大幅に良すぎる結果は漏洩を疑うきっかけにする。
用語
- ベースライン(baseline)
学習の工夫をほとんど使わない予測方法。モデルと同じ条件で評価し、改善幅を測る基準にする。
- 多数派予測(majority-class baseline)
訓練データで最も多いクラスを全員に予測する分類の基準。
- 季節ナイーブ予測(seasonal naive forecast)
1周期前(日別データで曜日の周期なら7日前)の実績をそのまま予測にする時系列の基準。
- 平均絶対誤差(MAE)(mean absolute error)
実績と予測の差の絶対値の平均。単位は目的変数と同じ。
- 期待利益(expected profit)
施策の成功率・価値・費用の前提のもとで、予測にもとづく行動が何もしない場合より平均していくら得かを表した金額。
よくある質問
なぜベースラインが必要なのですか? モデルの数字だけでは駄目ですか?
同じ「正解率80%」でも、多数派が50%のデータなら大きな改善、79%のデータならほぼ改善なしです。数字の意味は比べる相手で決まります。また、ベースラインより悪い・良すぎる結果は、パイプラインの不具合や漏洩の手がかりになります。
ベースラインと現行運用は同じものですか?
重なることもありますが、区別します。多数派や平均は「データの難しさ」を測る最低ライン、現行運用は「置き換える相手」です。導入の判断には現行運用との比較が必須で、現行運用が記録されていないなら、まず記録してもらうよう依頼します。
どのベースラインを選べばよいかわからないときは?
問題の種類ごとに最低1つ(分類なら多数派、回帰なら平均、時系列なら季節ナイーブ)と、業務の人に聞いた単純な規則を1つ置くのが出発点です。複数置いて、最も強いものと比べるのが公平です。
期待利益の前提(成功率0.3など)が不確かな場合はどうしますか?
前提を複数の値(例:0.1、0.3、0.5)に変えて同じ比較表を作ります。どの前提でもモデルが勝つなら結論は頑健です。前提によって順位が入れ替わるなら、まず小規模なA/Bテストで成功率を測る、という提案が適切です。
ベースラインに勝てなかったら、そのプロジェクトは失敗ですか?
失敗ではありません。「単純な規則で十分」とわかれば、開発や運用の費用を節約できます。勝てない理由(特徴量に情報がない、ラベルが不正確、問題の定義が施策と合っていない)を調べ、報告することが成果です。
条件が変わって陽性割合が50%になったら、何が変わりますか?
多数派の正解率は50%付近まで下がるので、正解率の比較が意味を持ちやすくなります。ただし、施策の費用と価値が変わらないなら、期待利益で比べるべきことは同じです。陽性割合は、評価データを変えるたびに表の下に書いておきます。
確認問題
問1 検証データ1000人のうち解約者が50人。モデルの正解率は95.5%だった。まず確認すべきことはどれか。
- ① 95%を超えたので本番に導入する
- ② 全員「継続」と予測する多数派の正解率95.0%と比べ、再現率や損益も確認する
- ③ 正解率をさらに上げるため特徴量を増やす
- ④ 検証データを増やせば正解率は必ず上がる
解答と解説
正解:②
陽性5%のデータでは多数派だけで95.0%になります。差は0.5ポイントで、施策に必要な指標も見る必要があります。
問2 日別販売数の予測で、最初に置くベースラインとして最も適切な組み合わせはどれか。
- ① 評価期間の平均と、評価期間の中央値
- ② 訓練期間の平均と、7日前の実績(季節ナイーブ)
- ③ 深層学習モデルと、勾配ブースティング
- ④ 前日の気温と、明日の気温
解答と解説
正解:②
訓練データだけで作れる平均と、曜日の周期を取り込む季節ナイーブが代表的なベースラインです。
問3 電話1件500円、引き留め1件の価値が $0.3\times12000=3600$ 円のとき、解約確率がいくら以上の人に電話すると平均して得になるか。
- ① 約0.04
- ② 約0.14
- ③ 0.5
- ④ 約0.86
解答と解説
正解:②
確率 $p$ の人に電話した期待利益は $3600p-500$ です。これが0以上になるのは $p \ge 500/3600 \approx 0.139$ のときです。
問4 ベースラインの多数派モデルを作るとき、DummyClassifier を fit するデータとして正しいものはどれか。
- ① 訓練データ
- ② 検証データ
- ③ テストデータ
- ④ 全データ
解答と解説
正解:①
ベースラインもモデルの一種なので、モデルと同じ訓練データで作り、評価データで評価します。
問5 新しいモデルが、単純な規則より大幅に良く、正解率99.9%になった。ベースラインの観点から適切な対応はどれか。
- ① 大成功として報告する
- ② 良すぎる結果なので、未来情報や目的変数の混入(漏洩)がないか確認する
- ③ ベースラインを削除して、モデルだけを報告する
- ④ 規則のほうが間違っているので、規則を作り直す
解答と解説
正解:②
基準から大きく離れた結果は、喜ぶ前に漏洩などの不具合を疑います。ベースラインは異常の検知器にもなります。
問6 正解率で多数派(0.790)に負ける規則(0.777)の評価として正しいものはどれか。
- ① 正解率が低いので必ず不採用にする
- ② 正解率は低くても、解約者を拾う再現率や施策の期待利益が多数派より大きければ、業務上は有用なことがある
- ③ 正解率の差は必ず統計的に有意である
- ④ 多数派は正解率が高いので、施策に使える
解答と解説
正解:②
多数派は誰にも電話しない予測です。施策の目的に合う指標で比べると評価が逆転することがあります。
次に学ぶこと
次は 訓練・検証・テスト で、訓練・検証・テストの3つのデータの役割を整理し、この授業で使わなかったテストデータをいつ・何回使うかを学びます。
指標の式や交差検証に不安があれば 「指標と交差検証」(有料版) へ、標準誤差は 「標準誤差」(有料版) へ戻ってください。良すぎる結果の原因調べは 漏洩の検出 で扱います。
キャリア学習:データサイエンティスト・機械学習エンジニア・DX推進・研究者を目指す人の学習アプリ。164モジュール・984授業を、ブラウザで動くSQLとPythonの演習で。基礎と各分野の最初のモジュールは無料。全部は2,980円の買い切り。
アプリを無料で開く有料版と無料版の違い