Harga rumah tidak selalu naik lurus terhadap luas: di kompleks tertentu harga per meter menurun setelah rumah melewati ukuran tertentu, dan hubungan seperti itu membuat garis lurus selalu meleset secara sistematis. Regresi polynomial menjawabnya dengan trik yang elegan — menambahkan fitur berpangkat (luas², luas³, …) sehingga kurva prediksi bisa melengkung, sementara mesin pembelajarannya tetap regresi linier yang sudah kita kuasai. Chapter ini membedah mekanika PolynomialFeatures (termasuk fitur interaksi yang jarang disadari pemula), membuktikan bahwa modelnya tetap “linier dalam parameter”, lalu memperlihatkan tanda tangan overfitting klasik saat derajat dinaikkan terlalu jauh.

Mekanika PolynomialFeatures #

Transformer PolynomialFeatures tidak menyentuh model sama sekali — tugasnya memperluas kolom fitur. Untuk satu fitur x dan derajat d, kolom baru x², x³, ..., xᵈ dibuat otomatis; untuk dua fitur (x₀, x₁) muncul juga fitur interaksi seperti x₀·x₁ dan x₀²·x₁, yaitu hasil kali antar fitur yang memungkinkan efek satu fitur bergantung pada nilai fitur lain (luas berpengaruh berbeda pada rumah yang jauh dari pusat kota). Jumlah kolom melonjak kombinatorial:

DerajatFitur dari 2 kolom asliDaftar fitur
12x0, x1
25x0, x1, x0^2, x0 x1, x1^2
39ditambah x0^3, x0^2 x1, x0 x1^2, x1^3
954pangkat dan campuran sampai total derajat 9

Sebuah fitur interaksi seperti luas × jarak memiliki tafsiran nyata: kontribusi luas termodifikasi oleh posisi rumah. PolynomialFeatures menawarkan opsi interaction_only=True bila kita hanya ingin suku hasil kali tanpa pangkat — berguna saat domain masalahnya memang perkalian silang.

Masih Regresi Linier #

Bagian yang paling sering membingungkan pemula: model ŷ = w₁x + w₂x² + w₃x³ + b disebut regresi linier. Kuncinya ada pada frasa linier dalam parameter. Yang diperlakukan garis lurus bukanlah hubungan x terhadap y, melainkan hubungan tiap parameter wⱼ terhadap ŷ: gandakan w₂ dan kontribusi w₂x² pun berganda lurus, tanpa w₂ masuk ke dalam pangkat, eksponen, atau pembagi. Setelah PolynomialFeatures membuat kolom x², kolom itu hanyalah fitur baru seperti sisa kolom lain — LinearRegression tidak tahu dan tidak perlu tahu bahwa kolom itu berasal dari kuadrat.

Konsekuensinya besar: seluruh perangkat section ini — least squares, koefisien, metrik, sampai regularisasi di chapter berikutnya — langsung berlaku tanpa modifikasi. “Kurva” polynomial dan “garis” linier adalah model yang sama secara matematis; bedanya hanya pada data yang dilihat model.

Contoh Kode: Empat Derajat dan Satu Jebakan #

File regresi-polynomial.py membangun sepuluh rumah sintetis dari kurva kuadratik berderau, lalu melatih regresi pada derajat 1, 2, 3, dan 9 sambil mencetak MSE latih dan jumlah parameter. Bagian kedua memperlihatkan isi get_feature_names_out untuk dua fitur asli — bukti langsung adanya fitur interaksi.

python
# Regresi polynomial: fitur berpangkat membuat kurva prediksi melengkung,
# sementara modelnya tetap regresi LINIER terhadap parameternya.

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import PolynomialFeatures

rng = np.random.default_rng(42)

# Sepuluh rumah dari kurva kuadratik berderau:
# harga = 0.4*luas^2 - 2.5*luas + 35 + derau.
# Luas dinormalisasi ke sekitar [-1, 1] agar kolom berpangkat tinggi
# tidak melonjak jauh secara numerik.
luas = rng.uniform(10.0, 60.0, size=10)
derau = rng.normal(loc=0.0, scale=6.0, size=10)
harga = 0.4 * luas**2 - 2.5 * luas + 35.0 + derau
X = ((luas - 35.0) / 25.0).reshape(-1, 1)

# Bagian 1: MSE latih untuk derajat 1, 2, 3, dan 9.
print("MSE latih untuk beberapa derajat PolynomialFeatures:")
print(f"{'derajat':>7} {'parameter':>10} {'MSE latih':>12}")
for derajat in [1, 2, 3, 9]:
    poly = PolynomialFeatures(degree=derajat, include_bias=False)
    X_pangkat = poly.fit_transform(X)
    model = LinearRegression().fit(X_pangkat, harga)
    mse = mean_squared_error(harga, model.predict(X_pangkat))
    print(f"{derajat:>7} {X_pangkat.shape[1] + 1:>10} {mse:>12.3f}")
print()
print("Derajat 9 punya 10 parameter untuk 10 titik: model menghafal data")
print("latih (MSE praktis nol), bukan mempelajari polanya.")
print()

# Bagian 2: dengan dua fitur asli, PolynomialFeatures juga membuat
# fitur interaksi (perkalian silang antar fitur), bukan hanya pangkat.
poly2 = PolynomialFeatures(degree=2, include_bias=False)
X_demo = np.array([
    [60.0, 5.0],    # luas 60 m^2, 5 km ke pusat kota
    [80.0, 12.0],
    [100.0, 8.0],
])
X_demo_pangkat = poly2.fit_transform(X_demo)
print("Fitur hasil transformasi (luas, jarak) pada derajat 2:")
print(poly2.get_feature_names_out(["luas", "jarak"]))
print("Matriks fitur baru (3 rumah x 5 kolom):")
np.set_printoptions(precision=3, suppress=True)
print(X_demo_pangkat)

Output yang Dihasilkan:

text
MSE latih untuk beberapa derajat PolynomialFeatures:
derajat  parameter    MSE latih
      1          2     4427.401
      2          3       11.263
      3          4        9.985
      9         10        0.000

Derajat 9 punya 10 parameter untuk 10 titik: model menghafal data
latih (MSE praktis nol), bukan mempelajari polanya.

Fitur hasil transformasi (luas, jarak) pada derajat 2:
['luas' 'jarak' 'luas^2' 'luas jarak' 'jarak^2']
Matriks fitur baru (3 rumah x 5 kolom):
[[   60.     5.  3600.   300.    25.]
 [   80.    12.  6400.   960.   144.]
 [  100.     8. 10000.   800.    64.]]

Bedah kode di atas baris demi baris:

  1. Baris 15–18 (data ternormalisasi): luas 10–60 m² digeser dan dibagi skala menjadi sekitar [−1, 1]. Tanpa ini, kolom luas⁹ akan bernilai hingga ratusan triliun dan pembelajaran numerik menjadi rapuh — normalisasi skala adalah kawan setiap fitur berpangkat.
  2. Baris 23–28 (loop derajat): untuk tiap derajat, fit_transform membuat kolom pangkat, LinearRegression dilatih pada kolom tersebut, dan MSE latih dihitung. Jumlah parameter dicetak lewat X_pangkat.shape[1] + 1 (kolom fitur ditambah intersep).
  3. Baris 30–31 (kesimpulan derajat 9): sepuluh parameter untuk sepuluh titik berarti sistem persamaan punya solusi yang menyentuh hampir semua titik data — MSE 0,000 pada data latih.
  4. Baris 36–44 (fitur interaksi): tiga rumah dengan dua fitur asli ditransformasi derajat 2. get_feature_names_out memperlihatkan lima kolom — termasuk luas jarak, perkalian silang yang tidak kita minta secara eksplisit.
  5. Baris 46–47 (matriks hasil): baris pertama (60, 5) menjadi (60, 5, 3600, 300, 25) — angka 300 adalah interaksi 60 × 5.

Derajat dan Bahaya Overfitting #

Bacaan tabel MSE latih itu menegur kita dengan sopan. Derajat 1 jelas keliru bentuk (MSE 4.427 — kurva kuadratik dipaksa jadi garis). Derajat 2 dan 3 turun ke kisaran 10 — sekitar besar derau yang memang kita tanamkan (variansi 6² = 36, terserap residu). Lalu derajat 9 menyentuh 0,000. Apakah itu berarti derajat 9 terbaik? Justru sebaliknya: MSE latih yang terlalu sempurna adalah gejala hafalan, bukan pemahaman. Model dengan jumlah parameter menyamai jumlah titik dapat melengkung melewati setiap titik data, termasuk deraunya — pola di titik baru justru akan ditebak buruk.

Persoalan yang sama sudah kita saksikan pada Chapter Overfitting dan Underfitting; kini penyebabnya terlihat dari sisi jumlah parameter. Cara sehat memilih derajat adalah validasi: pisahkan data uji (atau pakai cross-validation), lalu pilih derajat dengan MSE uji terendah — biasanya derajat kecil yang bentuknya cocok dengan domain. Kerangka pemilihan seperti ini akan kita latih tuntas di section evaluasi model.

Fleksibilitas derajat tinggi, seperti baru saja kita lihat, adalah pedang bermata dua: kurva bebas bergerak mengejar derau begitu parameternya banyak. Bagaimana kalau kita tetap ingin fleksibilitas itu tetapi memaksa koefisien berhati-hati? Jawabannya adalah regularisasi — menambahkan penalti pada besar koefisien — yang akan kita bahas tuntas di Chapter Regularisasi: Ridge, Lasso, dan Elastic Net.

Referensi Resmi #