La maggior parte dei problemi che incontriamo può essere risolta in diversi modi. Per esempio, se volessimo andare da un lato all'altro di una stanza, potremmo decidere di camminare tutto intorno fino ad arrivare al lato opposto, oppure potremmo tagliare direttamente di traverso.
L'equazione normale mette semplicemente in evidenza questo concetto. È solo un altro modo per risolvere un problema. Quale problema, ti chiedi? Lo vedremo nel resto di questo articolo. Per ora, ti basta sapere che è un approccio efficace che può farti risparmiare molto tempo quando implementi la regressione lineare in determinate condizioni.
Andiamo più a fondo…
Che cos'è l'equazione normale?
L'equazione normale è una soluzione in forma chiusa usata per trovare il valore di θ che minimizza la funzione di costo per la regressione lineare con minimi quadrati ordinari. Un altro modo per descriverla è come un approccio analitico per trovare i coefficienti che minimizzano la funzione di perdita. Entrambe le descrizioni vanno bene, ma cosa significano esattamente?
La regressione lineare fa una previsione, y_hat, calcolando la somma pesata delle feature in input più un termine di bias. Matematicamente, può essere rappresentata così:

Dove θ rappresenta i parametri e n è il numero di feature.
In sostanza, in quell'equazione non avviene altro che il prodotto scalare tra θ e x seguito da una somma. Un modo più conciso di rappresentarla è usare la forma vettoriale:

h(θ) è la funzione ipotesi.
Data questa funzione obiettivo approssimata, possiamo usare il nostro modello per fare previsioni. Per capire se il modello ha imparato bene, è importante misurarne le prestazioni sui dati di training. A questo scopo, calcoliamo una funzione di perdita. L'obiettivo del processo di training è trovare i valori di theta (θ) che minimizzano la funzione di perdita.
Ecco come possiamo rappresentare matematicamente la nostra funzione di perdita:

Nell'equazione sopra, theta (θ) è un vettore di dimensione n + 1 e la nostra funzione di perdita è una funzione del valore vettoriale. Di conseguenza, bisogna calcolare la derivata parziale della funzione di perdita, J, rispetto a ogni parametro di θ_j, uno alla volta. Tutte devono essere uguali a zero. Seguendo questo processo e risolvendo per tutti i valori di θ da θ_0 a θ_n si ottengono i valori di θ che minimizzano la funzione di perdita.
Lavorare alla soluzione dei parametri da θ_0 a θ_n con il processo descritto sopra porta a una derivazione estremamente laboriosa. Esiste effettivamente una soluzione più rapida.
Guarda la formula dell'equazione normale:

Dove:
θ → I parametri che minimizzano la funzione di perdita X → I valori delle feature in input per ciascuna istanza y → Il vettore dei valori di output per ciascuna istanza
Equazione normale vs gradient descent
Anche se entrambi i metodi cercano i parametri theta (θ) che minimizzano la funzione di perdita, l'approccio seguito è molto diverso tra le due soluzioni.
Poiché abbiamo già visto come funziona l'equazione normale nella sezione precedente, accenneremo brevemente al gradient descent e poi spiegheremo in cosa differiscono le due tecniche.
Gradient descent
Il gradient descent è uno degli algoritmi più usati nel machine learning. Viene impiegato per trovare iterativamente i parametri theta (θ) che minimizzano la funzione di perdita.
Il processo inizia valutando le prestazioni del modello. Poi si calcola la derivata parziale della funzione di perdita, che serve a individuare la pendenza nel punto corrente. Infine, si compiono passi proporzionali al gradiente negativo per scendere verso il minimo della funzione di perdita aggiornando l'attuale insieme di parametri - vedi formula sotto.

Questo processo si ripete fino alla convergenza al minimo della funzione di perdita.
In cosa differiscono?
Il modo più evidente in cui l'equazione normale differisce dal gradient descent è che è analitica. Il gradient descent adotta un approccio iterativo, il che significa che i nostri parametri vengono aggiornati gradualmente fino alla convergenza. Un'altra differenza implicita è che il gradient descent richiede di definire un learning rate che controlla l'ampiezza dei passi verso il minimo della funzione di perdita. L'equazione normale non richiede di definire un learning rate perché non facciamo passi iterativi: otteniamo i risultati direttamente.
Inoltre, la scalatura delle feature non è richiesta quando usiamo l'equazione normale; in genere eseguiamo il feature scaling per fare in modo che le feature abbiano intervalli di valori simili. Questo perché il gradient descent è sensibile agli intervalli dei nostri punti dati. Se non normalizziamo le feature quando usiamo il gradient descent, potremmo introdurre asimmetrie nel grafico a contorni della funzione di perdita, mentre l'equazione normale non soffre di questo problema.
Capire quando usare l'equazione normale
Il modo migliore per sapere se dovresti usare l'equazione normale invece del gradient descent è capirne gli svantaggi.
Calcolare l'equazione normale diventa computazionalmente impegnativo quando il numero di feature nel nostro dataset è elevato. Il motivo è che, per risolvere i parametri θ, bisogna calcolare il termine (X’ X)^-1. Calcolare X’ X produce una matrice n x n e, per la maggior parte delle implementazioni, invertire una matrice ha un costo che cresce approssimativamente con il cubo della sua dimensione. Ciò significa che l'operazione di inversione ha complessità temporale O(n^3), il che rende l'equazione normale estremamente lenta quando n è molto grande - scopri di più sulla complessità temporale.
Quindi è meglio usare il gradient descent quando il numero di feature nel dataset è grande. Andrew Ng, un noto esperto di machine learning e IA, consiglia di prendere in considerazione il gradient descent quando il numero di feature, n, è superiore a 10.000. Con 10.000 feature o meno, potresti trovarti meglio con un approccio analitico come l'equazione normale, dato che non devi scegliere un valore per il learning rate, il che significa avere un iperparametro in meno da ottimizzare. Tuttavia, va detto che linguaggi come R o Python in realtà usano la decomposizione QR per trovare i coefficienti di una regressione lineare con minimi quadrati ordinari, perché la decomposizione QR è numericamente più stabile ed efficiente dell'equazione normale.
Equazione normale da zero in Python
Generiamo un problema di regressione per testare questa equazione:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression
# Generate a regression problem
X, y = make_regression(
n_samples=100,
n_features=2,
n_informative=2,
noise = 10,
random_state=25
)
# Visualize feature at index 1 vs target
plt.subplots(figsize=(8, 5))
plt.scatter(X[:, 1], y, marker='o')
plt.xlabel("Feature at Index 1")
plt.ylabel("Target")
plt.show()

Ecco dove implementeremo l'equazione normale:
# adds x0 = 1 to each instance
X_b = np.concatenate([np.ones((len(X), 1)), X], axis=1)
# calculate normal equation
theta_best = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y)
# best values for theta
intercept, *coef = theta_best
print(f"Intercept: {intercept}\n\
Coefficients: {coef}")
Intercept: 0.35921242677977794
Coefficients: [6.129199175400593, 96.44309685893134]
Mettiamo alla prova il nostro modello facendo una previsione:
# making a new sample
new_sample = np.array([[-2, 0.25]])
# adding a bias term to the instance
new_sample_b = np.concatenate([np.ones((len(new_sample), 1)), new_sample], axis=1)
# predicting the value of our new sample
new_sample_pred = new_sample_b.dot(theta_best)
print(f"Prediction: {new_sample_pred}")
Prediction: [12.21158829]
Quando implementi un algoritmo di machine learning da zero, è sempre utile avere un metodo per convalidare la tua soluzione; Scikit-learn è una delle librerie di machine learning più popolari in Python. Include diverse implementazioni di algoritmi, tra cui la regressione lineare, che useremo per convalidare la nostra equazione normale.
from sklearn.linear_model import LinearRegression
lr = LinearRegression()
lr.fit(X, y)
print(f"Intercept: {lr.intercept_}\n\
Coefficients: {lr.coef_}")
print(f"Prediction: {lr.predict(new_sample)}")
Intercept: 0.3592124267797807
Coefficients: [ 6.12919918 96.44309686]
Prediction: [12.21158829]
Le soluzioni sono approssimativamente uguali, quindi possiamo confermare che la nostra soluzione è corretta.
Domande frequenti (FAQ)
Cos'è l'equazione normale nel machine learning?
L'equazione normale è un approccio analitico per trovare il valore di θ che minimizza la funzione di perdita senza dover iterare.
Quando dovrei usare l'equazione normale invece del gradient descent?
È meglio usare l'equazione normale quando abbiamo poche feature. Calcolare l'equazione normale diventa computazionalmente impegnativo quando il numero di feature nel nostro dataset è elevato.
Si può usare l'equazione normale per la regressione logistica?
Purtroppo no. Esiste un solo modello condizionale nella teoria della classificazione che ha una soluzione in forma chiusa: la regressione lineare.
Qual è la differenza tra l'equazione normale e il gradient descent?
La differenza evidente tra l'equazione normale e il gradient descent è che l'equazione normale usa un approccio analitico per trovare il minimo della funzione di perdita, mentre il gradient descent usa un approccio iterativo. Un'altra differenza è che non devi regolare un learning rate per calcolare l'equazione normale, dato che si compie un solo passo per trovare i parametri θ.

