<marco />
← Tutti gli articoli
26 min di lettura

Regressione lineare multipla: forma matriciale ed equazioni normali

aiprogrammazione

Nell'articolo sulla regressione lineare abbiamo stimato il prezzo di un appartamento a partire dalla sola superficie. La retta funzionava bene, ma sbagliava comunque di qualche migliaio di euro: due appartamenti di metratura simile possono costare diversamente per tanti motivi.

Uno di questi è l'età dell'immobile. In questo articolo la aggiungiamo al modello e vediamo come cambiano i conti quando le variabili sono più di una: si passa dalle formule con le sommatorie alla forma matriciale, che vale per qualunque numero di variabili.

I dati

Agli stessi dieci appartamenti aggiungiamo gli anni dalla costruzione:

Superficie (m²) Età (anni) Prezzo (k€)
40 20 105
50 45 120
55 25 140
65 40 150
70 10 175
80 30 185
90 15 210
100 35 225
110 20 255
120 40 265

Guardando i residui della retta del primo articolo, l'appartamento da 70 m² costava 8,5 k€ più del previsto e quello da 65 m² 6,2 k€ meno: il primo ha 10 anni, il secondo 40. L'età sembra spiegare una parte di quegli errori.

La notazione

Con più variabili, mm e qq non bastano più. Si usa una notazione generale:

y(i)=θ0+θ1 φ1(i)+θ2 φ2(i)+…+θd−1 φd−1(i)+ε(i)\begin{aligned} y(i) = \theta_0 &+ \theta_1\,\varphi_1(i) + \theta_2\,\varphi_2(i) + \dots \\ &+ \theta_{d-1}\,\varphi_{d-1}(i) + \varepsilon(i) \end{aligned}
  • ii indica l'osservazione: l'i-esimo appartamento, da 1 a NN;
  • φ1,φ2,…\varphi_1, \varphi_2, \dots sono i regressori (o feature): le variabili di input, qui superficie ed età;
  • θ0,θ1,…\theta_0, \theta_1, \dots sono i parametri da stimare. θ0\theta_0 è l'intercetta, quella che prima chiamavamo qq;
  • ε(i)\varepsilon(i) è l'errore: la parte di y(i)y(i) che il modello non riesce a spiegare.

Il caso del primo articolo è quello con un solo regressore: θ0=q\theta_0 = q, θ1=m\theta_1 = m.

C'è un trucco che semplifica tutto: si aggiunge un regressore finto φ0=1\varphi_0 = 1, sempre uguale a uno. Così anche l'intercetta diventa un parametro "moltiplicato per qualcosa", e l'intero modello si scrive come un prodotto scalare tra due vettori:

φ(i)=[1φ1(i)⋮φd−1(i)]∈Rd\varphi(i) = \begin{bmatrix} 1 \\ \varphi_1(i) \\ \vdots \\ \varphi_{d-1}(i) \end{bmatrix} \in \mathbb{R}^{d} θ=[θ0θ1⋮θd−1]∈Rd\theta = \begin{bmatrix} \theta_0 \\ \theta_1 \\ \vdots \\ \theta_{d-1} \end{bmatrix} \in \mathbb{R}^{d} y(i)=φ(i)⊤θ+ε(i)y(i) = \varphi(i)^\top \theta + \varepsilon(i)

dd è il numero di parametri, intercetta compresa. Nel nostro esempio d=3d = 3: intercetta, superficie, età.

Con un regressore il modello è una retta, con due è un piano nello spazio tridimensionale (superficie, età, prezzo). Oltre è un iperpiano, che non si può disegnare ma si calcola esattamente allo stesso modo.

Tutto in una matrice

Scrivere un'equazione per ogni appartamento diventa scomodo. Si impilano allora le NN osservazioni una sotto l'altra:

XN×d=[φ(1)⊤φ(2)⊤⋮φ(N)⊤]=[1402015045⋮⋮⋮112040]\underset{N \times d}{X} = \begin{bmatrix} \varphi(1)^\top \\ \varphi(2)^\top \\ \vdots \\ \varphi(N)^\top \end{bmatrix} = \begin{bmatrix} 1 & 40 & 20 \\ 1 & 50 & 45 \\ \vdots & \vdots & \vdots \\ 1 & 120 & 40 \end{bmatrix} YN×1=[y(1)y(2)⋮y(N)]=[105120⋮265]θd×1=[θ0θ1θ2]\underset{N \times 1}{Y} = \begin{bmatrix} y(1) \\ y(2) \\ \vdots \\ y(N) \end{bmatrix} = \begin{bmatrix} 105 \\ 120 \\ \vdots \\ 265 \end{bmatrix} \qquad \underset{d \times 1}{\theta} = \begin{bmatrix} \theta_0 \\ \theta_1 \\ \theta_2 \end{bmatrix}

Ogni riga di XX è un appartamento, ogni colonna un regressore. La prima colonna è tutta di uni: è il φ0=1\varphi_0 = 1 di prima. Le dieci equazioni diventano una sola:

Y=Xθ+EY = X\theta + E

dove EE è il vettore dei dieci errori.

La funzione di costo

È lo stesso errore quadratico medio del primo articolo, riscritto con i nuovi simboli. La previsione per l'appartamento ii prima era m xi+qm\,x_i + q, ora è φ(i)⊤θ\varphi(i)^\top\theta; l'MSE prende il nome di funzione di costo e si indica con J(θ)J(\theta):

J(θ)=1N∑i=1N(y(i)−φ(i)⊤θ)2J(\theta) = \frac{1}{N} \sum_{i=1}^{N} \bigl( y(i) - \varphi(i)^\top \theta \bigr)^2

La stessa formula, con i vettori

La sommatoria si può scrivere in modo più compatto usando le matrici della sezione precedente:

  • XθX\theta è il vettore delle previsioni: moltiplicare la matrice per θ\theta calcola φ(i)⊤θ\varphi(i)^\top\theta per ogni riga, cioè per ogni appartamento;
  • Y−XθY - X\theta è quindi il vettore dei residui, uno per appartamento;
  • ∥v∥2\lVert v \rVert^2, la norma al quadrato di un vettore, è la somma dei quadrati dei suoi elementi: v12+v22+⋯+vN2v_1^2 + v_2^2 + \dots + v_N^2.

Mettendo insieme le tre cose, la somma dei residui al quadrato diventa ∥Y−Xθ∥2\lVert Y - X\theta \rVert^2:

J(θ)=1N ∥Y−Xθ∥2J(\theta) = \frac{1}{N} \, \lVert Y - X\theta \rVert^2
Esempio

Scegliamo dei parametri e calcoliamo JJ a mano, nei due modi. Prendiamo:

Parametro Valore Significato
θ0\theta_0 30 k€ prezzo di partenza, fisso
θ1\theta_1 2 k€/m² quanto vale ogni metro quadro
θ2\theta_2 0 k€/anno l'età non conta

Con θ2=0\theta_2 = 0 l'età sparisce dal modello, e resta la retta y^=2x+30\hat y = 2x + 30: è la "retta B" del primo articolo, che lì aveva MSE 35 k€².

1. La previsione per un appartamento. Si moltiplica la sua riga di XX per θ\theta, termine a termine, e si somma. Per il primo appartamento (40 m², 20 anni) la riga è [1, 40, 20][1,\ 40,\ 20]:

φ(1)⊤θ=1⋅30+40⋅2+20⋅0=110 k€\begin{aligned} \varphi(1)^\top \theta &= 1 \cdot 30 + 40 \cdot 2 + 20 \cdot 0 \\ &= 110 \ \text{k€} \end{aligned}

Il prezzo vero è 105 k€, quindi il residuo è 105−110=−5105 - 110 = -5 k€: il modello sovrastima di 5.

2. Lo stesso per tutte le righe. Ripetendo il conto per ogni appartamento:

# m² Anni Previsto φ(i)⊤θ\varphi(i)^\top\theta (k€) Vero y(i)y(i) (k€) Residuo (k€) Residuo² (k€²)
1 40 20 110 105 −5 25
2 50 45 130 120 −10 100
3 55 25 140 140 0 0
4 65 40 160 150 −10 100
5 70 10 170 175 +5 25
6 80 30 190 185 −5 25
7 90 15 210 210 0 0
8 100 35 230 225 −5 25
9 110 20 250 255 +5 25
10 120 40 270 265 −5 25
Somma 350

3. Con la formula sommatoria si fa esattamente questo: si sommano i residui al quadrato dell'ultima colonna (350 k€²) e si divide per N=10N = 10, cioè J=35J = 35 k€².

4. Con la formula vettoriale si fa lo stesso conto, ma guardando le colonne della tabella come vettori:

  • la colonna "Previsto" è il vettore XθX\theta;
  • la colonna "Vero" è il vettore YY;
  • la colonna "Residuo" è la loro differenza, Y−XθY - X\theta:
Y−Xθ=(−5, −10, 0, −10, 5,−5, 0, −5, 5, −5)⊤\begin{aligned} Y - X\theta = (&{-5},\ -10,\ 0,\ -10,\ 5, \\ &{-5},\ 0,\ -5,\ 5,\ -5)^\top \end{aligned}

La norma al quadrato ∥Y−Xθ∥2\lVert Y - X\theta \rVert^2 è la somma dei quadrati di questi dieci numeri, cioè di nuovo 350 k€², e J=350/10=35J = 350 / 10 = 35 k€².

I due modi danno lo stesso risultato perché sono lo stesso calcolo: la sommatoria lo scrive riga per riga, la forma vettoriale tutto in una volta. La seconda è più comoda per fare i conti con le matrici, ed è quella che useremo da qui in avanti.

Il θ migliore

La stima θ^\hat\theta è il vettore che rende JJ più piccolo possibile, e si scrive così:

θ^=arg⁡min⁡θJ(θ)\hat\theta = \arg\min_{\theta} J(\theta)

Attenzione alla differenza tra le due parole:

  • min⁡θJ(θ)\min_\theta J(\theta) è il valore più basso che l'errore può raggiungere. Nel nostro esempio, 4,28 k€²;
  • arg⁡min⁡θJ(θ)\arg\min_\theta J(\theta) è il θ\theta che lo raggiunge, cioè i parametri da usare: θ^=(32,59; 2,069; −0,392)\hat\theta = (32{,}59;\ 2{,}069;\ -0{,}392), come vedremo tra poco. "arg" sta per argomento, il valore da mettere dentro la funzione.

A noi interessa il secondo: non quanto vale l'errore minimo, ma quale modello lo produce.

Perché il minimo è unico

Nel primo articolo, tenendo fermo qq e muovendo solo mm, l'MSE disegnava una curva a U. Qui succede lo stesso con qualunque parametro: ogni residuo y(i)−φ(i)⊤θy(i) - \varphi(i)^\top\theta è una funzione lineare di θ\theta, il suo quadrato è una parabola rivolta verso l'alto, e una somma di parabole rivolte verso l'alto è ancora una parabola rivolta verso l'alto.

Se JJ è una U in ogni direzione, nel suo insieme è una scodella. Una scodella ha un solo punto più basso: non ci sono "buche" secondarie in cui un algoritmo potrebbe fermarsi credendo di aver trovato il minimo. In matematica questa proprietà si chiama convessità.

C'è un'eccezione. Se due colonne di XX contengono la stessa informazione, la scodella ha il fondo piatto, come una grondaia, e i minimi sono infiniti. È il caso dei regressori ridondanti, che vedremo più avanti.

Le equazioni normali

Nel punto più basso della scodella, la funzione di costo non diminuisce più in nessuna direzione: il suo gradiente è nullo. Possiamo sfruttare questa proprietà per trovare direttamente i parametri che minimizzano l'errore, senza procedere per tentativi come nella discesa del gradiente.

Partiamo dalla funzione di costo della regressione lineare multipla:

J(θ)=1N∥Y−Xθ∥2J(\theta) = \frac{1}{N} \lVert Y - X\theta \rVert^2

Sviluppando il quadrato, otteniamo:

J(θ)=1N(Y⊤Y−2 θ⊤X⊤Y+θ⊤X⊤Xθ)\begin{aligned} J(\theta) = \frac{1}{N} \bigl( &Y^\top Y - 2\,\theta^\top X^\top Y \\ &+ \theta^\top X^\top X \theta \bigr) \end{aligned}
Formula, passo per passo

1. Dalla norma al prodotto matriciale. La norma al quadrato di un vettore è la somma dei quadrati dei suoi elementi. In notazione matriciale, questa operazione si scrive moltiplicando il vettore trasposto per il vettore stesso:

∥v∥2=v⊤v\lVert v \rVert^2 = v^\top v

Per esempio:

v=[34]⟹v⊤v=[34][34]v = \begin{bmatrix} 3 \\ 4 \end{bmatrix} \quad \Longrightarrow \quad v^\top v = \begin{bmatrix} 3 & 4 \end{bmatrix} \begin{bmatrix} 3 \\ 4 \end{bmatrix} v⊤v=32+42=25v^\top v = 3^2 + 4^2 = 25

Applicando la stessa regola al vettore degli errori Y−XθY - X\theta, otteniamo:

J(θ)=1N (Y−Xθ)⊤(Y−Xθ)J(\theta) = \frac{1}{N} \, (Y - X\theta)^\top (Y - X\theta)

2. Calcoliamo la trasposta. La trasposta di una differenza è la differenza delle trasposte. Inoltre, la trasposta di un prodotto inverte l'ordine dei fattori:

(Xθ)⊤=θ⊤X⊤(X\theta)^\top = \theta^\top X^\top

Di conseguenza:

(Y−Xθ)⊤=Y⊤−θ⊤X⊤(Y - X\theta)^\top = Y^\top - \theta^\top X^\top

3. Sviluppiamo il prodotto. Ora moltiplichiamo ogni termine della prima parentesi per ogni termine della seconda, proprio come nello sviluppo di (a−b)2(a - b)^2. Dobbiamo solo rispettare l'ordine dei fattori, perché le matrici non si possono scambiare liberamente:

(Y⊤−θ⊤X⊤)(Y−Xθ)=Y⊤Y−Y⊤Xθ−θ⊤X⊤Y+θ⊤X⊤Xθ\begin{aligned} &(Y^\top - \theta^\top X^\top)(Y - X\theta) \\ &= Y^\top Y - Y^\top X\theta \\ &\quad - \theta^\top X^\top Y + \theta^\top X^\top X\theta \end{aligned}

4. Perché i due termini centrali sono uguali? I termini

Y⊤Xθeθ⊤X⊤YY^\top X\theta \quad \text{e} \quad \theta^\top X^\top Y

sono entrambi scalari, cioè singoli numeri. Infatti, le dimensioni dei fattori nel primo prodotto sono:

(1×N)(N×d)(d×1)=1×1(1 \times N)(N \times d)(d \times 1) = 1 \times 1

Il secondo prodotto è il trasposto del primo. Lo vediamo applicando la regola della trasposta di un prodotto:

(Y⊤Xθ)⊤=θ⊤X⊤Y(Y^\top X\theta)^\top = \theta^\top X^\top Y

Ma il trasposto di uno scalare è lo scalare stesso. I due termini sono quindi uguali e possiamo sommarli:

−Y⊤Xθ−θ⊤X⊤Y=−2 θ⊤X⊤Y-Y^\top X\theta - \theta^\top X^\top Y = -2\,\theta^\top X^\top Y

Otteniamo così la formula iniziale:

J(θ)=1N(Y⊤Y−2 θ⊤X⊤Y+θ⊤X⊤Xθ)\begin{aligned} J(\theta) = \frac{1}{N} \bigl( &Y^\top Y - 2\,\theta^\top X^\top Y \\ &+ \theta^\top X^\top X \theta \bigr) \end{aligned}

Deriviamo la funzione di costo

Abbiamo sviluppato la funzione di costo in modo da separare i termini costanti da quelli che dipendono dai parametri θ\theta:

J(θ)=1N(Y⊤Y−2 θ⊤X⊤Y+θ⊤X⊤Xθ)\begin{aligned} J(\theta) = \frac{1}{N} \bigl( &Y^\top Y - 2\,\theta^\top X^\top Y \\ &+ \theta^\top X^\top X \theta \bigr) \end{aligned}

Ora vogliamo trovare i valori di θ\theta che rendono J(θ)J(\theta) minima. Per farlo, calcoliamo il gradiente, cioè il vettore delle derivate parziali rispetto a tutti i parametri del modello.

1. Due regole di derivazione matriciale

Ci servono due regole, che generalizzano quelle delle funzioni a una variabile:

∇x (x⊤b)=b∇x (x⊤Ax)=(A+A⊤) x\begin{aligned} \nabla_x \, (x^\top b) &= b \\ \nabla_x \, (x^\top A x) &= (A + A^\top)\, x \end{aligned}

Nella prima formula, bb è un vettore di costanti: la derivata di una funzione lineare restituisce i suoi coefficienti. È l'equivalente di:

ddx (b x)=b\frac{d}{dx}\,(b\,x) = b

La seconda formula riguarda invece una funzione quadratica. È l'equivalente della regola:

ddx (a x2)=2a x\frac{d}{dx}\,(a\,x^2) = 2a\,x

La differenza è che, nel caso matriciale, la derivata contiene A+A⊤A + A^\top, perché il vettore xx compare sia a sinistra sia a destra della matrice.

Se AA è simmetrica, cioè A⊤=AA^\top = A, la formula si semplifica:

∇x (x⊤Ax)=2A x\nabla_x \, (x^\top A x) = 2A\,x

2. Applichiamo le regole alla funzione di costo

Riprendiamo i tre termini di J(θ)J(\theta) e deriviamoli uno alla volta rispetto a θ\theta.

Primo termine: Y⊤YY^\top Y

∇θ (Y⊤Y)=0\nabla_\theta \, (Y^\top Y) = 0

Questo termine non dipende da θ\theta: contiene soltanto i dati osservati YY, che consideriamo costanti durante l'addestramento. La sua derivata è quindi zero.

Secondo termine: −2 θ⊤X⊤Y-2\,\theta^\top X^\top Y

Applichiamo la prima regola, identificando x=θx = \theta e b=X⊤Yb = X^\top Y:

∇θ (θ⊤X⊤Y)=X⊤Y\nabla_\theta \, (\theta^\top X^\top Y) = X^\top Y

Il fattore −2-2 rimane davanti alla derivata:

∇θ (−2 θ⊤X⊤Y)=−2 X⊤Y\nabla_\theta \, (-2\,\theta^\top X^\top Y) = -2\,X^\top Y

Terzo termine: θ⊤X⊤Xθ\theta^\top X^\top X \theta

Applichiamo la seconda regola, identificando x=θx = \theta e A=X⊤XA = X^\top X:

∇θ (θ⊤X⊤Xθ)=(X⊤X+(X⊤X)⊤) θ\begin{aligned} &\nabla_\theta \, (\theta^\top X^\top X \theta) \\ &= \bigl( X^\top X + (X^\top X)^\top \bigr)\, \theta \end{aligned}

La matrice X⊤XX^\top X è simmetrica, perché:

(X⊤X)⊤=X⊤X(X^\top X)^\top = X^\top X

I due termini nella parentesi sono quindi uguali. Possiamo sommarli:

∇θ (θ⊤X⊤Xθ)=2 X⊤Xθ\nabla_\theta \, (\theta^\top X^\top X \theta) = 2\,X^\top X \theta

3. Mettiamo insieme le derivate

La derivata di una somma è la somma delle derivate. Inoltre, il fattore costante 1/N1/N rimane davanti:

∇J(θ)=1N(−2 X⊤Y+2 X⊤Xθ)\nabla J(\theta) = \frac{1}{N} \bigl( -2\,X^\top Y + 2\,X^\top X \theta \bigr)

Abbiamo così ottenuto il gradiente della funzione di costo.

4. Poniamo il gradiente uguale a zero

Nel punto di minimo, il gradiente è nullo. Poniamo quindi:

1N(−2 X⊤Y+2 X⊤Xθ)=0\frac{1}{N} \bigl( -2\,X^\top Y + 2\,X^\top X \theta \bigr) = 0

Moltiplichiamo entrambi i membri per N/2N/2, eliminando i fattori costanti:

−X⊤Y+X⊤Xθ=0-X^\top Y + X^\top X \theta = 0

Portiamo il primo termine a destra:

X⊤X θ=X⊤YX^\top X \, \theta = X^\top Y

Queste sono le equazioni normali: abbiamo trasformato il problema di minimizzazione della funzione di costo in un sistema lineare di equazioni.

La soluzione in forma chiusa

Se X⊤XX^\top X è invertibile, possiamo moltiplicare entrambi i membri delle equazioni normali per (X⊤X)−1(X^\top X)^{-1}:

(X⊤X)−1X⊤X θ=(X⊤X)−1X⊤Y\begin{aligned} &(X^\top X)^{-1} X^\top X \, \theta \\ &= (X^\top X)^{-1} X^\top Y \end{aligned}

Poiché (X⊤X)−1X⊤X=I(X^\top X)^{-1} X^\top X = I, dove II è la matrice identità, rimane:

θ^=(X⊤X)−1X⊤Y\hat\theta = (X^\top X)^{-1} X^\top Y

Questa è la soluzione dei minimi quadrati in forma chiusa: una formula che permette di calcolare direttamente i parametri ottimali, senza aggiornamenti iterativi.

Se X⊤XX^\top X non è invertibile, la formula con l'inversa non è applicabile direttamente. Il problema può comunque avere soluzioni, eventualmente non uniche.

Con un solo regressore e un'intercetta, questa formula restituisce gli stessi parametri mm e qq della regressione lineare semplice. Cambia la notazione, ma il principio è identico.

Esempio

Con i nostri dieci appartamenti le tre colonne di XX sono gli uni dell'intercetta, le superfici xx e le età ee.

1. Le due matrici del sistema. Nel prodotto X⊤XX^\top X ogni casella è la somma, su tutti gli appartamenti, del prodotto tra due colonne di XX:

X⊤X=[N∑x∑e∑x∑x2∑x e∑e∑x e∑e2]X^\top X = \begin{bmatrix} N & \sum x & \sum e \\ \sum x & \sum x^2 & \sum x\,e \\ \sum e & \sum x\,e & \sum e^2 \end{bmatrix}

Per esempio, la casella al centro è la somma delle superfici al quadrato: 402+502+⋯+1202=67.25040^2 + 50^2 + \dots + 120^2 = 67.250. Con tutti i numeri:

X⊤X=[1078028078067.25021.97528021.9759.100]X^\top X = \begin{bmatrix} 10 & 780 & 280 \\ 780 & 67.250 & 21.975 \\ 280 & 21.975 & 9.100 \end{bmatrix}

Allo stesso modo X⊤YX^\top Y moltiplica ogni colonna di XX per i prezzi, e somma:

X⊤Y=[∑y∑x y∑e y]=[1.830155.95051.025]X^\top Y = \begin{bmatrix} \sum y \\ \sum x\,y \\ \sum e\,y \end{bmatrix} = \begin{bmatrix} 1.830 \\ 155.950 \\ 51.025 \end{bmatrix}

X⊤XX^\top X ha una riga e una colonna per ogni parametro.

2. Il sistema per esteso. Le equazioni normali X⊤X θ=X⊤YX^\top X\,\theta = X^\top Y, scritte riga per riga, sono tre equazioni nelle tre incognite θ0\theta_0, θ1\theta_1, θ2\theta_2:

10θ0+780θ1+280θ2=1.830780θ0+67.250θ1+21.975θ2=155.950280θ0+21.975θ1+9.100θ2=51.025\small \begin{aligned} 10\theta_0 + 780\theta_1 + 280\theta_2 &= 1.830 \\ 780\theta_0 + 67.250\theta_1 + 21.975\theta_2 &= 155.950 \\ 280\theta_0 + 21.975\theta_1 + 9.100\theta_2 &= 51.025 \end{aligned}

Si risolvono come un qualsiasi sistema lineare, a mano per sostituzione oppure con il computer.

3. La soluzione.

Parametro Significato Valore
θ0\theta_0 intercetta 32,59 k€
θ1\theta_1 per ogni m² in più +2,069 k€/m²
θ2\theta_2 per ogni anno in più −0,392 k€/anno

Controprova sulla prima equazione: 10⋅32,595+780⋅2,069+280⋅(−0,392)≈1.83010 \cdot 32{,}595 + 780 \cdot 2{,}069 + 280 \cdot (-0{,}392) \approx 1.830. Torna.

Ogni metro quadro vale circa 2.070 €, come prima. Ogni anno di età toglie circa 390 € al prezzo. L'errore quadratico medio scende da 23,6 a 4,3 k€² e l'R² sale da 0,991 a 0,998.

4. Previsione. Per un appartamento da 85 m² con 20 anni ora possiamo stimare il prezzo:

y^=32,59+2,069⋅85−0,392⋅20≈200,6 k€\begin{aligned} \hat y &= 32{,}59 + 2{,}069 \cdot 85 - 0{,}392 \cdot 20 \\ &\approx 200{,}6\ \text{k€} \end{aligned}

Ora dipendente anche dall'età:

Età Prezzo stimato
nuovo (0 anni) 208,5 k€
20 anni 200,6 k€
40 anni 192,8 k€

In Python, con NumPy, l'intero calcolo è una riga:

python
import numpy as np

superficie = np.array([40, 50, 55, 65, 70, 80, 90, 100, 110, 120])
eta = np.array([20, 45, 25, 40, 10, 30, 15, 35, 20, 40])
prezzo = np.array([105, 120, 140, 150, 175, 185, 210, 225, 255, 265])

# la colonna di uni è il regressore finto per l'intercetta
X = np.column_stack([np.ones(len(prezzo)), superficie, eta])

theta = np.linalg.solve(X.T @ X, X.T @ prezzo)
print(theta.round(3))                           # [32.595  2.069 -0.392]
print(round(np.array([1, 85, 20]) @ theta, 1))  # 200.6

Nota che il codice non calcola l'inversa: np.linalg.solve risolve direttamente il sistema X⊤Xθ=X⊤YX^\top X \theta = X^\top Y. Il risultato è lo stesso, ma è più veloce e più preciso numericamente. La formula con (X⊤X)−1(X^\top X)^{-1} serve a capire il ragionamento.

Quando XᵀX non è invertibile

La formula funziona solo se X⊤XX^\top X si può invertire. Ci sono due casi tipici in cui non succede.

Regressori ridondanti

Supponiamo di aggiungere al dataset anche la superficie in piedi quadrati: è la stessa informazione della superficie in metri quadrati. La quarta colonna di XX è un multiplo esatto della seconda, quindi le colonne sono linearmente dipendenti. Le soluzioni sono infinite: un m² in più può essere "pagato" dal parametro dei metri, da quello dei piedi o da un mix dei due, e la previsione non cambia.

X⊤XX^\top X è singolare, o meglio, a causa degli arrotondamenti, quasi singolare. Ed è qui che sta il pericolo: np.linalg.inv spesso non dà errore, ma restituisce numeri insensati. Sul mio computer:

Metodo θ0\theta_0 (k€) θ1\theta_1 (k€/m²) θ2\theta_2 (k€/anno) θ3\theta_3 (k€/ft²) MSE (k€²)
inv(XᵀX) 272,8 −1,184 −0,392 0,130 11.301
pinv(X) 32,6 0,0177 −0,392 0,191 4,28

Con l'inversa "forzata" la funzione di costo esplode da 4,3 a oltre 11.000 k€². I valori esatti dipendono dalla libreria e dal processore, il che è un altro sintomo del problema.

Esiste anche una versione più subdola del problema: regressori non identici ma molto correlati, come la superficie e il numero di locali. X⊤XX^\top X è invertibile, ma i parametri diventano instabili e difficili da interpretare: il modello non sa a chi dei due attribuire l'effetto.

Troppi pochi dati

Se le osservazioni sono meno dei parametri, o tante quante (N≤dN \le d), i dati non bastano a determinare il modello. Con soli 3 appartamenti e 3 parametri il piano passa esattamente per tutti e tre i punti, con errore zero:

Dati usati θ0\theta_0 (k€) θ1\theta_1 (k€/m²) θ2\theta_2 (k€/anno) MSE sui dati usati (k€²)
3 appartamenti 14,2 2,462 −0,385 0
tutti e 10 32,6 2,069 −0,392 4,28

Errore zero non vuol dire modello perfetto: vuol dire che il modello ha memorizzato i dati invece di imparare la relazione. Con 3 appartamenti il valore di un m² sale a 2.460 €, un numero che non regge su nessun altro immobile. È il primo assaggio dell'overfitting.

Il limite delle equazioni normali

X⊤XX^\top X è una matrice d×dd \times d, e risolvere il sistema costa all'incirca d3d^3 operazioni. Con 3 parametri è istantaneo, con qualche migliaio ancora fattibile. Con milioni di feature, come nei modelli per testo o immagini, diventa impraticabile, anche solo per la memoria necessaria a contenere la matrice.

In quei casi si rinuncia alla soluzione esatta e si usa un metodo iterativo: la discesa del gradiente, già vista nel primo articolo. Con più variabili però nasconde una trappola, e il prossimo articolo è dedicato a quella: discesa del gradiente e normalizzazione dei dati.

  • Con più regressori il modello si scrive y(i)=φ(i)⊤θ+ε(i)y(i) = \varphi(i)^\top \theta + \varepsilon(i), con un regressore finto φ0=1\varphi_0 = 1 per l'intercetta.
  • Impilando le osservazioni si ottiene Y=Xθ+EY = X\theta + E: ogni riga di XX è un'osservazione, ogni colonna un regressore.
  • La funzione di costo J(θ)=1N∥Y−Xθ∥2J(\theta) = \frac{1}{N} \lVert Y - X\theta \rVert^2 è convessa: ha un unico minimo.
  • Annullando il gradiente si ottengono le equazioni normali X⊤Xθ=X⊤YX^\top X \theta = X^\top Y, da cui θ^=(X⊤X)−1X⊤Y\hat\theta = (X^\top X)^{-1} X^\top Y.
  • X⊤XX^\top X non è invertibile con regressori ridondanti (si toglie la colonna, o si usa la pseudo-inversa) o con troppi pochi dati (N≤dN \le d): il modello memorizza invece di imparare.
  • Con moltissimi parametri le equazioni normali diventano troppo costose e si passa alla discesa del gradiente.