Model regresi pertama kita juga model paling berpengaruh dalam sejarah statistika: regresi linier sederhana, prediksi dengan tepat satu fitur. Seluruh pengetahuannya muat dalam dua angka — kemiringan dan titik potong — sehingga kita bisa menghitungnya sendiri dengan rumus, lalu membuktikan bahwa API scikit-learn menghasilkan angka yang persis sama. Chapter ini membedah cara kerja least squares, arti tiap komponen garis, dan cara membaca koefisien coef_ serta intercept_. Setelah ini, melatih regresi tidak akan terasa seperti kotak hitam lagi: hanya aritmetika yang bisa kita lacak sampai ke angkanya.
Satu Fitur, Satu Garis #
Regresi linier sederhana memodelkan hubungan satu fitur x dengan target y sebagai garis lurus:
ŷ = w · x + b
di mana w adalah slope (kemiringan) dan b adalah intersep (titik potong sumbu tegak). Model “belajar” berarti mencari pasangan (w, b) yang paling pas dengan data latih. Untuk masalah harga rumah, w terbaca sebagai tambahan harga per satu meter persegi, dan b sebagai harga dasar ketika luas nol — angka yang secara teori memang tidak pernah terjadi di pasar, tetapi dibutuhkan garis untuk menentukan posisi vertikalnya.
Membaca garis hasil pelatihan sama mudahnya dengan membaca peta harga. Jika model menghasilkan harga = 7,51 × luas + 60,48, maka dua rumah yang berselisih 10 m² diprediksi berselisih 75,1 juta — informasi yang jauh lebih ringkas daripada menghafal dua belas transaksi mentah.
Intuisi Least Squares #
Bagaimana kita memilih garis terbaik dari tak terhingga kandidat? Kriteria standarnya: pilih garis yang membuat jumlah kuadrat jarak vertikal antara titik data dan garis sekecil mungkin. Jarak vertikal tiap titik — selisih y aktual dengan ŷ — disebut residu; least squares meminimalkan jumlah kuadrat residu. Ini persis fungsi loss MSE yang sudah kita hitung dengan tangan di Chapter Cara Machine Learning Belajar dari Data, dan di sini dipandang dari sisi geometrinya: garis yang dipilih adalah garis yang paling “dekat rata-rata” ke seluruh titik.
Untuk satu fitur, nilai terbaik (w, b) bahkan tidak perlu dicari bertahap — tersedia rumus tertutup:
w = Σ(xᵢ − x̄)(yᵢ − ȳ) / Σ(xᵢ − x̄)² (setara cov(x, y) / var(x))
b = ȳ − w · x̄
Pembilang mengukur seberapa bersama-sama x dan y bergerak dari nilai reratanya; penyebut mengukur seberapa lebar sebaran x. Rumus ini adalah hasil menurunkan loss terhadap kedua parameter lalu menyetel turunannya nol — perhitungan yang akan kita serahkan ke rumus, bukan diulang di sini.
Dari Rumus Manual ke API #
Sekarang bagian yang menyenangkan: menghitung kedua parameter dua kali — sekali dengan rumus di atas ditulis di NumPy, sekali lewat LinearRegression — lalu membandingkannya langsung. File regresi-sederhana.py juga memprediksi dua rumah baru dengan kedua cara dan menutup dengan R² yang dihitung manual serta lewat r2_score.
# Regresi linier sederhana: hitung garis terbaik dengan rumus manual,
# lalu bandingkan hasilnya dengan LinearRegression dari scikit-learn.
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
# Dua belas rumah terjual di satu kompleks: luas (m^2) dan harga (juta rupiah).
luas = np.array([30.0, 35.0, 40.0, 45.0, 50.0, 55.0,
60.0, 65.0, 70.0, 75.0, 80.0, 85.0])
harga = np.array([292.0, 318.0, 365.0, 390.0, 441.0, 470.0,
516.0, 543.0, 590.0, 615.0, 668.0, 700.0])
# Bagian 1 -- rumus least squares manual:
# slope = jumlah((x - x_bar) * (y - y_bar)) / jumlah((x - x_bar)^2)
# intersep = y_bar - slope * x_bar
x_mid = luas - luas.mean()
y_mid = harga - harga.mean()
slope_manual = np.sum(x_mid * y_mid) / np.sum(x_mid**2)
intersep_manual = harga.mean() - slope_manual * luas.mean()
# Bagian 2 -- API scikit-learn mempelajari garis yang sama lewat fit().
model = LinearRegression()
model.fit(luas.reshape(-1, 1), harga)
slope_api = model.coef_[0]
intersep_api = model.intercept_
print("Perbandingan rumus manual vs LinearRegression:")
print(f"{'besaran':<10} {'manual':>12} {'scikit-learn':>14}")
print(f"{'slope':<10} {slope_manual:>12.4f} {slope_api:>14.4f}")
print(f"{'intersep':<10} {intersep_manual:>12.4f} {intersep_api:>14.4f}")
print()
# Prediksi dua rumah baru: hitung manual dengan rumus garis,
# lalu bandingkan dengan model.predict().
for l_baru in [48.0, 82.0]:
p_manual = slope_manual * l_baru + intersep_manual
p_api = model.predict(np.array([[l_baru]]))[0]
print(f"luas {l_baru:4.0f} m^2 -> manual {p_manual:7.2f} juta | "
f"predict() {p_api:7.2f} juta")
print()
# Bagian 3 -- R^2 manual (1 - SSE/SST) vs r2_score dari scikit-learn.
prediksi_latih = slope_api * luas + intersep_api
sse = np.sum((harga - prediksi_latih) ** 2)
sst = np.sum((harga - harga.mean()) ** 2)
r2_manual = 1.0 - sse / sst
r2_api = r2_score(harga, prediksi_latih)
print(f"R^2 manual = 1 - SSE/SST = {r2_manual:.4f}")
print(f"R^2 r2_score = {r2_api:.4f}")Output yang Dihasilkan:
Perbandingan rumus manual vs LinearRegression:
besaran manual scikit-learn
slope 7.5105 7.5105
intersep 60.4802 60.4802
luas 48 m^2 -> manual 420.98 juta | predict() 420.98 juta
luas 82 m^2 -> manual 676.34 juta | predict() 676.34 juta
R^2 manual = 1 - SSE/SST = 0.9981
R^2 r2_score = 0.9981Bedah kode di atas baris demi baris:
- Baris 9–12 (
luas,harga): dua belas titik data ditulis tetap — satu fitur numerik dan satu target kontinu, syarat lengkap regresi sederhana. - Baris 17–20 (rumus manual):
x_middany_midadalah selisih tiap nilai terhadap reratanya. Pembilangnp.sum(x_mid * y_mid)menjumlahkan hasil kali simpangan; penyebutnp.sum(x_mid**2)menjumlahkan kuadrat simpanganx. Keduanya menghasilkan slope 7,5105; intersep tinggal 60,4802 dariȳ − w·x̄. - Baris 23–26 (API):
fit()menjalankan least squares yang sama di balik layar, lalu menyimpan hasilnya pada dua atribut:coef_berisi array slope (satu nilai per fitur) danintercept_berisi skalarb. - Baris 28–31 (tabel perbandingan): keempat angka dicetak berdampingan — kolom manual dan kolom scikit-learn identik sampai desimal keempat. Bukan kebetulan: keduanya menyelesaikan optimasi yang sama secara eksak.
- Baris 36–40 (prediksi ganda): rumus garis dievaluasi dengan tangan untuk luas 48 dan 82 m², lalu dibandingkan dengan
model.predict(). Hasilnya sama persis: 420,98 juta dan 676,34 juta. - Baris 44–50 (R² dua versi): residu dijumlahkan kuadratnya menjadi SSE, sebaran total terhadap rerata menjadi SST, dan
1 − SSE/SSTmenghasilkan 0,9981 — sama denganr2_score.
Membaca Slope, Intersep, dan R² #
Ketiga besaran hasil pelatihan masing-masing punya bacaan praktis:
| Besaran | Nilai contoh | Cara membaca |
|---|---|---|
coef_ (slope) | 7,5105 | Tiap tambahan 1 m² luas menaikkan prediksi harga sekitar 7,51 juta |
intercept_ | 60,4802 | Titik potong garis di luas 0 — harga dasar teoretis, bukan harga pasar nyata |
| R² | 0,9981 | 99,81% variasi harga data latih terjelaskan oleh luas lewat garis ini |
R² perlu dibaca dengan kepala dingin: nilainya dihitung pada data yang sama dengan data latih, dan “variasi terjelaskan” bukan jaminan hubungan sebab-akibat. Data harga rumah memang hampir selalu bergerak seiring luas, sehingga R² tinggi wajar di sini; pada data yang lebih berderau, angka 0,3 saja bisa jadi kabar baik. Kita akan membedah R² bersama MAE, MSE, dan RMSE secara menyeluruh di Chapter Metrik Evaluasi Regresi.
Satu fitur memang jarang cukup di dunia nyata: harga rumah dipengaruhi luas sekaligus jarak ke pusat kota, jumlah kamar, dan usia bangunan. Kabar baiknya, seluruh mesin yang baru kita bangun — least squares, coef_, intercept_ — naik kelas ke banyak fitur tanpa perlu rancang ulang: rumusnya menjadi perkalian matriks, dan tiap fitur mendapat koefisien sendiri. Perluasan itulah isi Chapter Regresi Linier Berganda.
Referensi Resmi #
- Linear Models — scikit-learn User Guide — bagian Ordinary Least Squares menjelaskan rumus yang kita hitung manual di atas.
- sklearn.linear_model.LinearRegression — API Reference
— dokumentasi atribut
coef_danintercept_. - sklearn.metrics.r2_score — API Reference — definisi resmi koefisien determinasi R².