0Pricing
Pandas & NumPy Academy · Lezione

Risoluzione di sistemi lineari

Risolva Ax=b con np.linalg.solve e confronti questo metodo con il semplice approccio basato su inversa e moltiplicazione in termini di stabilità numerica.

Risoluzione di sistemi lineari è una lezione Pandas & NumPy Academy gratuita su CoddyKit. Questa è la lezione 3 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Pandas & NumPy Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Pandas & NumPy Academy include 4 lezioni in totale.

Che cos'è un sistema lineare?

Un sistema di equazioni lineari può essere scritto in forma matriciale come Ax = b, dove A è la matrice dei coefficienti, x è il vettore delle incognite e b è il vettore dei termini noti. Ad esempio, due equazioni con due incognite possono essere espresse come un'equazione matriciale 2×2. Risolvere il sistema significa trovare x tale che A moltiplicata per x sia uguale a b. np.linalg.solve(A, b) di NumPy gestisce questa operazione in modo efficiente e accurato.

import numpy as np

# System: 2x + y = 5
#         x + 3y = 10
A = np.array([[2.0, 1.0],
              [1.0, 3.0]])
b = np.array([5.0, 10.0])

x = np.linalg.solve(A, b)
print('Solution x:', x)
print('Verify A @ x == b:', np.allclose(A @ x, b))

Perché non usare l'inversa?

Dal punto di vista matematico, la soluzione di Ax = b è x = A⁻¹b. Tuttavia, calcolare np.linalg.inv(A) @ b è più lento e meno preciso che chiamare direttamente np.linalg.solve(A, b). solve() usa internamente la decomposizione LU, che richiede meno operazioni e accumula meno errori di arrotondamento. Regola generale: se sta risolvendo x in Ax=b, usi sempre solve, mai inv.

import numpy as np

A = np.random.rand(100, 100)
b = np.random.rand(100)

# Avoid this pattern
x_inv = np.linalg.inv(A) @ b

# Prefer this
x_solve = np.linalg.solve(A, b)

print('Max difference:', np.max(np.abs(x_inv - x_solve)))
# solve is faster AND more accurate

Requisiti di solve()

np.linalg.solve(A, b) richiede che A sia quadrata e non singolare. Se A è singolare (il determinante è zero), la funzione solleva np.linalg.LinAlgError: Singular matrix. A è singolare quando le righe sono linearmente dipendenti, ad esempio quando un'equazione è semplicemente un multiplo di un'altra. Verifichi sempre che il sistema sia ben posto prima di chiamare solve. Se A non è quadrata, usi invece np.linalg.lstsq().

import numpy as np

# Well-posed system
A = np.array([[1.0, 2.0], [3.0, 4.0]])
b = np.array([5.0, 6.0])
print('Solution:', np.linalg.solve(A, b))

# Singular system (row 2 = 3 * row 1)
A_singular = np.array([[1.0, 2.0], [3.0, 6.0]])
try:
    np.linalg.solve(A_singular, b)
except np.linalg.LinAlgError as e:
    print('Error:', e)

La decomposizione LU dietro le quinte

np.linalg.solve applica internamente la decomposizione LU: fattorizza A in una matrice triangolare inferiore L e una matrice triangolare superiore U, tali che A = LU. La risoluzione diventa quindi la risoluzione di due sistemi triangolari più semplici (sostituzione in avanti e all'indietro), molto più efficienti dell'eliminazione di Gauss ripetuta da zero. È lo stesso algoritmo usato da MATLAB, Fortran LAPACK e praticamente tutte le librerie di calcolo scientifico.

import numpy as np
from scipy import linalg

A = np.array([[2.0, 1.0, -1.0],
              [-3.0, -1.0, 2.0],
              [-2.0, 1.0, 2.0]])
b = np.array([8.0, -11.0, -3.0])

# NumPy solve (uses LAPACK dgesv under the hood)
x = np.linalg.solve(A, b)
print('Solution:', x)
print('Check:', np.allclose(A @ x, b))

Risolvere più termini noti

np.linalg.solve(A, B) può gestire una matrice B con più colonne, risolvendo simultaneamente il sistema per ogni colonna. Se B ha forma (n, k), il risultato X ha forma (n, k), dove ogni colonna di X è la soluzione corrispondente alla colonna di B. Questo è utile nelle simulazioni fisiche e nel machine learning, quando è necessario risolvere la stessa matrice dei coefficienti con molti termini noti diversi.

import numpy as np

A = np.array([[3.0, 1.0],
              [1.0, 2.0]])

# Three right-hand side vectors at once
B = np.array([[9.0, 3.0, 6.0],
              [8.0, 4.0, 2.0]])

X = np.linalg.solve(A, B)
print('Solutions X shape:', X.shape)  # (2, 3)
print('Verify A @ X == B:', np.allclose(A @ X, B))

Minimi quadrati con np.linalg.lstsq()

Quando il sistema è sovradeterminato (con più equazioni che incognite), non esiste una soluzione esatta. np.linalg.lstsq(A, b) trova il valore di x che minimizza la somma dei quadrati dei residui ||Ax - b||²: è esattamente ciò che calcola la regressione lineare. Restituisce la soluzione x, i residui, il rango e i valori singolari. L'argomento rcond=None evita un avviso di deprecazione e imposta la soglia per trattare i valori singolari come zero.

import numpy as np

# Over-determined: 4 equations, 2 unknowns
A = np.array([[1.0, 1.0],
              [1.0, 2.0],
              [1.0, 3.0],
              [1.0, 4.0]])
b = np.array([2.0, 2.5, 3.5, 4.5])

x, residuals, rank, sv = np.linalg.lstsq(A, b, rcond=None)
print('Least-squares solution:', x)
print('Residuals:', residuals)
print('Rank:', rank)

Applicare solve() alla regressione lineare

Le equazioni normali dei minimi quadrati ordinari sono A.T @ A @ x = A.T @ b, un sistema quadrato risolvibile con np.linalg.solve. Il risultato coincide con quello di lstsq quando A.T @ A è ben condizionata. Nella pratica, lstsq è preferibile perché usa la SVD ed è stabile anche quando le colonne sono quasi collineari; tuttavia, le equazioni normali aiutano a comprendere la matematica alla base della regressione.

import numpy as np

np.random.seed(0)
X = np.column_stack([np.ones(50), np.random.rand(50) * 10])
y = 3.0 + 2.0 * X[:, 1] + np.random.randn(50)

# Solve normal equations
coeffs = np.linalg.solve(X.T @ X, X.T @ y)
print('Intercept:', round(coeffs[0], 3))
print('Slope:', round(coeffs[1], 3))

Controllare il numero di condizionamento

Prima di risolvere il sistema, è buona pratica controllare il numero di condizionamento con np.linalg.cond(A). Un numero di condizionamento vicino a 1 indica che il sistema è ben condizionato e che la soluzione è affidabile. Un numero di condizionamento molto grande (ad esempio, 1e12) indica che la matrice è quasi singolare: piccole variazioni in b producono grandi variazioni in x e la soluzione potrebbe essere numericamente inaffidabile. In tal caso, valuti la regolarizzazione (regressione ridge) o l'uso di un risolutore più robusto.

import numpy as np

# Well-conditioned
A1 = np.array([[2.0, 1.0], [1.0, 3.0]])
print('Condition number (well):', np.linalg.cond(A1))

# Ill-conditioned (nearly linearly dependent rows)
A2 = np.array([[1.0, 1.0], [1.0, 1.0001]])
print('Condition number (ill):', np.linalg.cond(A2))

Sistemi sparsi: quando non usare linalg

Per sistemi molto grandi in cui A contiene prevalentemente valori nulli (una matrice sparsa), memorizzare l'intera matrice spreca memoria e usare np.linalg.solve denso è lento. SciPy fornisce scipy.sparse e scipy.sparse.linalg.spsolve, che sfruttano la sparsità per gestire sistemi enormi, come quelli dei modelli a elementi finiti o dei problemi di rete. Capire quando una matrice è sparsa è un aspetto importante delle prestazioni nel calcolo scientifico.

import numpy as np

# Dense solve is fine for small-to-medium systems
A = np.random.rand(200, 200)
b = np.random.rand(200)
x = np.linalg.solve(A, b)
print('Dense solve OK, solution shape:', x.shape)

# For large sparse systems, use scipy.sparse.linalg.spsolve instead
# from scipy.sparse.linalg import spsolve
# x = spsolve(A_sparse, b)

Interpretare il vettore soluzione

Una volta ottenuto il vettore soluzione x da np.linalg.solve(A, b), lo verifichi sempre calcolando A @ x e confrontandolo con b tramite np.allclose(A @ x, b). Nell'aritmetica in virgola mobile, raramente si ottiene un'uguaglianza esatta: allclose verifica che i valori rientrino in una piccola tolleranza. Il residuo ||Ax - b|| dovrebbe essere prossimo all'epsilon di macchina moltiplicato per la scala del problema, se il sistema è ben condizionato.

import numpy as np

A = np.array([[4.0, 3.0, 2.0],
              [1.0, 5.0, 3.0],
              [2.0, 1.0, 6.0]])
b = np.array([10.0, 20.0, 15.0])

x = np.linalg.solve(A, b)
print('Solution:', np.round(x, 4))

# Residual check
residual = np.linalg.norm(A @ x - b)
print('Residual ||Ax - b||:', residual)
print('Valid:', np.allclose(A @ x, b))

Risoluzione nei flussi di lavoro di machine learning

I risolutori lineari sono presenti in tutto il machine learning: la regressione lineare risolve le equazioni normali, i processi gaussiani risolvono sistemi con matrici kernel e i filtri di Kalman risolvono le equazioni di aggiornamento dello stato. Comprendendo np.linalg.solve e lstsq, può implementare questi algoritmi da zero e analizzarli quando i risultati non sono quelli attesi. Il modulo linalg di NumPy offre gli stessi strumenti numerici utilizzati nelle librerie scientifiche di produzione.

import numpy as np

# Ridge regression: (X.T @ X + lambda * I) @ w = X.T @ y
np.random.seed(42)
X = np.random.rand(100, 5)
y = np.random.rand(100)
lambda_reg = 0.1
n_features = X.shape[1]

A = X.T @ X + lambda_reg * np.eye(n_features)
bvec = X.T @ y
w = np.linalg.solve(A, bvec)
print('Ridge regression weights:', np.round(w, 4))

Verifica rapida

Verifichi la sua comprensione dei concetti di analisi dei dati trattati in questa lezione.

Riepilogo della lezione

In questa lezione ha imparato che: np.linalg.solve(A, b) risolve in modo efficiente i sistemi lineari quadrati utilizzando la decomposizione LU, np.linalg.lstsq() trova la soluzione ai minimi quadrati per i sistemi sovradeterminati e il numero di condizionamento misura la stabilità numerica: valori elevati segnalano matrici quasi singolari. Ora esamineremo gli autovalori e la SVD, alla base della PCA e di molti algoritmi di ML.

Domande Frequenti

La lezione «Risoluzione di sistemi lineari» è gratuita?

Sì — il testo completo di «Risoluzione di sistemi lineari» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Pandas & NumPy Academy, passa a CoddyKit PRO. Il corso Pandas & NumPy Academy include 4 lezioni in totale.

Cosa imparerò in «Risoluzione di sistemi lineari»?

Risolva Ax=b con np.linalg.solve e confronti questo metodo con il semplice approccio basato su inversa e moltiplicazione in termini di stabilità numerica. Eserciti Pandas & NumPy Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Pandas & NumPy Academy?

Non è richiesta alcuna esperienza precedente. Pandas & NumPy Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 4.

Quanto tempo richiede la lezione «Risoluzione di sistemi lineari»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Pandas & NumPy Academy?

Sì. Ogni lezione Pandas & NumPy Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Moltiplicazione di matrici con np.matmul e @
  2. Determinanti, inverse e trasposte
  3. Risoluzione di sistemi lineari
  4. Panoramica su autovalori e SVD
← Torna a Pandas & NumPy Academy