Idenya
Regresi linear memprediksi sebuah angka sebagai jumlah berbobot dari fitur-fitur ditambah sebuah konstanta:
units = w₁·temperature + w₂·weekend + w₃·promo + w₄·ad_spend + b
Itulah X @ w + b dari modul aljabar linear NumPy, dan "model + loss" dari dua modul lalu, dengan satu sifat istimewa: bobot dengan MSE terendah bisa dihitung secara eksak, dengan sebuah rumus, tanpa perlu mencari. Ini model pertama yang dicoba untuk masalah regresi apa pun, dan sering menjadi yang akhirnya dirilis, karena koefisiennya menjelaskan dirinya sendiri.
Satu fitur: sebuah garis
Mulai dari versi paling sederhana pertanyaannya: apakah belanja iklan yang lebih banyak menjual lebih banyak unit? Dengan satu fitur, model linear hanyalah garis lurus yang melewati titik-titiknya, dan NumPy bisa langsung mencari garis yang paling pas:
import numpy as np
import pandas as pd
demand = pd.read_csv("daily_demand.csv")
x = demand["ad_spend"].to_numpy()
y = demand["units"].to_numpy()
w, b = np.polyfit(x, y, 1)
print(round(w, 2), round(b, 2))
7.51 44.56
Kemiringan w berarti: setiap tambahan sejuta Rupiah iklan berkaitan dengan sekitar sebanyak itu unit terjual. Intercept b adalah unit yang diprediksi dengan belanja iklan nol.
Bagaimana cara menghitungnya? Least squares punya jawaban dalam bentuk tertutup. Untuk satu fitur, rumusnya cukup pendek untuk ditulis:
w_formula = np.sum((x - x.mean()) * (y - y.mean())) / np.sum((x - x.mean()) ** 2)
b_formula = y.mean() - w_formula * x.mean()
print(round(w_formula, 2), round(b_formula, 2))
7.51 44.56
Jawabannya sama. Kemiringannya adalah "seberapa banyak x dan y bergerak bersama" dibagi "seberapa banyak x bergerak", dan garisnya selalu melewati titik (rata-rata x, rata-rata y).
Beberapa fitur: sebuah bidang
Dengan beberapa fitur, NumPy menyelesaikan masalah least squares dengan np.linalg.lstsq. Tambahkan kolom berisi angka satu supaya model bisa mempelajari intercept-nya:
features = ["temperature", "weekend", "promo", "ad_spend"]
X = demand[features].to_numpy()
X1 = np.column_stack([X, np.ones(len(X))]) # kolom terakhir: intercept
coefs, *_ = np.linalg.lstsq(X1, y, rcond=None)
for name, c in zip(features + ["intercept"], coefs):
print(f"{name:12} {c:8.2f}")
temperature -1.67
weekend 5.75
promo 18.92
ad_spend 7.62
intercept 85.75
Setiap koefisien adalah efek dengan fitur-fitur lain dibuat tetap:
promo≈ +19: hari promosi menjual sekitar 19 unit lebih banyak daripada hari yang selain itu identik.weekend≈ +6 unit.ad_spend≈ +7,6 unit per juta Rupiah.temperature≈ −1,7: setiap derajat tambahan, sedikit lebih sedikit kopi panas.
Itulah daya tarik regresi linear: seorang manajer bisa membacanya. "Promosi bernilai sekitar 19 unit per hari" adalah kalimat yang bisa ditindaklanjuti (bandingkan dengan biaya sebuah promosi).
Regresi linear menemukan bobot yang meminimalkan error kuadrat, secara eksak. Setiap bobot adalah efek dari satu fitur dengan yang lain dibuat tetap, dalam satuan fitur tersebut.
Hal yang sama dengan scikit-learn
Dalam praktik kamu memakai scikit-learn, yang punya antarmuka yang sama untuk setiap model: fit, lalu predict:
from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(demand[features], y)
print(np.round(model.coef_, 2), round(model.intercept_, 2))
tomorrow = pd.DataFrame({"temperature": [29.0], "weekend": [1], "promo": [1], "ad_spend": [2.0]})
print(model.predict(tomorrow).round(1))
[-1.67 5.75 18.92 7.62] 85.75
[77.2]
Koefisiennya identik dengan lstsq. predict mengubah fitur hari baru menjadi ramalan: hari Sabtu yang panas dengan promosi dan iklan Rp 2 jt.
R²: seberapa banyak yang dijelaskan?
model.score(X, y) mengembalikan R²: porsi variasi y yang dijelaskan oleh model (1,0 = sempurna, 0 = tidak lebih baik daripada memprediksi rata-ratanya).
print(round(model.score(demand[features], y), 3))
0.811
Modul metrik regresi menjelaskan R² dengan benar. Di sini ia menyatakan bahwa keempat fitur ini menjelaskan sebagian besar variasi penjualan dari hari ke hari.
Periksa residualnya
Sebuah model bisa punya skor yang lumayan tapi tetap salah secara sistematis. Lihat residual-nya (nilai sebenarnya − prediksi):
residuals = y - model.predict(demand[features])
print("average is ~0:", bool(np.isclose(residuals.mean(), 0)), "| typical size:", round(residuals.std(), 2))
by_weekend = pd.Series(residuals).groupby(demand["weekend"]).mean()
print("weekday and weekend averages ~0:", bool(np.allclose(by_weekend, 0)))
average is ~0: True | typical size: 4.98
weekday and weekend averages ~0: True
Tanda-tanda yang baik: residual rata-ratanya nol secara keseluruhan dan di dalam kelompok (tidak ada kelompok yang konsisten diprediksi terlalu tinggi atau terlalu rendah), dan sebarannya (sekitar ±5 unit) sesuai dengan noise yang kamu harapkan. Pola di residual (misalnya, selalu memprediksi terlalu rendah di hari panas) berarti model melewatkan sesuatu: hubungan yang melengkung, interaksi, atau sebuah fitur.
Keterbatasan
- Ia mengasumsikan efek-efeknya saling menjumlah dan berupa garis lurus. Lengkungan dan interaksi butuh fitur tambahan (misalnya
temperature²,promo × weekend) atau model lain (pohon). - Koefisien menggambarkan asosiasi, bukan bukti sebab-akibat: mungkin iklan dijalankan di hari-hari yang memang akan ramai.
- Outlier menarik garisnya dengan kuat, karena error-nya dikuadratkan.
- Fitur yang berkorelasi (dua ukuran dari hal yang sama) membuat koefisien individu tidak stabil; regularisasi membantu (modul selanjutnya).
Mengapa ini penting untuk kode yang bersih
Regresi linear adalah baseline yang harus dikalahkan setiap model regresi lainnya, dan yang paling bisa dijelaskan yang akan pernah kamu deploy. Jaga daftar fitur tetap eksplisit, cetak koefisien beserta namanya, dan selalu periksa residual. Model rumit yang mengalahkannya sebesar 1% sering tidak sepadan dengan hilangnya penjelasan.
Rangkuman
- Regresi linear: prediksi = jumlah berbobot fitur + intercept; bobot meminimalkan MSE.
- Satu fitur:
np.polyfit(x, y, 1); banyak:np.linalg.lstsqdengan kolom berisi angka satu, atauLinearRegression().fit(X, y). - Koefisien = efek sebuah fitur dengan yang lain dibuat tetap, dalam satuannya.
model.predict(new_X)meramal;model.scorememberi R².- Periksa residual: berpusat di nol, tanpa pola per kelompok. Perhatikan lengkungan, sebab-akibat, outlier dan fitur yang berkorelasi.