はじめに
普通の回帰は「だいたいこのくらい」という1点を予測します。しかし実務では、「予測はこのくらいだが、上振れ・下振れはどこまであり得るか」という**幅(不確実性)**を知りたい場面があります。
LightGBMはobjective="quantile"で分位点回帰ができます。alphaで指定した分位点(例:alpha=0.9なら「9割がこの値以下」という値)を予測するもので、複数のalphaで学習すれば予測区間が作れます。
この記事では、予測区間の作り方と、その区間が実際に当たっているか(カバレッジ)を確認します。
分位点回帰で予測区間を作る
ノイズの大きさがxとともに増えるデータを用意します(xが大きいほど散らばる)。alphaを0.05 / 0.5 / 0.95にした3つのモデルを学習し、0.05〜0.95を90%予測区間とします。
import numpy as np
import lightgbm as lgb
import matplotlib.pyplot as plt
rng = np.random.RandomState(0)
n = 5000
x = rng.uniform(0, 10, n)
noise_std = 0.2 + 0.25 * x # x が大きいほどノイズ大
y = np.sin(x) + 0.3 * x + rng.randn(n) * noise_std
X = x.reshape(-1, 1)
tr = np.arange(n) < 4000 # train/test split
params = dict(num_leaves=15, learning_rate=0.05, min_child_samples=50, verbose=-1)
# 分位点ごとに別々のモデルを学習する
models = {a: lgb.train(dict(params, objective="quantile", alpha=a),
lgb.Dataset(X[tr], y[tr]), num_boost_round=300)
for a in [0.05, 0.5, 0.95]}
grid = np.linspace(0, 10, 500).reshape(-1, 1)
q05, q50, q95 = (models[a].predict(grid) for a in [0.05, 0.5, 0.95])
plt.scatter(x[~tr], y[~tr], s=6, alpha=0.15, color="gray", label="test data")
plt.fill_between(grid.ravel(), q05, q95, alpha=0.25, color="#1f77b4",
label="90% interval (alpha=0.05 - 0.95)")
plt.plot(grid, q50, color="#1f77b4", lw=2, label="median (alpha=0.5)")
plt.xlabel("x"); plt.ylabel("y"); plt.legend(); plt.show()
xが大きいほど区間の幅が広がり、データの散らばりが大きくなる様子をそのまま捉えています。真ん中の線はalpha=0.5=中央値の予測です(平均ではありません)。
区間は当たっているか(カバレッジ)
予測区間は「作れる」だけでなく「当たっている」ことが大事です。テストデータの真値が[q05, q95]に入る割合(カバレッジ)を測ります。90%区間なら理想は0.90です。
pred = {a: models[a].predict(X[~tr]) for a in [0.05, 0.5, 0.95]}
yte = y[~tr]
inside = (yte >= pred[0.05]) & (yte <= pred[0.95])
print("90%区間のカバレッジ:", round(float(inside.mean()), 3), "(理想 0.90)")
for a in [0.05, 0.5, 0.95]:
emp = float((yte <= pred[a]).mean())
print(f" alpha={a}: 真値がその予測以下の割合={emp:.3f} (理想 {a})")
90%区間のカバレッジ: 0.881 (理想 0.90)
alpha=0.05: 真値がその予測以下の割合=0.067 (理想 0.05)
alpha=0.5: 真値がその予測以下の割合=0.537 (理想 0.5)
alpha=0.95: 真値がその予測以下の割合=0.948 (理想 0.95)
90%区間に実際に88.1%が入り、ほぼ狙い通りです。各分位点の実測割合も、指定したalphaに近い値になっています。有限データなので理想値とぴったりにはなりませんが、区間が意味のある形で機能していることが確認できます。
注意点
- 分位点ごとに別モデルが必要です。区間の上下+中央値なら3回学習します。多くの分位点が欲しいときは学習コストが増えます。
- **分位点交差(quantile crossing)**が起こり得ます。分位点を独立に学習するため、場所によって
q05 > q95のように上下が逆転することがあります(今回のデータでは0件でしたが、一般には起こります)。気になる場合は交差を後処理で補正します。 - ここで得られる区間はデータのばらつき(予測分布の広がり)を表すもので、モデルパラメータの信頼区間とは別物です。
alpha=0.5は平均ではなく中央値を最適化します。外れ値の影響を受けにくいのが特徴です。
まとめ
- LightGBMは
objective="quantile"+alphaで分位点回帰ができる - 複数の
alpha(例:0.05 / 0.5 / 0.95)を学習すれば予測区間が作れる - 区間はカバレッジ(真値が入る割合)で検証できる。今回は90%区間に88.1%が入った
- 分位点ごとに別学習が必要/分位点交差に注意