Outlier dan Robustness

最終更新: 3 分で読めます このページを編集

Outlier adalah observasi yang sangat menyimpang dari mayoritas data. Apa itu outlier tergantung masalah, distribusi, dan skala target. Di sini kita bandingkan OLS (loss kuadrat) dengan loss Huber pada data yang mengandung titik ekstrem.

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

1. Mengapa OLS sensitif terhadap outlier #

OLS meminimalkan jumlah kuadrat residual $$ \text{RSS} = \sum_{i=1}^n (y_i - \hat y_i)^2. $$ Karena residual dikuadratkan, satu titik ekstrem saja dapat mendominasi loss dan menyeret garis hasil fitting menuju outlier.


2. Loss Huber: kompromi antara kuadrat dan absolut #

Loss Huber memakai kuadrat untuk residual kecil dan absolut untuk residual besar. Untuk r = y - \hat y dan ambang $\delta > 0$:

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

Turunannya (pengaruh) $$ \psi_\delta(r) = \frac{d}{dr}\ell_\delta(r) = \begin{cases} r, & |r| \le \delta \ \delta,\mathrm{sign}(r), & |r| > \delta, \end{cases} $$ sehingga gradien terklip untuk residual besar (outlier).

Catatan: di HuberRegressor scikit-learn, ambang disebut epsilon (sesuai $\delta$ di atas).


3. Visualisasi bentuk loss #

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"kuadrat $r^2$")
plt.plot(r_vals, np.abs(r_vals),    "orange",label=r"absolut $|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("residual $r$")
plt.ylabel("loss")
plt.title("Kuadrat vs absolut vs Huber")
plt.show()

png


4. Apa yang terjadi bila ada outlier? (data) #

Buat masalah linear 2 fitur dan suntikkan satu outlier ekstrem pada y.

np.random.seed(42)

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

y[5] = 500  # satu outlier sangat besar

plt.figure(figsize=(8, 6))
plt.plot(x1, y, "ko", label="data")
plt.xlabel("$x_1$")
plt.ylabel("$y$")
plt.legend()
plt.title("Dataset dengan outlier")
plt.show()

png


5. Bandingkan OLS vs Ridge vs Huber #

  • OLS: sangat sensitif terhadap outlier.
  • Ridge (L2): mengecilkan koefisien; sedikit lebih stabil, tetap terpengaruh.
  • Huber: mengklip pengaruh outlier; garis kurang terseret.
from sklearn.linear_model import HuberRegressor, Ridge, LinearRegression

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

# Huber: epsilon=3 untuk mengurangi pengaruh outlier
huber = HuberRegressor(alpha=0.0, epsilon=3.0)
huber.fit(X, y)
plt.plot(x1, huber.predict(X), "green", label="Huber")

# Ridge (L2). Dengan alpha≈0, mirip OLS
ridge = Ridge(alpha=1.0, random_state=0)
ridge.fit(X, y)
plt.plot(x1, ridge.predict(X), "orange", label="Ridge (α=1.0)")

# OLS
lr = LinearRegression()
lr.fit(X, y)
plt.plot(x1, lr.predict(X), "r-", label="OLS")

# data mentah
plt.plot(x1, y, "kx", alpha=0.7)

plt.xlabel("$x_1$")
plt.ylabel("$y$")
plt.legend()
plt.title("Dampak outlier pada garis hasil fitting")
plt.grid(alpha=0.3)
plt.show()

png

Interpretasi:

  • OLS (merah) sangat terseret oleh outlier.
  • Ridge (oranye) sedikit meredakan namun tetap terpengaruh.
  • Huber (hijau) mengurangi pengaruh outlier dan mengikuti tren keseluruhan lebih baik.

6. Parameter: epsilon dan alpha #

  • epsilon (ambang $\delta$):
    • Lebih besar → mendekati OLS; lebih kecil → mendekati loss absolut.
    • Bergantung skala residual; lakukan standardisasi atau robust scaling.
  • alpha (penalti L2):
    • Menstabilkan koefisien; berguna pada kolinearitas.

Sensitivitas terhadap epsilon:

from sklearn.metrics import mean_squared_error

for eps in [1.2, 1.5, 2.0, 3.0]:
    h = HuberRegressor(alpha=0.0, epsilon=eps).fit(X, y)
    mse = mean_squared_error(y, h.predict(X))
    print(f"epsilon={eps:>3}: MSE={mse:.3f}")

7. Catatan praktis #

  • Penskalaan: jika skala fitur/target berbeda, makna epsilon berubah; lakukan standardisasi atau robust scaling.
  • Titik leverage tinggi: Huber robust untuk outlier vertikal di y, tidak selalu untuk titik ekstrem di X.
  • Pemilihan ambang: atur epsilon dan alpha (misalnya GridSearchCV).
  • Evaluasi dengan CV: jangan hanya melihat kecocokan pada data latih.

8. Ringkasan #

  • OLS sensitif terhadap outlier; garis hasil fitting dapat terseret.
  • Huber memakai kuadrat untuk error kecil dan absolut untuk error besar, mengklip gradien untuk outlier.
  • Menyetel epsilon dan alpha menyeimbangkan robustness dan kecocokan.
  • Waspada titik leverage; kombinasikan dengan inspeksi dan praproses bila perlu.