Faza 02 · lecția 02

Regresie liniară

Scopul lecției: Regresia liniară trasează cea mai bună dreaptă prin datele dumneavoastră. Este „Hello, World!” al învățării automate.

Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.

Curs
AI Engineering from Scratch
Fază
Bazele învățării automate
Lectură
22 min.
Verificat
Cuprinsul lecției
  1. Obiective de învățare
  2. Problema
  3. Conceptul
  4. Modelul
  5. Funcția de cost (eroarea pătratică medie)
  6. Coborârea pe gradient
  7. Ecuația normală (soluție în formă închisă)
  8. Regresie liniară multiplă
  9. Regresie polinomială
  10. Scorul R pătrat
  11. Previzualizarea regularizării (regresie Ridge)
  12. Construiți
  13. Pasul 1: generați date de exemplu
  14. Pasul 2: regresie liniară de la zero prin coborâre pe gradient
  15. Pasul 3: ecuația normală (soluție în formă închisă)
  16. Pasul 4: regresie liniară multiplă
  17. Pasul 5: regresie polinomială
  18. Pasul 6: regresie Ridge (regularizare L2)
  19. Folosiți
  20. Livrați
  21. Exerciții
  22. Termeni-cheie
  23. Lecturi suplimentare

Regresia liniară trasează cea mai bună dreaptă prin datele dumneavoastră. Este „Hello, World!” al învățării automate.

Tip: Construire Limbaje: Python Cerințe preliminare: Faza 1 (Algebră liniară, Calcul diferențial și integral, Optimizare), Faza 2, lecția 1 Durată: ~90 de minute

Obiective de învățare

  • Deducerea regulilor de actualizare prin coborâre pe gradient pentru eroarea pătratică medie și implementarea regresiei liniare de la zero
  • Compararea coborârii pe gradient cu ecuația normală din perspectiva complexității de calcul și a situațiilor în care se folosește fiecare
  • Construirea unui model de regresie liniară multiplă cu standardizarea caracteristicilor și interpretarea ponderilor învățate
  • Explicarea modului în care regresia Ridge (regularizare L2) poate reduce riscul de supraînvățare penalizând ponderile mari

Notă tehnică a traducerii: regularizarea Ridge poate reduce varianța și riscul de supraînvățare, însă nu o previne în mod garantat; efectul depinde de date, de valoarea penalizării și de procedura de validare.

Problema

Aveți date despre suprafețele locuințelor și prețurile lor de vânzare. Doriți să preziceți prețul unei locuințe noi pe baza suprafeței. Ați putea aproxima vizual relația într-o diagramă de dispersie, dar aveți nevoie de o formulă: o dreaptă care se potrivește cât mai bine datelor, astfel încât să puteți introduce orice suprafață și să obțineți o predicție de preț.

Regresia liniară vă oferă această dreaptă. Mai important, ea introduce întreaga buclă de antrenare din învățarea automată: definiți un model, definiți o funcție de cost și optimizați parametrii. Fiecare algoritm de învățare automată urmează același tipar general. Dacă îl stăpâniți aici, în cel mai simplu caz, îl veți recunoaște peste tot.

Metoda nu este rezervată problemelor simple. Regresia liniară este folosită în sisteme de producție pentru prognozarea cererii, analiza testelor A/B, modelarea financiară și drept referință pentru orice sarcină de regresie.

Conceptul

Modelul

Regresia liniară presupune o relație liniară între intrare (x) și ieșire (y):

y = wx + b
  • w (pondere/pantă): cât se modifică y atunci când x crește cu 1
  • b (bias/ordonată la origine): valoarea lui y când x = 0

Pentru mai multe intrări (caracteristici), modelul devine:

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

Sau, în formă vectorială: y = w^T * x + b.

Obiectivul este să găsiți valorile lui w și b care fac ca valorile y prezise să fie cât mai apropiate de valorile y reale în toate exemplele de antrenare.

Funcția de cost (eroarea pătratică medie)

Cum măsurați „cât mai apropiate”? Aveți nevoie de un singur număr care să surprindă cât de greșite sunt predicțiile. Cea mai frecventă alegere este eroarea pătratică medie (MSE):

MSE = (1/n) * sum((y_predicted - y_actual)^2)

De ce ridicăm la pătrat? Din două motive. Mai întâi, erorile mari sunt penalizate mai mult decât cele mici (o eroare de 10 contribuie de 100 de ori mai mult la pierderea pătratică decât o eroare de 1, nu de 10 ori). În al doilea rând, funcția pătratică este netedă și diferențiabilă peste tot, ceea ce simplifică optimizarea.

Funcția de cost creează o suprafață. Pentru o singură pondere w și un bias b, suprafața MSE seamănă cu un bol (un paraboloid convex). Fundul bolului corespunde minimului MSE. Antrenarea înseamnă găsirea acelui punct.

Coborârea pe gradient

Coborârea pe gradient găsește fundul bolului făcând pași în jos.

Диаграмма к уроку «Regresie liniară»

Gradienții vă spun două lucruri: direcția în care trebuie deplasat fiecare parametru și mărimea deplasării înainte de scalarea cu rata de învățare.

Pentru MSE cu y_hat = wx + b:

dMSE/dw = (2/n) * sum((y_hat - y) * x)
dMSE/db = (2/n) * sum(y_hat - y)

Regula de actualizare:

w = w - learning_rate * dMSE/dw
b = b - learning_rate * dMSE/db

Rata de învățare controlează mărimea pasului. Dacă este prea mare, depășiți minimul și algoritmul poate diverge. Dacă este prea mică, antrenarea durează foarte mult. Valori precum 0,01, 0,001 sau 0,0001 pot servi drept puncte inițiale pentru experimentare.

Notă tehnică a traducerii: nu există valori „tipice” universal sigure pentru rata de învățare. Scara potrivită depinde de normalizarea caracteristicilor, definiția pierderii, condiționarea problemei și algoritmul de optimizare; valorile enumerate în original sunt numai euristici de pornire.

Ecuația normală (soluție în formă închisă)

Pentru regresia liniară există o formulă directă care oferă ponderile optime fără iterații:

w = (X^T * X)^(-1) * X^T * y

Formula rezolvă sistemul normal într-un singur pas conceptual. Poate fi convenabilă pentru probleme mici. Pentru multe caracteristici, formarea și factorizarea sistemului pot deveni costisitoare, iar metodele iterative sau rezolvitoarele numerice specializate pot fi mai potrivite.

Notă tehnică a traducerii: formula cu inversă presupune că X^T * X este inversabilă. În prezența caracteristicilor coliniare sau a rangului deficient se folosește pseudoinversa ori, preferabil numeric, o rezolvare prin QR/SVD fără formarea explicită a inversei. Dacă modelul include b, matricea X trebuie extinsă cu o coloană de 1 sau datele trebuie centrate. Costul nu este descris numai de O(n^3): pentru N exemple și p caracteristici, formarea lui X^T X costă aproximativ O(Np^2), iar rezolvarea densă O(p^3).

Regresie liniară multiplă

Cu mai multe caracteristici, modelul devine:

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

Totul funcționează la fel: MSE este funcția de cost, iar coborârea pe gradient actualizează simultan toate ponderile. Singura diferență geometrică este că ajustați un hiperplan în locul unei drepte.

Scalarea caracteristicilor contează în acest caz. Dacă o caracteristică variază între 0 și 1, iar alta între 0 și 1.000.000, coborârea pe gradient întâmpină dificultăți, deoarece suprafața costului devine foarte alungită. Standardizați caracteristicile (scădeți media și împărțiți la abaterea standard) înainte de antrenare.

Regresie polinomială

Ce faceți dacă relația nu este liniară? Puteți folosi în continuare regresia liniară, creând caracteristici polinomiale:

y = w1*x + w2*x^2 + w3*x^3 + b

Aceasta rămâne regresie „liniară”, deoarece modelul este liniar în ponderile w1, w2, w3. Folosiți doar caracteristici neliniare ale lui x.

Polinoamele de grad mai mare pot ajusta curbe mai complexe, dar riscă să supraînvețe. Pentru 10 puncte cu abscise distincte există deja un polinom interpolator de grad cel mult 9; un model de grad 10 are chiar mai multe grade de libertate și poate reproduce exact datele de antrenare, însă poate prezice slab pe date noi.

Notă tehnică a traducerii: afirmația originală că un polinom de grad 10 „va trece” prin toate cele 10 puncte necesită o procedură de ajustare care urmărește interpolarea exactă și abscise distincte. Gradul 9 este suficient pentru interpolatorul unic; gradul 10 nu face generalizarea mai bună.

Scorul R pătrat

MSE arată cât de greșite sunt predicțiile, dar valoarea depinde de scara lui y. R pătrat (R^2) oferă o măsură fără unități:

R^2 = 1 - (suma pătratelor reziduurilor) / (suma abaterilor pătratice față de medie)
    = 1 - SS_res / SS_tot
  • R^2 = 1,0: predicții perfecte
  • R^2 = 0,0: modelul nu este mai bun decât predicția constantă egală cu media, pentru ținte neconstante
  • R^2 < 0,0: modelul este mai slab decât predicția mediei pe datele evaluate

Notă tehnică a traducerii: interpretarea drept „proporția varianței explicate” are nevoie de atenție și coincide cu scorul de varianță explicată numai în condiții suplimentare, de exemplu când reziduurile au medie zero. Pentru o țintă constantă, formula are numitor zero și scorul brut este NaN sau -Inf; scikit-learn îl ajustează implicit la valori finite. Pe date de test, R^2 poate fi negativ.

Previzualizarea regularizării (regresie Ridge)

Când aveți multe caracteristici, modelul poate supraînvăța atribuind ponderi mari. Regresia Ridge (regularizare L2) adaugă o penalizare:

Cost = MSE + lambda * sum(w_i^2)

Termenul de penalizare descurajează ponderile mari. Hiperparametrul lambda controlează compromisul: o valoare mai mare înseamnă, în general, ponderi mai mici și regularizare mai puternică. Subiectul este tratat în profunzime într-o lecție ulterioară. Deocamdată este suficient să știți că metoda există și de ce poate ajuta.

linear-regression-fit

Construiți

Pasul 1: generați date de exemplu

import random
import math

random.seed(42)

TRUE_W = 3.0
TRUE_B = 7.0
N_SAMPLES = 100

X = [random.uniform(0, 10) for _ in range(N_SAMPLES)]
y = [TRUE_W * x + TRUE_B + random.gauss(0, 2.0) for x in X]

print(f"Generated {N_SAMPLES} samples")
print(f"True relationship: y = {TRUE_W}x + {TRUE_B} (+ noise)")
print(f"First 5 points: {[(round(X[i], 2), round(y[i], 2)) for i in range(5)]}")

Pasul 2: regresie liniară de la zero prin coborâre pe gradient

class LinearRegression:
    def __init__(self, learning_rate=0.01):
        self.w = 0.0
        self.b = 0.0
        self.lr = learning_rate
        self.cost_history = []

    def predict(self, X):
        return [self.w * x + self.b for x in X]

    def compute_cost(self, X, y):
        predictions = self.predict(X)
        n = len(y)
        cost = sum((pred - actual) ** 2 for pred, actual in zip(predictions, y)) / n
        return cost

    def compute_gradients(self, X, y):
        predictions = self.predict(X)
        n = len(y)
        dw = (2 / n) * sum((pred - actual) * x for pred, actual, x in zip(predictions, y, X))
        db = (2 / n) * sum(pred - actual for pred, actual in zip(predictions, y))
        return dw, db

    def fit(self, X, y, epochs=1000, print_every=200):
        for epoch in range(epochs):
            dw, db = self.compute_gradients(X, y)
            self.w -= self.lr * dw
            self.b -= self.lr * db
            cost = self.compute_cost(X, y)
            self.cost_history.append(cost)
            if epoch % print_every == 0:
                print(f"  Epoch {epoch:4d} | Cost: {cost:.4f} | w: {self.w:.4f} | b: {self.b:.4f}")
        return self

    def r_squared(self, X, y):
        predictions = self.predict(X)
        y_mean = sum(y) / len(y)
        ss_res = sum((actual - pred) ** 2 for actual, pred in zip(y, predictions))
        ss_tot = sum((actual - y_mean) ** 2 for actual in y)
        return 1 - (ss_res / ss_tot)


print("=== Training Linear Regression (Gradient Descent) ===")
model = LinearRegression(learning_rate=0.005)
model.fit(X, y, epochs=1000, print_every=200)
print(f"\nLearned: y = {model.w:.4f}x + {model.b:.4f}")
print(f"True:    y = {TRUE_W}x + {TRUE_B}")
print(f"R-squared: {model.r_squared(X, y):.4f}")

Notă tehnică a traducerii: metoda r_squared împarte la ss_tot fără să trateze cazul unei ținte constante, pentru care ss_tot = 0. Blocul executabil a fost păstrat exact.

Pasul 3: ecuația normală (soluție în formă închisă)

class LinearRegressionNormal:
    def __init__(self):
        self.w = 0.0
        self.b = 0.0

    def fit(self, X, y):
        n = len(X)
        x_mean = sum(X) / n
        y_mean = sum(y) / n
        numerator = sum((X[i] - x_mean) * (y[i] - y_mean) for i in range(n))
        denominator = sum((X[i] - x_mean) ** 2 for i in range(n))
        self.w = numerator / denominator
        self.b = y_mean - self.w * x_mean
        return self

    def predict(self, X):
        return [self.w * x + self.b for x in X]

    def r_squared(self, X, y):
        predictions = self.predict(X)
        y_mean = sum(y) / len(y)
        ss_res = sum((actual - pred) ** 2 for actual, pred in zip(y, predictions))
        ss_tot = sum((actual - y_mean) ** 2 for actual in y)
        return 1 - (ss_res / ss_tot)


print("\n=== Normal Equation (Closed-Form) ===")
model_normal = LinearRegressionNormal()
model_normal.fit(X, y)
print(f"Learned: y = {model_normal.w:.4f}x + {model_normal.b:.4f}")
print(f"R-squared: {model_normal.r_squared(X, y):.4f}")

Notă tehnică a traducerii: implementarea univariată împarte la varianța nenormalizată a lui X. Dacă toate valorile X sunt identice, numitorul este zero și panta nu poate fi identificată. Aceeași implementare a lui R^2 are și problema țintei constante menționată mai sus.

Pasul 4: regresie liniară multiplă

class MultipleLinearRegression:
    def __init__(self, n_features, learning_rate=0.01):
        self.weights = [0.0] * n_features
        self.bias = 0.0
        self.lr = learning_rate
        self.cost_history = []

    def predict_single(self, x):
        return sum(w * xi for w, xi in zip(self.weights, x)) + self.bias

    def predict(self, X):
        return [self.predict_single(x) for x in X]

    def compute_cost(self, X, y):
        predictions = self.predict(X)
        n = len(y)
        return sum((pred - actual) ** 2 for pred, actual in zip(predictions, y)) / n

    def fit(self, X, y, epochs=1000, print_every=200):
        n = len(y)
        n_features = len(X[0])
        for epoch in range(epochs):
            predictions = self.predict(X)
            errors = [pred - actual for pred, actual in zip(predictions, y)]
            for j in range(n_features):
                grad = (2 / n) * sum(errors[i] * X[i][j] for i in range(n))
                self.weights[j] -= self.lr * grad
            grad_b = (2 / n) * sum(errors)
            self.bias -= self.lr * grad_b
            cost = self.compute_cost(X, y)
            self.cost_history.append(cost)
            if epoch % print_every == 0:
                print(f"  Epoch {epoch:4d} | Cost: {cost:.4f}")
        return self

    def r_squared(self, X, y):
        predictions = self.predict(X)
        y_mean = sum(y) / len(y)
        ss_res = sum((actual - pred) ** 2 for actual, pred in zip(y, predictions))
        ss_tot = sum((actual - y_mean) ** 2 for actual in y)
        return 1 - (ss_res / ss_tot)


random.seed(42)
N = 100
X_multi = []
y_multi = []
for _ in range(N):
    size = random.uniform(500, 3000)
    bedrooms = random.randint(1, 5)
    age = random.uniform(0, 50)
    price = 50 * size + 10000 * bedrooms - 1000 * age + 50000 + random.gauss(0, 20000)
    X_multi.append([size, bedrooms, age])
    y_multi.append(price)


def standardize(X):
    n_features = len(X[0])
    means = [sum(X[i][j] for i in range(len(X))) / len(X) for j in range(n_features)]
    stds = []
    for j in range(n_features):
        variance = sum((X[i][j] - means[j]) ** 2 for i in range(len(X))) / len(X)
        stds.append(variance ** 0.5)
    X_scaled = []
    for i in range(len(X)):
        row = [(X[i][j] - means[j]) / stds[j] if stds[j] > 0 else 0 for j in range(n_features)]
        X_scaled.append(row)
    return X_scaled, means, stds


y_mean_val = sum(y_multi) / len(y_multi)
y_std_val = (sum((yi - y_mean_val) ** 2 for yi in y_multi) / len(y_multi)) ** 0.5
y_scaled = [(yi - y_mean_val) / y_std_val for yi in y_multi]

X_scaled, x_means, x_stds = standardize(X_multi)

print("\n=== Multiple Linear Regression (3 features) ===")
print("Features: house size, bedrooms, age")
multi_model = MultipleLinearRegression(n_features=3, learning_rate=0.01)
multi_model.fit(X_scaled, y_scaled, epochs=1000, print_every=200)

print(f"\nWeights (standardized): {[round(w, 4) for w in multi_model.weights]}")
print(f"Bias (standardized): {multi_model.bias:.4f}")
print(f"R-squared: {multi_model.r_squared(X_scaled, y_scaled):.4f}")

Deoarece atât intrările, cât și ținta sunt standardizate, fiecare pondere arată cu câte abateri standard se modifică prețul la creșterea caracteristicii respective cu o abatere standard, menținând celelalte caracteristici constante. Pentru coeficienți în unitățile originale, folosiți beta_j = y_std_val * weight_j / x_stds[j]; ordonata la origine trebuie transformată în mod corespunzător folosind mediile.

Pasul 5: regresie polinomială

class PolynomialRegression:
    def __init__(self, degree, learning_rate=0.01):
        self.degree = degree
        self.weights = [0.0] * degree
        self.bias = 0.0
        self.lr = learning_rate

    def make_features(self, X):
        return [[x ** (d + 1) for d in range(self.degree)] for x in X]

    def predict(self, X):
        features = self.make_features(X)
        return [sum(w * f for w, f in zip(self.weights, row)) + self.bias for row in features]

    def fit(self, X, y, epochs=1000, print_every=200):
        features = self.make_features(X)
        n = len(y)
        for epoch in range(epochs):
            predictions = [sum(w * f for w, f in zip(self.weights, row)) + self.bias for row in features]
            errors = [pred - actual for pred, actual in zip(predictions, y)]
            for j in range(self.degree):
                grad = (2 / n) * sum(errors[i] * features[i][j] for i in range(n))
                self.weights[j] -= self.lr * grad
            grad_b = (2 / n) * sum(errors)
            self.bias -= self.lr * grad_b
            if epoch % print_every == 0:
                cost = sum(e ** 2 for e in errors) / n
                print(f"  Epoch {epoch:4d} | Cost: {cost:.6f}")
        return self

    def r_squared(self, X, y):
        predictions = self.predict(X)
        y_mean = sum(y) / len(y)
        ss_res = sum((actual - pred) ** 2 for actual, pred in zip(y, predictions))
        ss_tot = sum((actual - y_mean) ** 2 for actual in y)
        return 1 - (ss_res / ss_tot)


random.seed(42)
X_poly = [x / 10.0 for x in range(0, 50)]
y_poly = [0.5 * x ** 2 - 2 * x + 3 + random.gauss(0, 1.0) for x in X_poly]

x_max = max(abs(x) for x in X_poly)
X_poly_norm = [x / x_max for x in X_poly]
y_poly_mean = sum(y_poly) / len(y_poly)
y_poly_std = (sum((yi - y_poly_mean) ** 2 for yi in y_poly) / len(y_poly)) ** 0.5
y_poly_norm = [(yi - y_poly_mean) / y_poly_std for yi in y_poly]

print("\n=== Polynomial Regression (degree 2 vs degree 5) ===")
print("True relationship: y = 0.5x^2 - 2x + 3")

print("\nDegree 2:")
poly2 = PolynomialRegression(degree=2, learning_rate=0.1)
poly2.fit(X_poly_norm, y_poly_norm, epochs=2000, print_every=500)
print(f"  R-squared: {poly2.r_squared(X_poly_norm, y_poly_norm):.4f}")

print("\nDegree 5:")
poly5 = PolynomialRegression(degree=5, learning_rate=0.1)
poly5.fit(X_poly_norm, y_poly_norm, epochs=2000, print_every=500)
print(f"  R-squared: {poly5.r_squared(X_poly_norm, y_poly_norm):.4f}")

print("\nDegree 2 fits the true curve well. Degree 5 fits training data slightly better")
print("but risks overfitting on new data.")

Pasul 6: regresie Ridge (regularizare L2)

class RidgeRegression:
    def __init__(self, n_features, learning_rate=0.01, alpha=1.0):
        self.weights = [0.0] * n_features
        self.bias = 0.0
        self.lr = learning_rate
        self.alpha = alpha

    def predict_single(self, x):
        return sum(w * xi for w, xi in zip(self.weights, x)) + self.bias

    def predict(self, X):
        return [self.predict_single(x) for x in X]

    def fit(self, X, y, epochs=1000, print_every=200):
        n = len(y)
        n_features = len(X[0])
        for epoch in range(epochs):
            predictions = self.predict(X)
            errors = [pred - actual for pred, actual in zip(predictions, y)]
            mse = sum(e ** 2 for e in errors) / n
            reg_term = self.alpha * sum(w ** 2 for w in self.weights)
            cost = mse + reg_term
            for j in range(n_features):
                grad = (2 / n) * sum(errors[i] * X[i][j] for i in range(n))
                grad += 2 * self.alpha * self.weights[j]
                self.weights[j] -= self.lr * grad
            grad_b = (2 / n) * sum(errors)
            self.bias -= self.lr * grad_b
            if epoch % print_every == 0:
                print(f"  Epoch {epoch:4d} | Cost: {cost:.4f} | L2 penalty: {reg_term:.4f}")
        return self


print("\n=== Ridge Regression (L2 Regularization) ===")
print("Same data as multiple regression, with alpha=0.1")
ridge = RidgeRegression(n_features=3, learning_rate=0.01, alpha=0.1)
ridge.fit(X_scaled, y_scaled, epochs=1000, print_every=200)
print(f"\nRidge weights: {[round(w, 4) for w in ridge.weights]}")
print(f"Plain weights: {[round(w, 4) for w in multi_model.weights]}")
print("Ridge weights are smaller (shrunk toward zero) due to the L2 penalty.")

Folosiți

Acum implementați același tip de model cu scikit-learn, biblioteca pe care o veți folosi efectiv în producție.

from sklearn.linear_model import LinearRegression as SklearnLR
from sklearn.linear_model import Ridge
from sklearn.preprocessing import PolynomialFeatures, StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

np.random.seed(42)
X_sk = np.random.uniform(0, 10, (100, 1))
y_sk = 3.0 * X_sk.squeeze() + 7.0 + np.random.normal(0, 2.0, 100)

X_train, X_test, y_train, y_test = train_test_split(X_sk, y_sk, test_size=0.2, random_state=42)

lr = SklearnLR()
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)

print("=== Scikit-learn Linear Regression ===")
print(f"Coefficient (w): {lr.coef_[0]:.4f}")
print(f"Intercept (b): {lr.intercept_:.4f}")
print(f"R-squared (test): {r2_score(y_test, y_pred):.4f}")
print(f"MSE (test): {mean_squared_error(y_test, y_pred):.4f}")

poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly_sk = poly.fit_transform(X_train)
X_poly_test = poly.transform(X_test)

lr_poly = SklearnLR()
lr_poly.fit(X_poly_sk, y_train)
print(f"\nPolynomial degree 2 R-squared: {r2_score(y_test, lr_poly.predict(X_poly_test)):.4f}")

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

ridge = Ridge(alpha=1.0)
ridge.fit(X_train_scaled, y_train)
print(f"Ridge R-squared: {r2_score(y_test, ridge.predict(X_test_scaled)):.4f}")
print(f"Ridge coefficient: {ridge.coef_[0]:.4f}")

Implementarea de la zero și scikit-learn rezolvă aceeași clasă de probleme și ar trebui să recupereze aproximativ relația generatoare y = 3x + 7, în limitele zgomotului și ale eșantionării. scikit-learn tratează cazurile-limită, stabilitatea numerică și optimizările de performanță. Folosiți biblioteca în producție și versiunea de la zero pentru a înțelege ce se întâmplă.

Notă tehnică a traducerii: originalul afirmă că cele două implementări produc „aceleași rezultate”, dar blocul scikit-learn generează un set de date nou cu generatorul NumPy și apoi îl împarte în antrenare/testare, pe când exemplul de la zero folosește modulul random și evaluează pe toate datele. Rezultatele numerice nu sunt direct identice sau comparabile fără același set și aceeași împărțire.

Livrați

Această lecție produce:

  • outputs/skill-regression.md — o competență pentru alegerea abordării de regresie potrivite problemei

Exerciții

  1. Implementați coborârea pe gradient în lot complet, coborârea stocastică pe gradient (SGD) și coborârea pe gradient cu miniloturi. Comparați viteza de convergență pe același set de date. Care ajunge prima la un prag de cost stabilit? Care are cea mai netedă curbă a costului?

Notă tehnică a traducerii: nu există o variantă universal „cea mai rapidă”. Comparația depinde de rata de învățare, dimensiunea lotului, costul măsurat pe epocă sau pe actualizare și pragul de convergență; formulați aceleași criterii și același buget de calcul pentru toate metodele.

  1. Generați date dintr-o funcție cubică (y = ax^3 + bx^2 + cx + d + noise). Ajustați polinoame de gradele 1, 3 și 10. Comparați R^2 pe datele de antrenare și pe cele de testare. De la ce grad devine evidentă supraînvățarea?

  2. Implementați regresia Lasso (regularizare L1: penalty = alpha * sum(|w_i|)). Antrenați-o pe datele despre locuințe cu mai multe caracteristici. Comparați ponderile care ajung la zero cu cele din Ridge. De ce L1 favorizează soluții rare, în timp ce L2 nu are aceeași tendință?

Notă tehnică a traducerii: penalizarea L1 poate produce coeficienți exact zero cu un rezolvitor adecvat, de exemplu coborâre pe coordonate cu prag moale, dar nu garantează că fiecare set de date sau fiecare valoare alpha va elimina caracteristici. O implementare naivă prin gradient trebuie să trateze nediferențiabilitatea în zero.

Termeni-cheie

Termen Ce spun oamenii Ce înseamnă de fapt
Regresie liniară „Trasați o dreaptă prin date” Găsiți ponderea w și biasul b care minimizează suma diferențelor pătratice dintre wx+b și valorile y reale
Funcție de cost „Cât de slab este modelul” O funcție care transformă parametrii modelului într-un singur număr ce măsoară eroarea de predicție și este minimizat prin optimizare
Eroare pătratică medie „Media erorilor ridicate la pătrat” (1/n) * sum((predicted - actual)^2), care penalizează disproporționat erorile mari
Coborâre pe gradient „Coborâți panta” Ajustați iterativ parametrii în direcția care reduce funcția de cost, folosind derivate parțiale
Rată de învățare „Mărimea pasului” Un scalar care controlează cât se modifică parametrii la fiecare pas al coborârii pe gradient
Ecuația normală „Rezolvați direct” Sistemul de ecuații normale al celor mai mici pătrate; formula cu inversă (X^T X)^-1 X^T y este valabilă când matricea are rang complet
R pătrat „Cât de bună este ajustarea” Coeficientul de determinare 1 - SS_res/SS_tot, cu valoare maximă 1 și posibil negativă; cazul țintei constante necesită tratament separat
Scalarea caracteristicilor „Faceți caracteristicile comparabile” Transformarea caracteristicilor la scări similare, de exemplu medie zero și varianță unitară, pentru a accelera convergența coborârii pe gradient
Regularizare „Penalizați complexitatea” Adăugarea unui termen la funcția de cost care micșorează ponderile și poate reduce supraînvățarea
Regresie Ridge „Regularizare L2” Regresie liniară cu penalizarea lambda * sum(w_i^2) adăugată la pierderea pătratică
Regresie polinomială „Ajustarea curbelor cu algebră liniară” Regresie liniară pe caracteristici polinomiale (x, x^2, x^3, …), în continuare liniară în ponderi
Supraînvățare „Memorarea datelor de antrenare” Folosirea unui model atât de flexibil încât ajustează zgomotul din antrenare și eșuează pe date noi

Lecturi suplimentare


Sursă: Linear Regression — original

Navigare: înapoi: 02.01 — Ce este învățarea automată · Faza 2 — Bazele învățării automate · Catalog complet · în continuare: 02.03 — Regresie logistică.