K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

ロバスト回帰

中級

02.1.3

ロバスト回帰

最終更新 2020-02-26 読了時間 4 分
まとめ
ロバスト回帰は、残差の 2 乗ではなく Huber 損失のように「大きな残差ほど罰の増え方を抑える」損失で直線を当てはめ、外れ値 1 点に直線が引きずられるのを防ぐ手法です。Huber 損失はしきい値 \(\delta\) より小さい残差には二乗誤差、大きい残差には線形の誤差を使うので、普通の点は最小二乗法と同じに扱い、外れ値だけ影響を頭打ちにします。scikit-learn では HuberRegressor の epsilon がこのしきい値、alpha が L2 正則化の強さです。このページでは 30 点のうち 1 点だけを 500 に置き換えたデータで、最小二乗法・リッジ回帰・Huber 回帰の 3 本の直線を重ね、Huber だけが残り 29 点の傾きを保つ様子を確かめます。

先に 線形回帰 で、残差を 2 乗するため残差 10 の点が残差 1 の点の 100 倍の重みを持つことを確認しておくと、このページで損失の形を変える理由が分かります。

直感 #

センサーの読み取りミスで 30 点のうち 1 点だけ \(y = 500\) になったとします。最小二乗法はその 1 点の残差 400 を 2 乗して 160,000 と数えるので、他の 29 点の残差(それぞれ 10 以下)を全部足しても勝てず、直線は外れ値の方へ傾きます。Huber 損失は残差が \(\delta\) を超えたら 2 乗をやめて 1 次で増やすので、外れ値の罰は 400 の定数倍で止まり、29 点の多数派が直線の位置を決めます。残差が小さい点では二乗損失と同じなので、外れ値のないデータでは最小二乗法とほぼ同じ直線が得られます。

何が起きているか(ステップで見る) #

コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。

見るポイント:誤差の大きい点の重みを下げるだけで、直線は多数派に戻る。HuberRegressor の epsilon は「残差がどこから大きいと見なすか」のしきい値で、下のコードでは 3.0 にしています。

式で書くとどこで損失の形が切り替わるか #

しきい値 \(\delta\) を境に、内側は放物線、外側は直線になる 1 つの関数が Huber 損失です。残差 \(r = y - \hat{y}\) とし、しきい値 \(\delta > 0\) を用いると Huber損失は

$$ \ell_\delta(r) = \begin{cases} \dfrac{1}{2} r^2, & |r| \le \delta, \\\\ \delta \left(|r| - \dfrac{1}{2}\delta \right), & |r| > \delta. \end{cases} $$

\(|r| \le \delta\) の内側では通常の二乗誤差と同じ挙動、外側では \(|r|\) に比例して増えるため、残差 400 の外れ値でも損失は \(\delta \times 400\) 程度で止まります。導関数(影響関数)は内側で \(r\)、外側で \(\pm\delta\) の折れ線になり、1 点が直線を引っぱる力が \(\delta\) で頭打ちになります。2 つ目の式の \(-\frac{1}{2}\delta\) は、\(|r| = \delta\) で 2 本の式がなめらかにつながるための補正項です。

Pythonを用いた実験や説明 #

まず Huber 損失を二乗損失・絶対値損失と重ねて形を確かめ、次に 30 点のうち 1 点を 500 に置き換えたデータで HuberRegressor・Ridge・LinearRegression の直線を比べます。最初のブロックは描画と数値計算のライブラリを読み込むだけです。

1
2
import matplotlib.pyplot as plt
import numpy as np

Huber損失と関連損失の比較 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def huber_loss(r: np.ndarray, delta: float = 1.5):
    half_sq = 0.5 * np.square(r)
    lin = delta * (np.abs(r) - 0.5 * delta)
    return np.where(np.abs(r) <= delta, half_sq, lin)

delta = 1.5
r_vals = np.arange(-2, 2, 0.01)
h_vals = huber_loss(r_vals, delta=delta)

plt.figure(figsize=(8, 6))
plt.plot(r_vals, np.square(r_vals), "red", label=r"二乗損失 $r^2$")
plt.plot(r_vals, np.abs(r_vals), "orange", label=r"絶対値損失 $|r|$")
plt.plot(r_vals, h_vals, "green", label=fr"Huber損失 ($\delta={delta}$)")
plt.axhline(0, color="k", linewidth=0.8)
plt.grid(True, alpha=0.3)
plt.legend()
plt.xlabel("残差 $r$")
plt.ylabel("損失値")
plt.title("二乗・絶対値・Huber損失の比較")
plt.show()

外れ値を含むデータでの挙動 #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
np.random.seed(42)

N = 30
x1 = np.arange(N)
x2 = np.arange(N)
X = np.c_[x1, x2]
epsilon = np.random.rand(N)
y = 5 * x1 + 10 * x2 + epsilon * 10

y[5] = 500  # 外れ値を1点だけ挿入

plt.figure(figsize=(8, 6))
plt.plot(x1, y, "ko", label="data")
plt.xlabel("$x_1$")
plt.ylabel("$y$")
plt.legend()
plt.title("外れ値を含むデータ")
plt.show()
 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.linear_model import HuberRegressor, Ridge, LinearRegression

plt.figure(figsize=(8, 6))

huber = HuberRegressor(alpha=0.0, epsilon=3.0)
huber.fit(X, y)
plt.plot(x1, huber.predict(X), "green", label="Huber回帰")

ridge = Ridge(alpha=1.0, random_state=0)
ridge.fit(X, y)
plt.plot(x1, ridge.predict(X), "orange", label="リッジ回帰 (α=1.0)")

ols = LinearRegression()
ols.fit(X, y)
plt.plot(x1, ols.predict(X), "r-", label="最小二乗法 (OLS)")

plt.plot(x1, y, "kx", alpha=0.7)
plt.xlabel("$x_1$")
plt.ylabel("$y$")
plt.legend()
plt.title("外れ値を含むときの推定曲線の違い")
plt.grid(alpha=0.3)
plt.show()

実行結果の読み方 #

1 枚目の図では、緑の Huber 損失が原点付近で赤の二乗損失に重なり、\(|r| > 1.5\) から橙の絶対値損失と同じ傾きに変わります。3 枚目の図では、緑(Huber 回帰)が 29 点の×印の列をなぞる位置に来るのに対し、赤(最小二乗法)と橙(リッジ回帰)は \(y = 500\) の 1 点に引かれて上にずれ、2 本はほぼ重なります。リッジ回帰が最小二乗法と並ぶのは、L2 正則化が係数の大きさを抑えるだけで損失の形を変えないためです。epsilon を 1.35(既定値)まで下げると Huber の直線はさらに多数派に寄り、100 まで上げると赤に一致します。

使いどころと落とし穴 #

センサー値や手入力データのように、全体の 1〜10% に異常値が混ざるデータでは HuberRegressor を最小二乗法の代わりに最初から使う価値があります。外れ値が 10% を超えるなら、分位点回帰 の中央値回帰や RANSACRegressor のように外れ値を明示的に除く手法を検討します。落とし穴は 2 つあります。1 つ目はスケールで、epsilon は残差をスケール推定値で割った値に対するしきい値なので、特徴量の単位がばらばらだと意図したしきい値になりません。StandardScaler を前に置いてください。2 つ目は「ロバスト=万能」という誤解で、Huber 損失は \(y\) 方向の外れ値には強いものの、\(x\) 方向に離れた点(てこ点)には最小二乗法と同じく引かれます。

外れ値の影響 #

外れ値の割合を変えた場合、ロバスト回帰と OLS がどう異なるか比較できます。

参考文献 #

  • Huber, P. J. (1964). Robust Estimation of a Location Parameter. The Annals of Mathematical Statistics, 35(1), 73–101.
  • Hampel, F. R. et al. (1986). Robust Statistics: The Approach Based on Influence Functions. Wiley.
  • Huber, P. J., & Ronchetti, E. M. (2009). Robust Statistics (2nd ed.). Wiley.