En küçük kareler çözümü
Zorluk: Zor Çözüldüdoğrusal cebir
Bu problemde doğrusal regresyonda (linear regression) ortalama kare hatayı (mean squared error, MSE) en küçük yapan parametreleri bulursun. Gradyan inişine (gradient descent) gerek yoktur. Bir doğrusal denklem sistemi çözersin.
Bu yönteme en küçük kareler (least squares) denir. Çözüm bir formülle, yani kapalı formda (closed form) gelir.
least_squares(X, y) fonksiyonunu yaz. Girdiler şunlardır:
X: şekli (shape)(n, d)olan bir dizi (array). Her satır bir örnek (sample), her sütun bir öznitelik (feature) taşır.y: hedef değerleri (target) içeren,(n,)shape’inde bir vektör.
(w, b) çiftini bir tuple olarak döndür. w, her feature için bir ağırlık (weight) içeren (d,) shape’inde bir array’dir. b, sapma (bias) olan bir float’tur.
Bias’ı weight’lerden ayrı tutmamak için şunu yap:
- ‘in sağına bir birler sütunu ekle: . Matris
(n, d + 1)shape’indedir. - Parametreleri tek bir vektörde topla: .
MSE’nin gradyanı sıfır olduğunda kayıp (loss) en küçüktür. Gradyanı sıfıra eşitlemek normal denklemleri (normal equations) verir:
Kapalı form şöyle yazılır:
Ama tersini alma: sistemi np.linalg.solve ile çöz. Sonra ‘dan ‘yi ve ‘yi ayır.
Örnekler
Girdi: X = [[1.0, 2.0], [2.0, 1.0], [3.0, 5.0], [4.0, 3.0], [5.0, 6.0]], y = [3.0, 4.0, 9.0, 8.0, 12.0]
Çıktı: (array([1.28333333, 0.91666667]), 0.23333333333332915)
Girdi: X = [[1.0], [3.0]], y = [2.0, 8.0]
Çıktı: (array([3.]), -1.000000000000001)
Girdi: X = [[-2.0, 1.0, 0.5], [-1.0, -1.0, 2.0], [0.0, 3.0, -1.0], [1.0, 0.0, 1.5], [2.0, -2.0, -0.5], [3.0, 1.0, 1.0]], y = [-4.0, 1.0, 3.5, 2.0, -1.0, 5.0]
Çıktı: (array([1.35470735, 1.19913395, 1.08798142]), -0.6283874853029737)
İpucu 1
Birler sütununu iki adımda ekle:
np.ones((n, 1))ile bir birler sütunu oluştur.np.hstackile onuX’in sağına ekle.
Bu genişletilmiş matrise Xb diyelim. Weight’ler ve bias tek bir vektörde toplanır. Bu yüzden Xb (n, d + 1) shape’inde olmalı.
İpucu 2
Denklemin iki yanı şöyledir:
- Sol taraf
Xb.T @ Xb,(d + 1, d + 1)shape’inde bir matristir. - Sağ taraf
Xb.T @ y,(d + 1,)shape’inde bir vektördür.
np.linalg.solve(A, c), sistemini için çözer.
İpucu 3
Çözüm vektörünü şöyle parçala:
- Son eleman birler sütununa karşılık gelir, yani bias’tır:
theta[-1]. - Ondan öncekiler weight’lerdir:
theta[:-1].
Gereksinimler
X(n, d)vey(n,)shape’inde array’lerdir.- matrisinin sütunları doğrusal bağımsızdır, yani tersinirdir. Aksi durumları ele alman gerekmez.
(w, b)biçiminde bir tuple döndür.w(d,)shape’inde bir NumPy array’i olmalı,(d, 1)bir sütun değil.btek birfloat’tur.theta[-1]’in verdiğinp.float64de kabul edilir.- Normal denklemleri
np.linalg.solveile çöz.np.linalg.inv,np.linalg.pinvya da hazır çözücünp.linalg.lstsqkullanma. - Birler sütununu sen ekle.
X’i vey’yi değiştirme. Fonksiyon bittiğinde onu çağıran kodun array’leri aynı kalmalı.- Örnekler üzerinde döngü kullanma: birkaç matris işlemi yeter.
MSE, ‘nın karesel bir fonksiyonudur: yüzeyi bir çanaktır ve en alçak noktasında gradyan sıfırdır. Gradyan şudur:
Onu sıfıra eşitlemek normal denklemleri verir.
Küçük bir örnek: ve olsun. Matrisler şöyle çıkar:
Yani ve . Sistemi şöyle çöz:
- İkinci denklemden çıkar.
- Bunu birinci denkleme yerleştir: .
- Böylece ve bulunur.
Ters matrisi hesaplayıp çarpmak ile sistemi doğrudan çözmek matematikte aynı sonucu verir. Ama solve genellikle daha hızlı ve sayısal olarak daha kararlıdır. Üstelik çözüm için tersin bütün elemanlarına ihtiyaç yoktur.
Normal denklemlerin de bir sınırı vardır. matrisinin koşul sayısı (condition number), matrisinin koşul sayısının karesidir. Bu yüzden sütunlar neredeyse doğrusal bağımlıysa sonuç güvenilmez olur.
Kütüphaneler bu yüzden çoğu zaman matrisini doğrudan QR ya da SVD ile çözen np.linalg.lstsq fonksiyonunu kullanır.
Sütunlar tam doğrusal bağımlıysa tekildir ve solve hata verir.
Kapalı form tek adımda tam sonucu verir. Ama iki sınırı vardır:
- büyüdükçe bir sistemi çözmek pahalıdır.
- Sinir ağları gibi modellerin kapalı formu yoktur.
Gradient descent bu yüzden her modelde işe yarayan genel yöntemdir. Doğrusal regresyonda ikisi aynı noktaya varır.
Daha fazlası için Ölçekleme, mini-batch ve kapalı form dersine bak.
Çözüm dört adımdır:
- Birler sütununu ekle.
- Normal denklemin iki yanını kur.
np.linalg.solveile çöz.- Çözümü ayır: son eleman bias, öncekiler weight’lerdir.
Kodda bu adımlar şöyle görünür:
import numpy as npdef least_squares(X: np.ndarray, y: np.ndarray) -> tuple[np.ndarray, float]: Xb = np.hstack([X, np.ones((X.shape[0], 1))]) # bias için birler sütunu theta = np.linalg.solve(Xb.T @ Xb, Xb.T @ y) return theta[:-1], float(theta[-1])
Sık yapılan hata, formülü olduğu gibi yazmaktır: np.linalg.inv(Xb.T @ Xb) @ Xb.T @ y.
Sonuç genellikle aynı çıkar, ama kod gereksiz yere ters matris hesaplar ve sayısal olarak daha zayıftır. Bu problemde inv kabul edilmez.
Bir diğer hata, birler sütununu unutmaktır. Model orijinden geçmeye zorlanır ve b hiç öğrenilmez.
Bu problemde bir sorun mu var?