การถดถอยแบบ Robust

Basic

การถดถอยแบบ Robust | ใช้ Huber loss เพื่อต้านทานค่าออกนอกกลุ่ม

まとめ
  • วิธีการกำลังสองน้อยที่สุดไวต่อค่าออกนอกกลุ่มอย่างมาก แม้ข้อมูลผิดเพียงไม่กี่จุดก็ทำให้เส้นประมาณเบนได้
  • Huber loss ทำงานเป็นกำลังสองกับความคลาดเคลื่อนเล็กๆ และเป็นเส้นตรงกับความคลาดเคลื่อนใหญ่ๆ จึงลดผลกระทบของ outlier ได้แบบไดนามิก
  • การปรับค่า threshold \(\delta\) และโทษ L2 \(\alpha\) ช่วยควบคุมสมดุลระหว่างความทนทานกับอคติของโมเดล
  • เมื่อใช้ร่วมกับการปรับสเกลฟีเจอร์และ cross-validation โมเดลจะเชื่อถือได้มากขึ้นในข้อมูลจริง

ภาพรวมเชิงสัญชาติญาณ #

outlier เกิดได้จากความผิดพลาดของเซนเซอร์ การป้อนข้อมูล หรือเหตุการณ์ที่ผิดปกติ หากใช้กำลังสองน้อยที่สุด ค่าผิดพลาดจะถูกยกกำลังสองและลากเส้นประมาณให้เบี่ยงไป การถดถอยแบบ robust ลดบทลงโทษของจุดที่ห่างมากแต่ยังให้ความสำคัญกับจุดส่วนใหญ่ Huber loss เป็นฟังก์ชันยอดนิยมเพราะบริเวณศูนย์เป็นกำลังสอง (ให้ผลลัพธ์เหมือนเดิม) แต่ปลายทั้งสองเป็นเส้นตรงคล้าย absolute loss

สูตรสำคัญ #

ให้ residual \(r = y - \hat{y}\) และ threshold \(\delta > 0\) Huber loss มีนิยาม

$$ \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} $$

จึงมีความชันที่ค่อยๆ อิ่มตัว ทำให้จุดที่ห่างมากถูกจำกัดอิทธิพลโดยอัตโนมัติ

ทดลองด้วย Python #

ตัวอย่างต่อไปนี้แสดงรูปร่างของ Huber loss เทียบกับ loss แบบอื่น และเปรียบเทียบ OLS, Ridge, Huber เมื่อมี outlier

import japanize_matplotlib
import matplotlib.pyplot as plt
import numpy as np


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"quadratic loss $r^2$")
plt.plot(r_vals, np.abs(r_vals), "orange", label=r"absolute loss $|r|$")
plt.plot(r_vals, h_vals, "green", label=fr"Huber loss ($\delta={delta}$)")
plt.axhline(0, color="k", linewidth=0.8)
plt.grid(True, alpha=0.3)
plt.legend()
plt.xlabel("residual $r$")
plt.ylabel("loss value")
plt.title("เปรียบเทียบ quadratic / absolute / Huber loss")
plt.show()

พฤติกรรมเมื่อมี outlier #

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  # แทรก outlier หนึ่งจุด

plt.figure(figsize=(8, 6))
plt.plot(x1, y, "ko", label="data")
plt.xlabel("$x_1$")
plt.ylabel("$y$")
plt.legend()
plt.title("ข้อมูลที่มี outlier")
plt.show()
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 regression")

ridge = Ridge(alpha=1.0, random_state=0)
ridge.fit(X, y)
plt.plot(x1, ridge.predict(X), "orange", label="Ridge (α=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("ผลกระทบของ outlier ต่อเส้นประมาณ")
plt.grid(alpha=0.3)
plt.show()

วิเคราะห์ผลลัพธ์ #

  • Huber loss ทำตัวเหมือนกำลังสองบริเวณศูนย์ แต่กลายเป็นเส้นตรงเมื่อ residual ใหญ่ จึงป้องกันไม่ให้ค่าผิดปกติครอบงำ
  • เมื่อมี outlier เส้นของ Huber จะใกล้กับแนวโน้มจริงมากกว่า OLS และมักเบี่ยงน้อยกว่า Ridge
  • ปรับ epsilon (กำหนดช่วงที่ถือเป็นค่าปกติ) และ alpha แล้วใช้ cross-validation เพื่อหาค่าที่สมดุลระหว่างการทนทานกับความแม่นยำ

เอกสารอ้างอิง #

  • Huber, P. J. (1964). Robust Estimation of a Location Parameter. The Annals of Mathematical Statistics, 35(1), 73 E01.
  • 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.