Regresi linear pada chapter sebelumnya bekerja baik karena harga rumah naik nyaris rata terhadap luas tanah. Namun pemilik Toko Kopi Kita menghadapi pola yang berbeda: makin besar biaya iklan harian, pendapatan memang naik, tetapi kenaikannya melandai — dari 5 ribu rupiah iklan tambahan di awal datang penambahan pendapatan besar, sementara di titik jenuh nyaris tidak terasa. Hubungan berbentuk lengkung seperti itu tidak bisa ditangkap garis lurus, dan di sinilah regresi polinomial masuk. Pada chapter ini kita melengkungkan model dengan PolynomialFeatures, membandingkan derajat 1, 2, dan 9, lalu menyaksikan sendiri bagaimana derajat yang terlalu tinggi justru merusak prediksi pada data baru.

Melengkungkan Garis dengan Fitur Turunan #

Ide regresi polinomial terasa nyaris curang karena sangat sederhana: modelnya tidak diganti sama sekali. Kita hanya menambahkan fitur turunan berupa pangkat dari fitur asli. Dari satu fitur x kita buat x dan x², lalu melatih LinearRegression yang biasa:

text
derajat 1: pendapatan = b0 + b1*x          garis lurus
derajat 2: pendapatan = b0 + b1*x + b2*x²  parabola (lengkung)
derajat 3: pendapatan = b0 + b1*x + b2*x² + b3*x³  lengkung berlekuk-lekuk

Perhatikan bahwa persamaan derajat 2 tetap linear terhadap parameter b0, b1, b2 — tidak ada parameter yang dipangkatkan. Karena itu LinearRegression scikit-learn yang sama masih bisa melatihnya; kita hanya memberi makan kolom-kolom baru. Makin tinggi derajat, makin lentur kurvanya, dan makin mudah model menempel pada data — kelenturan ini berguna, tetapi ada harganya:

DerajatBentuk kurvaKarakter
1Garis lurusKaku, hanya tren naik/turun
2ParabolaSatu lekukan; cocok untuk efek yang melandai
3-4Lengkung berlekukBeberapa belokan; mulai perlu kehati-hatian
9 ke atasSangat lenturMenempel hampir di tiap titik; risiko overfitting tinggi

Menjinakkan PolynomialFeatures #

Kelas PolynomialFeatures dari modul sklearn.preprocessing mengerjakan pembuatan fitur turunan tersebut. Kita pakai data 16 hari promosi Toko Kopi Kita — biaya iklan harian (ribu rupiah) dan pendapatan hari itu (ribu rupiah):

python
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

iklan = pd.DataFrame({
    "biaya_iklan": [0, 5, 10, 15, 20, 25, 30, 35,
                    40, 45, 50, 55, 60, 65, 70, 75],
    "pendapatan": [180, 235, 295, 345, 380, 430, 455, 495,
                   505, 540, 575, 545, 600, 555, 605, 565],
})

X = iklan[["biaya_iklan"]]
y = iklan["pendapatan"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3, random_state=42)

poly = PolynomialFeatures(degree=2, include_bias=False)
X_latih_poly = poly.fit_transform(X_latih)

print("Nama fitur turunan :", poly.get_feature_names_out())
print("Contoh hasil transformasi:")
print(pd.DataFrame(X_latih_poly[:5], columns=poly.get_feature_names_out()).to_string(index=False))

model = LinearRegression()
model.fit(X_latih_poly, y_latih)

b0 = model.intercept_
b1, b2 = model.coef_
print()
print("Persamaan: pendapatan = %.1f + %.2f*x + (%.4f)*x^2" % (b0, b1, b2))
print("Titik puncak kurva   : x = %.1f ribu rupiah" % (-b1 / (2 * b2)))

Output yang Dihasilkan:

text
Nama fitur turunan : ['biaya_iklan' 'biaya_iklan^2']
Contoh hasil transformasi:
 biaya_iklan  biaya_iklan^2
        55.0         3025.0
        40.0         1600.0
        45.0         2025.0
        10.0          100.0
        75.0         5625.0

Persamaan: pendapatan = 179.8 + 12.11*x + (-0.0917)*x^2
Titik puncak kurva   : x = 66.0 ribu rupiah

Mari kita telaah baris-baris kode di atas:

  1. PolynomialFeatures(degree=2, include_bias=False): parameter degree menentukan pangkat tertinggi fitur turunan; include_bias=False mencegah kolom bernilai konstan 1, karena LinearRegression sudah menghitung intersep sendiri lewat model.intercept_.
  2. poly.fit_transform(X_latih) menghasilkan matriks baru: kolom pertama biaya_iklan apa adanya, kolom kedua nilainya dikuadratkan — terlihat pada baris pertama, 55 menjadi 3.025. Kolom kedua inilah yang melengkungkan model.
  3. poly.transform(X_uji) (dipakai nanti) menerapkan transformasi yang sama tanpa mempelajari ulang — perbedaan fit_transform untuk data latih dan transform untuk data uji kita tegaskan lagi di bawah.
  4. -b1 / (2 * b2) mencari puncak parabola dari kalkulus paling dasar: turunan b1 + 2*b2*x bernilai nol di titik itu. Hasilnya praktis sekali: pendapatan harian berhenti naik sekitar biaya iklan 66 ribu rupiah — membelanjakan lebih dari itu hanya mengikuti hamburan, karena koefisien x² yang negatif menarik kurva turun.

Derajat 1 vs 2 vs 9: Perlombaan R² #

Sekarang kita adu tiga derajat pada data yang sama. Setiap model dilatih pada 11 hari latih lalu dinilai R² pada 5 hari uji yang tidak pernah dilihatnya:

python
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

iklan = pd.DataFrame({
    "biaya_iklan": [0, 5, 10, 15, 20, 25, 30, 35,
                    40, 45, 50, 55, 60, 65, 70, 75],
    "pendapatan": [180, 235, 295, 345, 380, 430, 455, 495,
                   505, 540, 575, 545, 600, 555, 605, 565],
})

X = iklan[["biaya_iklan"]]
y = iklan["pendapatan"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3, random_state=42)

print("Derajat | R2 latih | R2 uji")
for derajat in [1, 2, 9]:
    poly = PolynomialFeatures(degree=derajat, include_bias=False)
    X_latih_poly = poly.fit_transform(X_latih)
    X_uji_poly = poly.transform(X_uji)

    model = LinearRegression()
    model.fit(X_latih_poly, y_latih)
    print("%7d | %8.3f | %6.3f" % (derajat,
          model.score(X_latih_poly, y_latih),
          model.score(X_uji_poly, y_uji)))

Output yang Dihasilkan:

text
Derajat | R2 latih | R2 uji
      1 |    0.850 |  0.832
      2 |    0.983 |  0.991
      9 |    0.992 | -1.443

Tabel kecil ini memuat seluruh cerita chapter:

  1. Derajat 1 ketinggalan bentuk: R² latih 0,850 — garis lurus memang tidak bisa mengikuti efek melandai, jadi kesalahannya sistematik, bukan derau.
  2. Derajat 2 pas: R² uji justru naik ke 0,991. Satu lekukan parabola menangkap pola jenuh iklan dengan tiga parameter saja.
  3. Derajat 9 terlalu jauh: R² latih mentok di 0,992, tetapi R² uji jatuh ke -1,443. Angka negatif berarti prediksi pada data uji lebih buruk daripada sekadar menebak rata-rata y_latih terus-menerus — model telah menghafal derau (hari hujan, hari raya) yang menempel di 11 titik latih, lalu membawa hafalan keliru itu ke data baru. Inilah overfitting dalam wujud paling gamblang; bentuknya akan kita lihat pada grafik berikut.

Melihat Bentuk Ketiganya #

Angka-angka di atas lebih mudah dipercaya setelah kita lihat wujud kurvanya. Blok berikut menggambar sebaran data latih bersama prediksi ketiga model pada rentang biaya iklan 0 sampai 75 ribu rupiah:

python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures

iklan = pd.DataFrame({
    "biaya_iklan": [0, 5, 10, 15, 20, 25, 30, 35,
                    40, 45, 50, 55, 60, 65, 70, 75],
    "pendapatan": [180, 235, 295, 345, 380, 430, 455, 495,
                   505, 540, 575, 545, 600, 555, 605, 565],
})
X = iklan[["biaya_iklan"]]
y = iklan["pendapatan"]
X_latih, X_uji, y_latih, y_uji = train_test_split(X, y, test_size=0.3, random_state=42)

kurus = pd.DataFrame({"biaya_iklan": np.linspace(0, 75, 300)})
plt.figure(figsize=(7, 4.5))
plt.scatter(X_latih, y_latih, color="dimgray", label="data latih", zorder=3)
for derajat, warna in [(1, "tab:red"), (2, "tab:blue"), (9, "tab:green")]:
    poly = PolynomialFeatures(degree=derajat, include_bias=False)
    model = LinearRegression().fit(poly.fit_transform(X_latih), y_latih)
    plt.plot(kurus, model.predict(poly.transform(kurus)), color=warna,
             linewidth=1.6, label="derajat %d" % derajat)
plt.xlabel("Biaya iklan harian (ribu rupiah)")
plt.ylabel("Pendapatan harian (ribu rupiah)")
plt.legend()
plt.tight_layout()
plt.show()

Grafiknya menampilkan titik-titik data latih berwarna abu-abu dan tiga kurva. Garis merah (derajat 1) terlihat memotong awan titik secara miring — terlalu rendah di kiri, terlalu tinggi di kanan. Kurva biru (derajat 2) mengikuti alur naik lalu melandai dengan mulus. Kurva hijau (derajat 9) tampak seperti tali yang diikat di setiap titik: hampir menyentuh seluruh titik latih, tetapi berayun liar di sela-selanya — persis alasan R² ujinya jatuh negatif.

Kekuatan dan Kelemahan Regresi Polinomial #

AspekKeterangan
Menangkap lengkunganSatu-satunya cara termurah melenturkan regresi linear
Tetap transparanPersamaan b0 + b1x + b2x² masih bisa dibaca dan dicari puncaknya
Ekstrapolasi cepat melencengDi luar rentang data, pangkat tinggi meluncur turun atau naik tanpa kendali
Derajat tinggi = overfittingSebagaimana dibuktikan derajat 9 kita
Jumlah fitur membengkakDerajat tinggi dengan banyak fitur menghasilkan puluhan kolom turunan

Kapan Kita Memakainya #

Regresi polinomial tepat ketika kita mengetahui atau menduga ada efek melandai, seperti hubungan iklan-pendapatan, pupuk-hasil panen, atau harga-permintaan. Derajat 2 atau 3 biasanya cukup; naik ke derajat tinggi hanya dengan alasan kuat dari R² data uji. Untuk data yang bentuknya bebas dan tidak bisa dilukis parabola, model berbasis pohon di chapter-chapter berikutnya lebih aman. Namun sebelum itu, ada satu keluarga regresi yang masih memakai rumus linear — tetapi untuk menjawab pertanyaan ya/tidak.

Rangkuman #

  • Regresi polinomial = regresi linear + fitur turunan pangkat; LinearRegression tetap dipakai karena model tetap linear terhadap parameter.
  • PolynomialFeatures(degree=d, include_bias=False) membuat kolom x, x², …; latih dengan fit_transform(X_latih), terapkan ke data uji dengan transform(X_uji).
  • Derajat 2 menangkap efek melandai iklan (R² uji 0,991) dan memberi tahu titik jenuh di 66 ribu rupiah.
  • Derajat 9 menghafal derau: R² latih naik tipis tetapi R² uji jatuh ke -1,443 — overfitting dalam bentuk paling jelas.
  • Pilih derajat dari skor data uji, bukan skor latih; ekstrapolasi di luar rentang data berbahaya.

Garis dan lengkungan yang kita bangun sejauh ini sama-sama memprediksi angka: harga rumah, pendapatan harian. Padahal separuh persoalan bisnis justru bertanya biner — pelanggan akan berhenti berlangganan atau tidak. Membengkokkan rumus linear ke dunia peluang itulah tugas Regresi Logistik .

Referensi #

  1. scikit-learn — Preprocessing data (PolynomialFeatures)
  2. scikit-learn — LinearRegression
  3. scikit-learn — train_test_split