Belajar AI #8: Regresi — Memprediksi Nilai Kontinu dengan Linear Regression

Masuk episode 8, akhirnya kita sentuh algoritma sungguhan yang pertama kali saya latih sendiri: linear regression. Dipilih bukan karena canggih — justru karena paling polos. Dan dari kesederhanaannya, konsep-konsep episode sebelumnya (model sebagai fungsi, loss, evaluasi) akhirnya terasa nyambung semua.

Regresi itu memprediksi angka

Regresi adalah tugas supervised learning untuk memprediksi nilai kontinu — angka pada rentang bebas, bukan kategori. Harga rumah, suhu besok, estimasi durasi commit CI, pendapatan bulan depan. Bedakan dengan klasifikasi (episode berikutnya) yang outputnya kelas.

Linear regression adalah bentuk paling sederhananya: asumsi bahwa output adalah kombinasi linear dari fitur. Satu fitur berarti garis lurus, dua fitur bidang datar, banyak fitur hyperplane yang tidak bisa digambar tapi rumusnya sama:

y = w0 + w1*x1 + w2*x2 + ... + wn*xn

Persis seperti yang dibahas di episode 6: bobot dan bias. Training = mencari nilai w dan b yang membuat prediksi sedekat mungkin dengan data, biasanya dengan meminimalkan MSE dari episode 6. Semua episode lama ketemu di sini.

Kenapa mulai dari yang sederhana

  • Cepat dilatih — selesai dalam hitungan detik bahkan di laptop biasa.
  • Bisa dijelaskan — tiap bobot punya arti: “tiap tambahan 1 m² menambah harga sekian”. Emas saat harus presentasi ke orang non-teknis.
  • Baseline yang jujur — kalau model canggih hanya mengalahkan linear regression tipis, pertanyaan dulu apakah kompleksitasnya worth it.

Praktik: melatih linear regression

Contoh lengkap dengan scikit-learn, termasuk evaluasinya:

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, r2_score

X = [[50], [80], [120], [60], [95]]   # luas m2
y = [500, 750, 1100, 590, 900]        # harga juta

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.4, random_state=42
)

model = LinearRegression()
model.fit(X_train, y_train)

pred = model.predict(X_test)
print("MAE :", mean_absolute_error(y_test, pred))
print("R^2 :", r2_score(y_test, pred))

Dua metrik regresi yang saya pakai: MAE (rata-rata selisih absolut — “rata-rata meleset sekian unit”, gampang dijelaskan ke siapa pun) dan R² (proporsi variasi data yang bisa dijelaskan model; 1 sempurna, 0 setara menebak rata-rata). Untuk regresi, MSE dari episode 6 adalah loss function-nya; MAE dan R² lebih sering saya pakai untuk melapor hasil.

Visualisasi: scatter plot dan garis regresi

Salah satu cara paling intuitif untuk memahami linear regression adalah menggambar scatter plot data lalu melihat garis regresi melewatinya. Kode berikut memvisualisasikan model kita — garis merah adalah prediksi model terhadap seluruh data asli:

import matplotlib.pyplot as plt
import numpy as np

X_flat = np.array(X).flatten()
X_range = np.linspace(X_flat.min() - 5, X_flat.max() + 5, 100).reshape(-1, 1)
y_line = model.predict(X_range)

plt.scatter(X_flat, y, color="steelblue", label="Data asli")
plt.plot(X_range, y_line, color="red", label="Garis regresi")
plt.xlabel("Luas (m²)")
plt.ylabel("Harga (juta)")
plt.title("Linear Regression: Luas vs Harga")
plt.legend()
plt.show()

Ketika pertama kali saya menjalankan kode ini, rasanya langsung paham — titik-titik data tersebar di atas dan bawah garis, dan model menemukan “keseimbangan” di tengah-tengahnya. Inilah inti dari ordinary least squares: menyelesaikan garis yang meminimalkan total jarak vertikal kuadrat ke semua titik.

Multiple linear regression

Sejauh ini kita hanya pakai satu fitur. Dalam dunia nyata, harga rumah dipengaruhi luas tanah, jumlah kamar, jarak ke stasiun, usia bangunan, dan banyak lagi. Multiple linear regression menambahkan lebih banyak fitur — rumusnya tetap sama, cuma w yang bertambah:

import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score

# data: luas_m2, kamar, jarak_km
X = pd.DataFrame({
    "luas": [50, 80, 120, 60, 95, 110, 45, 85],
    "kamar": [2, 3, 4, 2, 3, 4, 2, 3],
    "jarak": [5.0, 3.2, 1.5, 4.8, 2.1, 1.8, 6.0, 2.9]
})
y = [500, 750, 1100, 590, 900, 1050, 460, 780]

model = LinearRegression()
model.fit(X, y)

for col, coef in zip(X.columns, model.coef_):
    print(f"  {col}: {coef:+.2f}")
print(f"  intercept: {model.intercept_:.2f}")

Keunggulan utamanya: koefisien tetap bisa dibaca langsung. “Setiap tambahan 1 kamar menambah harga sekian juta, dengan asumsi fitur lain tetap.” Kemampuan menjelaskan seperti ini jarang dimiliki model yang lebih kompleks.

Evaluasi model regresi secara mendalam

Sebelumnya kita sudah pakai MAE dan R². Berikut empat metrik utama yang harus dipahami setiap kali melatih model regresi:

from sklearn.metrics import (
    mean_absolute_error,
    mean_squared_error,
    r2_score
)
import numpy as np

mae  = mean_absolute_error(y_test, pred)
mse  = mean_squared_error(y_test, pred)
rmse = np.sqrt(mse)
r2   = r2_score(y_test, pred)

print(f"MAE  = {mae:.2f}  (rata-rata error absolut)")
print(f"MSE  = {mse:.2f}  (kuadrat error, hukum outlier)")
print(f"RMSE = {rmse:.2f}  (satuan sama dengan target)")
print(f"R²   = {r2:.4f}  (proporsi variasi terjelaskan)")

MAE mudah dijelaskan ke non-teknis: “prediksi meleset rata-rata sekian juta.” MSE menghukum outlier lebih berat karena error dikuadratkan — cocok saat satu prediksi yang sangat meleset harus dihindari. RMSE mengembalikan MSE ke satuan asli target, sehingga lebih intuitif dibanding MSE murni. R² menjawab pertanyaan “seberapa jauh model lebih baik daripada sekadar menebak rata-rata?” — nilai 0.85 berarti model menjelaskan 85% variasi data. Saya biasanya mulai dari RMSE karena paling praktis: langsung tahu magnitude error dalam satuan yang sama dengan target.

Polynomial regression

Kadang hubungan data jelas melengkung — bukan garis lurus. Polynomial regression menambahkan fitur kuadrat, kubik, dan seterusnya sehingga model tetap “linear” terhadap koefisiennya tapi bisa menangkap kelengkungan:

from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import make_pipeline

# degree=2 berarti fitur: x, x^2
pipe = make_pipeline(
    PolynomialFeatures(degree=2, include_bias=False),
    LinearRegression()
)
pipe.fit(X_train, y_train)
print("R² (poly-2):", pipe.score(X_test, y_test))

Kapan pakai? Ketika scatter plot menunjukkan pola melengkung, tapi Anda belum siap loncat ke model non-linear. Peringatan: degree terlalu tinggi berisiko overfitting — model melengkung mengikuti noise bukan pola.

Asumsi linear regression

Linear regression punya asumsi yang kalau dilanggar hasilnya menyesatkan secara halus. Saya catat empat asumsi utama yang sering dilupakan:

  • Linearitas — hubungan fitur-target memang mendekati garis lurus. Kalau tidak, transformasi (log, akar) atau model lain perlu dipertimbangkan.
  • Independensi residual — error satu observasi tidak boleh berkorelasi dengan error observasi lain. Pelanggaran umum pada data time series yang berurutan (autokorelasi). Tes Durbin-Watson bisa mendeteksi masalah ini.
  • Homoscedasticity — variansi error konstan di seluruh rentang prediksi. Kalau error makin lebar seiring nilai prediksi naik (heteroscedasticity), model tidak bisa dipercaya untuk interval prediksi. Plot residual vs predicted bisa memperlihatkan masalah ini: seharusnya terlihat seperti awan titik acak, bukan corong.
  • Normalitas residual — error terdistribusi normal. Penting untuk inferensi statistik (confidence interval, p-value), tapi untuk prediksi murni kurang kritis. Q-Q plot atau Shapiro-Wilk test bisa mengecek.
  • Outlier — satu titik ekstrem bisa menyeret garis cukup jauh, karena kuadrat error menghukumnya berat.
  • Ekstrapolasi — model hanya andal di rentang data latih. Prediksi harga rumah 500 m² padahal data maksimal 200 m²? Jangan percaya.

Regularisasi: Ridge dan Lasso

Fitur banyak, data sedikit — linear regression bisa overfit. Regularisasi menambahkan penalti pada ukuran koefisien agar model tetap sederhana:

from sklearn.linear_model import Ridge, Lasso

# Ridge: penalti L2 — koefisien ditekan kecil tapi tidak nol
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)

# Lasso: penalti L1 — bisa mengecilkan koefisien sampai nol (feature selection)
lasso = Lasso(alpha=1.0)
lasso.fit(X_train, y_train)

print("R² Ridge:", ridge.score(X_test, y_test))
print("R² Lasso:", lasso.score(X_test, y_test))

Ridge cocok saat semua fitur relevan tapi perlu ditekan ukurannya. Lasso cocok saat Anda curiga banyak fitur yang tidak berguna — koefisiennya bisa menjadi nol, secara otomatis melakukan feature selection. Ada juga ElasticNet yang menggabungkan keduanya.

Contoh kasus nyata

  • Prediksi harga rumah — fitur: luas, jumlah kamar, jarak ke pusat kota. Linear regression memberikan baseline yang kuat. Dalam proyek properti nyata, baseline linear seringkali mengalahkan ekspektasi klien karena transparansi koefisien.
  • Estimasi waktu CI/CD — durasi build bergantung jumlah test file, ukuran kode, jumlah dependensi. Linear regression membantu memprediksi kapan pipeline selesai sehingga developer bisa merencanakan waktu.
  • Perkiraan konsumsi energi — suhu luar, jumlah penghuni, dan jam operasional sebagai fitur. Perusahaan manufaktur pakai regresi untuk mengestimasi biaya listrik bulan depan dan merencanakan anggaran.

Kapan harus beralih ke model lebih kompleks

Linear regression punya tempat, tapi ada tanda-tanda kapan harus pindah ke model lain:

  • Residual plot menunjukkan pola — garis lengkung, corong, atau klaster. Artinya ada struktur di data yang tidak ditangkap.
  • R² rendah meskipun asumsi terpenuhi — hubungannya memang bukan linear, perlu tree-based model atau neural network.
  • Interaksi fitur penting — efek fitur A terhadap target bergantung pada nilai fitur B. Linear regression standar tidak menangkap ini tanpa feature engineering manual.
  • Data kategorikal banyak — encoding menghasilkan ratusan kolom. Tree-based model (Random Forest, XGBoost) biasanya menangani ini lebih elegan.

Catatan untuk diri sendiri

Eksperimen pertama saya gagal bukan karena algoritmanya, tapi karena saya lupa train/test split dan mengukur di data yang sama dengan data latih — hasilnya R² hampir sempurna yang ternyata bohong. Pelajaran episode ini: algoritma sederhana + evaluasi benar mengalahkan algoritma canggih + evaluasi salah. Selalu.

Momen yang tidak saya lupa: pertama kali menjalankan model.fit(), lalu melihat scatter plot data dengan garis regresi melewatinya di matplotlib. Rasanya paham sekaligus rendah hati — matematika seratus tahun lalu masih jadi baseline terkuat di banyak proyek machine learning hari ini. Saya belajar tidak meremehkan yang sederhana, dan selalu mulai dari sana.

Sumber

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses