Perché l’Algebra Lineare Decide il Successo dei Modelli
Quando si parla di machine learning si citano spesso librerie, framework e architetture.
Raramente si dice la verità più scomoda:
ogni modello supervisionato vive dentro un sistema lineare.
Regressione lineare, regressione logistica (localmente), PCA, SVD, least squares, ridge, lasso:
tutto nasce da una matrice e dal suo comportamento strutturale.
Uno degli strumenti più sottovalutati — ma più potenti — è la forma a gradini (row echelon form).
Non è un esercizio da maturità.
È una diagnostica matematica del dataset.
In questo articolo rivediamo 6 esercizi classici, ma reinterpretati come farebbe un data scientist, con soluzioni commentate e insight operativi.
Esercizio 1 — Riconoscere la forma a gradini = Riconoscere la collinearità
Problema originale: stabilire se una matrice è a gradini.
Versione data science: stabilire se le feature sono collineari.
👉 In ML, una matrice NON a gradini spesso indica collinearità o feature duplicate.
Se una riga non può “scalare” verso destra, significa che una feature è combinazione lineare delle precedenti.
Interpretazione ML:
- Se la matrice è a gradini → le feature sono indipendenti.
- Se non lo è → regressione lineare instabile, pesi non identificabili, warning di scikit‑learn.
💡 Insight: La forma a gradini è un test manuale di multicollinearità.
Collegamento con le Feature in Machine Learning
In ambito ML, l’algebra lineare non è solo calcolo, ma fornisce strumenti diagnostici fondamentali per la qualità dei dati.
1. La Matrice dei Dati [math]X[/math]
Consideriamo una matrice [math]X[/math] di dimensioni [math]m \times n[/math]:
- Righe ([math]m[/math]): Rappresentano gli esempi (samples, osservazioni).
- Colonne ([math]n[/math]): Rappresentano le feature (variabili) [math]X_1, X_2, \dots, X_n[/math].
In genere, per avere un modello robusto, desideriamo che [math]m \ge n[/math] (più dati che variabili) e che le colonne siano linearmente indipendenti.
2. Il Problema della Multicollinearità
La collinearità (o multicollinearità) si verifica quando una feature (una colonna) è combinazione lineare delle altre. In termini pratici, significa che quella feature è ridondante: non porta nuova informazione, ma ripete informazioni già presenti.
Conseguenze matematiche:
- Se c’è dipendenza lineare, il rango di [math]X[/math] non è massimo: [math]\text{rango}(X) < n[/math].
- Nella regressione lineare (metodo dei minimi quadrati), cerchiamo di risolvere [math]Xw = y[/math]. La soluzione analitica richiede l’inversione di [math]X^T X[/math]:
[math]\displaystyle w = (X^T X)^{-1} X^T y[/math] - Se [math]\text{rango}(X) < n[/math], la matrice [math]X^T X[/math] diventa singolare (determinante nullo) e non può essere invertita. Questo rende la regressione instabile o impossibile.
3. Diagnosi tramite Matrici a Gradini
Come facciamo a scoprire se soffriamo di multicollinearità senza calcolare determinanti complessi? Usiamo l’eliminazione di Gauss per portare la matrice [math]X[/math] in forma a gradini.
Per il teorema fondamentale dell’algebra lineare, il rango per righe è uguale al rango per colonne. Quindi, contando i pivot otteniamo la risposta.
| Analisi dei Pivot | Interpretazione ML | Conseguenza |
|---|---|---|
| Numero Pivot = [math]n[/math] | Colonne indipendenti | ✔ Nessuna multicollinearità |
| Numero Pivot < [math]n[/math] | Colonne dipendenti | ⚠ Multicollinearità (Feature ridondanti) |
Se durante l’eliminazione di Gauss su [math]X[/math] trovi una colonna che non genera un nuovo pivot (ovvero, la variabile corrispondente è libera), quella specifica feature è linearmente dipendente dalle precedenti (nell’ordine in cui sono state processate).
Esempio: Diagnosi di Collinearità nel Machine Learning
Immaginiamo di avere un dataset con 3 feature (variabili) e 3 osservazioni. Vogliamo verificare se queste variabili sono indipendenti o se creano instabilità nel modello.
1. Definizione della Matrice Dati [math]X[/math]
Siano le nostre feature:
- [math]X_1 = [1, 2, 3]^T[/math]
- [math]X_2 = [2, 4, 6]^T[/math] (Notiamo subito che [math]X_2 = 2X_1[/math])
- [math]X_3 = [1, 1, 1]^T[/math]
La matrice dei dati [math]X[/math] ([math]3 \times 3[/math]) è:
[math]\displaystyle
X = \begin{pmatrix}
1 & 2 & 1 \\
2 & 4 & 1 \\
3 & 6 & 1
\end{pmatrix}
[/math]
2. Riduzione a Gradini (Algoritmo di Gauss)
Applichiamo le operazioni elementari per annullare gli elementi sotto il primo pivot:
- Passo 1: [math]R_2 \leftarrow R_2 – 2R_1[/math] → [math](2, 4, 1) – (2, 4, 2) = (0, 0, -1)[/math]
- Passo 2: [math]R_3 \leftarrow R_3 – 3R_1[/math] → [math](3, 6, 1) – (3, 6, 3) = (0, 0, -2)[/math]
La matrice parziale è ora:
[math]\displaystyle \begin{pmatrix} 1 & 2 & 1 \\ 0 & 0 & -1 \\ 0 & 0 & -2 \end{pmatrix}[/math]
- Passo 3: [math]R_3 \leftarrow R_3 – 2R_2[/math] → [math](0, 0, -2) – (0, 0, -2) = (0, 0, 0)[/math]
Matrice a gradini finale:
[math]\displaystyle
\begin{pmatrix}
\mathbf{1} & 2 & 1 \\
0 & 0 & \mathbf{-1} \\
0 & 0 & 0
\end{pmatrix}
[/math]
3. Interpretazione Diagnostica per il Machine Learning
Analizziamo il risultato ottenuto:
- Numero di Pivot: 2 (nelle colonne 1 e 3).
- Numero di Feature: 3.
- Risultato: Poiché il Rango (2) < Numero Feature (3), esiste una collinearità perfetta.
In questo scenario, il modello di regressione fallirà o sarà instabile perché:
- L’inversa di [math]X^T X[/math] non esiste (determinante nullo).
- I coefficienti [math]w[/math] non sono unici (esistono infinite combinazioni di pesi).
- Librerie come Scikit-Learn potrebbero dare warning di ill-conditioned matrix.
4. Conclusione Finale
Il “test della forma a gradini” applicato alla matrice dei dati rivela la salute del dataset:
- Forma a gradini con [math]n[/math] pivot: Le feature sono indipendenti. Il modello sarà stabile.
- Forma a gradini con [math] < n[/math] pivot: Almeno una feature è ridondante. Azione richiesta: Rimuovere la feature che non ha generato il pivot (nel nostro caso, la seconda colonna).
La forma a gradini è il “test del DNA” delle tue feature: rivela legami di parentela nascosti che potrebbero confondere il tuo modello.
Ecco uno snippet Python che implementa il test della multicollinearità tramite la forma a gradini:
import numpy as np
from scipy import linalg
import warnings
def is_row_echelon(matrix, tol=1e-10):
"""
Verifica se una matrice è in forma a gradini (row echelon form).
Args:
matrix: Matrice numpy (m x n)
tol: Tolleranza per considerare un elemento zero
Returns:
bool: True se la matrice è in forma a gradini
"""
m, n = matrix.shape
# Troviamo i pivot di ogni riga (primo elemento non zero)
pivot_positions = []
for i in range(m):
pivot_col = None
for j in range(n):
if abs(matrix[i, j]) > tol:
pivot_col = j
break
pivot_positions.append(pivot_col)
# Controllo delle condizioni della forma a gradini
last_pivot = -1
for i, pivot in enumerate(pivot_positions):
if pivot is None: # riga tutta zero
# Verifica che tutte le righe sotto siano anche zero
for k in range(i+1, m):
if pivot_positions[k] is not None:
return False
continue
# Condizione: ogni pivot deve essere a destra del precedente
if pivot <= last_pivot:
return False
last_pivot = pivot
def check_multicollinearity(X, tol=1e-10, verbose=True):
"""
Controlla la multicollinearità nelle feature usando la forma a gradini.
Args:
X: Matrice dei dati (esempi x feature)
tol: Tolleranza numerica
verbose: Se True, stampa informazioni dettagliate
Returns:
dict: Risultati del test
"""
# Trasponiamo per avere le feature come righe
X_T = X.T
# Calcoliamo la forma a gradini
m, n = X_T.shape
# Copia per non modificare l'originale
A = X_T.copy().astype(float)
# Riduzione a gradini (Gauss semplice)
rows, cols = A.shape
pivot_cols = []
current_row = 0
for col in range(cols):
if current_row >= rows:
break
# Trova il pivot in questa colonna
pivot_row = None
for r in range(current_row, rows):
if abs(A[r, col]) > tol:
pivot_row = r
break
if pivot_row is None:
continue # Nessun pivot in questa colonna
# Scambia le righe
if pivot_row != current_row:
A[[current_row, pivot_row]] = A[[pivot_row, current_row]]
# Normalizza la riga del pivot (opzionale, per chiarezza)
pivot_val = A[current_row, col]
if abs(pivot_val) > tol:
A[current_row] = A[current_row] / pivot_val
# Elimina sotto il pivot
for r in range(current_row + 1, rows):
factor = A[r, col]
if abs(factor) > tol:
A[r] = A[r] - factor * A[current_row]
pivot_cols.append((current_row, col))
current_row += 1
# Numero di pivot (rango della trasposta)
num_pivots = len(pivot_cols)
num_features = X.shape[1]
# Risultati
is_echelon = is_row_echelon(A, tol)
# Calcolo del numero di condizione per ulteriore validazione
if X.shape[0] >= X.shape[1]:
try:
cond_number = np.linalg.cond(X)
high_cond = cond_number > 1e12 # Soglia per multicollinearità grave
except:
cond_number = np.inf
high_cond = True
else:
cond_number = None
high_cond = False
# Interpretazione
independent = (num_pivots == num_features)
collinear = not independent
if verbose:
print("="*60)
print("TEST DI MULTICOLLINEARITÀ TRAMITE FORMA A GRADINI")
print("="*60)
print(f"Matrice dati: {X.shape[0]} esempi, {X.shape[1]} feature")
print(f"Matrice trasposta (feature come righe): {X_T.shape}")
print(f"\nNumero di pivot trovati: {num_pivots}")
print(f"Numero di feature: {num_features}")
print(f"Matrice risultante è a gradini: {is_echelon}")
if cond_number is not None:
print(f"Numero di condizione di X: {cond_number:.2e}")
print(f"\n{'='*60}")
print("DIAGNOSI:")
if independent:
print("✅ Feature INDIPENDENTI (nessuna multicollinearità)")
print(" Regressione lineare stabile, pesi identificabili")
else:
print("❌ MULTICOLLINEARITÀ RILEVATA")
print(f" Rango: {num_pivots} < {num_features}")
print(" Almeno una feature è combinazione lineare delle altre")
print(" Regressione lineare instabile, possibili warning")
# Suggerimenti
print("\n💡 SUGGERIMENTI:")
print(" 1. Rimuovere feature ridondanti")
print(" 2. Usare Ridge Regression (L2 regularization)")
print(" 3. Applicare PCA per ridurre la dimensionalità")
print(" 4. Verificare correlazioni tra feature")
if high_cond and cond_number is not None:
print(f"\n⚠️ Attenzione: numero di condizione molto alto ({cond_number:.2e})")
print(" Indica multicollinearità grave anche se il rango è massimo")
return {
'independent': independent,
'collinear': collinear,
'num_pivots': num_pivots,
'num_features': num_features,
'rank': num_pivots,
'condition_number': cond_number,
'is_row_echelon': is_echelon,
'echelon_matrix': A,
'pivot_positions': pivot_cols
}
def create_example_data(example_type='independent'):
"""Crea dati di esempio per testare la multicollinearità."""
if example_type == 'independent':
# Feature indipendenti
X = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 10],
[2, 3, 4]
])
elif example_type == 'collinear':
# Feature 2 = 2 * Feature 1
X = np.array([
[1, 2, 5],
[2, 4, 6],
[3, 6, 7],
[4, 8, 8]
])
elif example_type == 'perfect_collinear':
# Feature 3 = Feature 1 + Feature 2
X = np.array([
[1, 2, 3],
[2, 3, 5],
[3, 4, 7],
[4, 5, 9]
])
elif example_type == 'almost_collinear':
# Quasi collinearità (numericamente problematico)
X = np.array([
[1, 2.001, 3],
[2, 4, 6],
[3, 6.002, 9],
[4, 8, 12]
])
return X
def test_examples():
"""Testa diversi esempi di multicollinearità."""
examples = ['independent', 'collinear', 'perfect_collinear', 'almost_collinear']
for ex_type in examples:
print(f"\n{'='*60}")
print(f"TEST: {ex_type.upper()}")
print(f"{'='*60}")
X = create_example_data(ex_type)
print(f"\nMatrice X:\n{X}")
result = check_multicollinearity(X, verbose=True)
# Mostra la matrice a gradini risultante
print(f"\nMatrice a gradini (feature come righe):")
print(result['echelon_matrix'].round(4))
# Mostra posizioni dei pivot
if result['pivot_positions']:
print(f"Posizioni pivot (riga, colonna): {result['pivot_positions']}")
# -----------------------------------------------------------------
# ESEMPIO DI UTILIZZO
# -----------------------------------------------------------------
if __name__ == "__main__":
# Test con tutti gli esempi
test_examples()
print("\n" + "="*60)
print("USO PRATICO CON NUOVI DATI")
print("="*60)
# Crea i tuoi dati
print("\n1. Inserisci manualmente i dati:")
X_custom = np.array([
[1, 2, 3],
[4, 8, 6], # Nota: colonna 2 = 2 * colonna 1
[2, 4, 5],
[3, 6, 7]
])
print(f"Matrice:\n{X_custom}")
result = check_multicollinearity(X_custom, verbose=True)
# Verifica con scikit-learn per confronto
try:
from sklearn.linear_model import LinearRegression
print(f"\n{'='*60}")
print("VERIFICA CON SCKIT-LEARN")
print("="*60)
# Crea target fittizio
y = np.array([1, 2, 3, 4])
model = LinearRegression()
try:
model.fit(X_custom, y)
print("✅ Scikit-learn ha completato il fit senza errori")
print(f" Coefficienti: {model.coef_}")
except Exception as e:
print(f"❌ Scikit-learn ha sollevato un'eccezione: {e}")
# Test con Ridge per confronto
from sklearn.linear_model import Ridge
ridge_model = Ridge(alpha=1.0)
ridge_model.fit(X_custom, y)
print(f" Ridge Regression coefficienti: {ridge_model.coef_}")
except ImportError:
print("\nNota: scikit-learn non installato. Per installare: pip install scikit-learn")
============================================================
TEST: INDEPENDENT
============================================================
Matrice X:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 10]
[ 2 3 4]]
============================================================
TEST DI MULTICOLLINEARITÀ TRAMITE FORMA A GRADINI
============================================================
Matrice dati: 4 esempi, 3 feature
Matrice trasposta (feature come righe): (3, 4)
Numero di pivot trovati: 3
Numero di feature: 3
Matrice risultante è a gradini: True
Numero di condizione di X: 9.16e+01
============================================================
DIAGNOSI:
✅ Feature INDIPENDENTI (nessuna multicollinearità)
Regressione lineare stabile, pesi identificabili
Matrice a gradini (feature come righe):
[[ 1. 4. 7. 2. ]
[-0. 1. 2. 0.3333]
[ 0. 0. 1. 0. ]]
Posizioni pivot (riga, colonna): [(0, 0), (1, 1), (2, 2)]
============================================================
TEST: COLLINEAR
============================================================
Matrice X:
[[1 2 5]
[2 4 6]
[3 6 7]
[4 8 8]]
============================================================
TEST DI MULTICOLLINEARITÀ TRAMITE FORMA A GRADINI
============================================================
Matrice dati: 4 esempi, 3 feature
Matrice trasposta (feature come righe): (3, 4)
Numero di pivot trovati: 2
Numero di feature: 3
Matrice risultante è a gradini: True
Numero di condizione di X: 2.77e+16
============================================================
DIAGNOSI:
❌ MULTICOLLINEARITÀ RILEVATA
Rango: 2 < 3
Almeno una feature è combinazione lineare delle altre
Regressione lineare instabile, possibili warning
💡 SUGGERIMENTI:
1. Rimuovere feature ridondanti
2. Usare Ridge Regression (L2 regularization)
3. Applicare PCA per ridurre la dimensionalità
4. Verificare correlazioni tra feature
⚠️ Attenzione: numero di condizione molto alto (2.77e+16)
Indica multicollinearità grave anche se il rango è massimo
Matrice a gradini (feature come righe):
[[ 1. 2. 3. 4.]
[-0. 1. 2. 3.]
[ 0. 0. 0. 0.]]
Posizioni pivot (riga, colonna): [(0, 0), (1, 1)]
============================================================
TEST: PERFECT_COLLINEAR
============================================================
Matrice X:
[[1 2 3]
[2 3 5]
[3 4 7]
[4 5 9]]
============================================================
TEST DI MULTICOLLINEARITÀ TRAMITE FORMA A GRADINI
============================================================
Matrice dati: 4 esempi, 3 feature
Matrice trasposta (feature come righe): (3, 4)
Numero di pivot trovati: 2
Numero di feature: 3
Matrice risultante è a gradini: True
Numero di condizione di X: 3.95e+16
============================================================
DIAGNOSI:
❌ MULTICOLLINEARITÀ RILEVATA
Rango: 2 < 3
Almeno una feature è combinazione lineare delle altre
Regressione lineare instabile, possibili warning
💡 SUGGERIMENTI:
1. Rimuovere feature ridondanti
2. Usare Ridge Regression (L2 regularization)
3. Applicare PCA per ridurre la dimensionalità
4. Verificare correlazioni tra feature
⚠️ Attenzione: numero di condizione molto alto (3.95e+16)
Indica multicollinearità grave anche se il rango è massimo
Matrice a gradini (feature come righe):
[[ 1. 2. 3. 4.]
[-0. 1. 2. 3.]
[ 0. 0. 0. 0.]]
Posizioni pivot (riga, colonna): [(0, 0), (1, 1)]
============================================================
TEST: ALMOST_COLLINEAR
============================================================
Matrice X:
[[ 1. 2.001 3. ]
[ 2. 4. 6. ]
[ 3. 6.002 9. ]
[ 4. 8. 12. ]]
============================================================
TEST DI MULTICOLLINEARITÀ TRAMITE FORMA A GRADINI
============================================================
Matrice dati: 4 esempi, 3 feature
Matrice trasposta (feature come righe): (3, 4)
Numero di pivot trovati: 2
Numero di feature: 3
Matrice risultante è a gradini: True
Numero di condizione di X: 6.34e+16
============================================================
DIAGNOSI:
❌ MULTICOLLINEARITÀ RILEVATA
Rango: 2 < 3
Almeno una feature è combinazione lineare delle altre
Regressione lineare instabile, possibili warning
💡 SUGGERIMENTI:
1. Rimuovere feature ridondanti
2. Usare Ridge Regression (L2 regularization)
3. Applicare PCA per ridurre la dimensionalità
4. Verificare correlazioni tra feature
⚠️ Attenzione: numero di condizione molto alto (6.34e+16)
Indica multicollinearità grave anche se il rango è massimo
Matrice a gradini (feature come righe):
[[ 1. 2. 3. 4. ]
[-0. 1. 0.5 2. ]
[ 0. 0. 0. 0. ]]
Posizioni pivot (riga, colonna): [(0, 0), (1, 1)]
============================================================
USO PRATICO CON NUOVI DATI
============================================================
1. Inserisci manualmente i dati:
Matrice:
[[1 2 3]
[4 8 6]
[2 4 5]
[3 6 7]]
============================================================
TEST DI MULTICOLLINEARITÀ TRAMITE FORMA A GRADINI
============================================================
Matrice dati: 4 esempi, 3 feature
Matrice trasposta (feature come righe): (3, 4)
Numero di pivot trovati: 2
Numero di feature: 3
Matrice risultante è a gradini: True
Numero di condizione di X: 2.22e+16
============================================================
DIAGNOSI:
❌ MULTICOLLINEARITÀ RILEVATA
Rango: 2 < 3
Almeno una feature è combinazione lineare delle altre
Regressione lineare instabile, possibili warning
💡 SUGGERIMENTI:
1. Rimuovere feature ridondanti
2. Usare Ridge Regression (L2 regularization)
3. Applicare PCA per ridurre la dimensionalità
4. Verificare correlazioni tra feature
⚠️ Attenzione: numero di condizione molto alto (2.22e+16)
Indica multicollinearità grave anche se il rango è massimo
============================================================
VERIFICA CON SCKIT-LEARN
============================================================
✅ Scikit-learn ha completato il fit senza errori
Coefficienti: [-0.18888889 -0.37777778 1.22222222]
Per utilizzarlo con i tuoi dati:
import numpy as np # Carica i tuoi dati # X = np.array([...]) # Matrice (esempi × feature) # Esegui il test result = check_multicollinearity(X, verbose=True)
L’output mostrerà chiaramente se le feature sono collineari e fornirà indicazioni su come procedere.
Quasi-Collinearità: Quando il “Quasi” è Peggio del “Certo”
In teoria, una matrice o ha rango pieno o non ce l’ha. Nella realtà del Data Science, le feature non sono quasi mai perfettamente collineari (es. [math]X_2 = 2 \cdot X_1[/math]), ma spesso sono quasi collineari (es. [math]X_2 = 2 \cdot X_1 + \epsilon[/math], dove [math]\epsilon[/math] è un rumore piccolissimo).
1. Il Limite della Forma a Gradini
L’algoritmo di Gauss usa una tolleranza (tol) per decidere se un pivot è zero.
- Se la collinearità è “quasi perfetta”, Gauss vedrà un numero molto piccolo ma diverso da zero e manterrà il pivot.
- Risultato: La RREF ti dirà che le feature sono indipendenti, ma il tuo modello di regressione si comporterà comunque in modo folle.
2. Che cos’è il Condition Number?
Il numero di condizione di una matrice [math]X[/math] si definisce come il rapporto tra il valore singolare più grande e quello più piccolo ottenuto tramite la SVD (Singular Value Decomposition):
[math]\displaystyle \kappa(X) = \frac{\sigma_{max}}{\sigma_{min}}[/math]
| Valore di [math]\kappa[/math] | Significato Strategico |
|---|---|
| [math]\kappa = 1[/math] | Feature perfettamente ortogonali (il sogno di ogni DS). |
| [math]10^3[/math] a [math]10^6[/math] | Inizia a esserci “attrito” numerico; instabilità moderata. |
| [math]> 10^{12}[/math] | Matrice ill-conditioned. Siamo in zona pericolo estremo. |
Perché il “Quasi” è peggio del “Certo”?
Se due feature sono perfettamente collineari, l’algebra lineare “rompe” il sistema e ti avverte chiaramente (rango ridotto).
Se sono quasi collineari:
- Il sistema calcola comunque una soluzione, ma i pesi [math]w[/math] diventano enormi e instabili.
- Piccole variazioni nel rumore di input causano oscillazioni gigantesche nell’output.
- L’interpretazione dei coefficienti perde senso: il modello non riesce più a distinguere il contributo di una feature dall’altra.
Diagnostica Avanzata: Algebra Lineare come Bussola per il ML
Oltre al calcolo del rango, la forma a gradini ci permette di fare il “tagliando” al nostro dataset.
Ecco come interpretare le anomalie matematiche in ottica Data Science.
Esercizio 2 — Righe Inconsistenti = Dati Contraddittori
Problema: Una matrice aumentata [math][A|b][/math] che, dopo l’eliminazione di Gauss, presenta una riga del tipo [math][0, 0, 0 | k][/math] con [math]k \neq 0[/math].
Versione Data Science: Identificare record che confondono il modello (Target diversi per input identici).
Interpretazione ML:
In un sistema lineare, una riga [math][0, 0, 0 | 5][/math] significa [math]0 = 5[/math]. Impossibile.
Nel Machine Learning, questo accade quando hai due righe nel dataset con feature identiche ma etichette (target) diverse.
Esempio: Due case con la stessa metratura, posizione e anno, ma prezzi drasticamente diversi senza una feature che lo spieghi.
Diagnosi: Il dataset è “rumoroso” o mancano feature deterministiche. Nessun modello potrà mai avere un errore zero qui.
Rappresentazione formale dell’inconsistenza:
[math]\displaystyle \begin{aligned}
\text{Se } \exists i \text{ tale che: } & \sum_{j=1}^{n} a_{ij}x_j = 0 \\
& \text{ma } b_i \neq 0 \\
\implies & \text{Sistema Impossibile}
\end{aligned}[/math]
Esercizio 3 — Variabili Libere = Sotto-determinazione e Overfitting
Problema: La forma a gradini ha meno pivot delle colonne ([math]r < n[/math]).
Versione Data Science: Troppe feature per pochi dati ([math]p > n[/math]).
Interpretazione ML:
Se hai colonne senza pivot, quelle sono “variabili libere”. In ML, questo significa che il modello ha infiniti modi (infinite combinazioni di pesi [math]w[/math]) per mappare [math]X[/math] su [math]y[/math].
Conseguenza: È il paradiso dell’overfitting. Il modello “memorizza” il rumore perché ha troppa libertà di movimento.
Soluzione Matematica: La forma a gradini ti dice esattamente quante e quali sono le feature che stanno creando questa libertà eccessiva.
Insight Critico:
Non è “flessibilità”, è anarchia. Quando vedi variabili libere nella tua matrice, la regolarizzazione (Lasso/Ridge) non è un optional, è l’unico modo per scegliere una soluzione tra le infinite possibili.
Relazione tra Pivot e Dimensionalità:
[math]\displaystyle \begin{aligned}
\text{Dimensione del Kernel (Null Space)} &= n – r \\
&{} \quad \text{(Numero di variabili libere)} \\
\text{Se } n – r > 0 \implies & \text{Infinità di soluzioni } \mathbf{w} \\
& \text{tali che } \mathbf{Xw} = \mathbf{y}
\end{aligned}[/math]
Esercizio 4 — Matrice Identità = Feature Ortogonali (Il Sogno)
Problema: La forma a gradini ridotta (RREF) è una matrice identità [math]I[/math].
Versione Data Science: Feature perfettamente indipendenti e “pulite”.
Interpretazione ML:
Se Gauss ti restituisce una matrice identità, congratulazioni: ogni feature porta un’informazione unica e ortogonale alle altre.
Vantaggio: I coefficienti della tua regressione saranno estremamente interpretabili. Il peso [math]w_1[/math] riflette esattamente l’impatto della feature [math]X_1[/math] senza “contaminazioni” dalle altre.
Realtà: Succede quasi solo dopo aver applicato una PCA (Principal Component Analysis) o un processo di sbiancamento (whitening).
Insight Critico:
L’identità è il punto d’arrivo della Feature Engineering. Se la tua matrice dati originale somiglia già a un’identità, probabilmente hai fatto un lavoro di raccolta dati eccezionale o stai guardando dati sintetici.
Proprietà della Matrice Identità nel Sistema Lineare:
[math]\displaystyle \begin{aligned}
\mathbf{I} \mathbf{w} &= \mathbf{b} \\
\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1
\end{bmatrix} \begin{bmatrix} w_1 \\ w_2 \\ w_3 \end{bmatrix} &= \begin{bmatrix} b_1 \\ b_2 \\ b_3 \end{bmatrix} \\
\implies w_i &= b_i
\end{aligned}[/math]
In questo scenario, la soluzione è unica e diretta: ogni coefficiente dipende esclusivamente dal proprio target corrispondente.
Esercizio 5 — Righe Nulle = Osservazioni Inutili
Problema: Durante l’eliminazione di Gauss, una o più righe si annullano completamente [math][0, 0, 0 | 0][/math].
Versione Data Science: Record duplicati o informazioni che non aggiungono varianza.
Interpretazione ML:
Una riga di zeri significa che quel record era già “scritto” nelle altre righe. In termini matematici, è una combinazione lineare di altri esempi presenti nel dataset.
- ML Case: Hai duplicati nel dataset o record che, pur non essendo identici, non aggiungono alcuna nuova informazione alla “superficie di decisione” del modello.
- Efficienza: Elaborare queste righe spreca solo RAM e tempo di calcolo, un fattore critico specialmente quando si lavora su dataset di dimensioni massicce.
Insight Critico:
In un’epoca di “Big Data”, spesso accumuliamo righe sperando che la quantità batta la qualità. Gauss ci ricorda che se una riga si annulla, stai solo facendo fare ginnastica inutile alla tua CPU. La ridondanza non è solo inutile, è costosa.
Rappresentazione del Rango e Ridondanza:
[math]\displaystyle \begin{aligned}
\text{Rango}(A) &= r < m \\
&{} \quad \text{(m = numero totale di righe)} \\
\text{Righe Nulle} &= m – r \\
&{} \quad \text{(Informazioni ridondanti eliminate)}
\end{aligned}[/math]
Quando il rango [math]r[/math] è inferiore al numero di righe [math]m[/math], la matrice non è a rango pieno, indicando che il dataset contiene “eco” di informazioni già presenti.
Esercizio 6 — Forma Ridotta (RREF) = Feature Selection Implicita
Problema: Trasformare una matrice in forma a gradini ridotta (Reduced Row Echelon Form).
Versione Data Science: Capire quali feature “comandano” le altre.
Interpretazione ML:
La RREF non si limita a dirti se c’è dipendenza, ma esprime le variabili dipendenti come combinazione di quelle indipendenti (i pivot).
- Esempio: Se la colonna 3 non ha un pivot, la RREF ti mostrerà coefficienti come [math]X_3 = 0.5 X_1 + 2 X_2[/math].
- Applicazione: Questo è l’algoritmo di “compressione” più vecchio del mondo. Ti dice che puoi eliminare [math]X_3[/math] senza perdere un briciolo di informazione, perché è totalmente ricostruibile dalle altre due.
Insight Critico:
Prima di usare algoritmi complessi di Feature Selection, una passata di RREF ti direbbe già chi è il “capo” (pivot) e chi è solo un “eco” (variabile libera). È algebra lineare pura, non black box.
Relazione Matematica nella RREF:
[math]\displaystyle \begin{aligned}
\text{Data una matrice } R = \text{RREF}(A): & \\
\mathbf{r}_j = \sum_{i \in \text{Pivots}} c_i \mathbf{r}_i \\
&{} \quad \text{(Dove } \mathbf{r}_j \text{ è una colonna senza pivot)}
\end{aligned}[/math]
In questo stato, ogni colonna pivot è un vettore della base canonica [math]\mathbf{e}_i[/math], rendendo immediata la lettura delle relazioni di dipendenza tra le feature originali.
Come calcolare la RREF in Python usando la libreria SymPy per identificare esattamente quali colonne del tuo dataset sono ridondanti
Mentre NumPy è il re del calcolo numerico, quando si tratta di diagnostica strutturale e di trovare la forma a gradini ridotta (RREF), la libreria SymPy è lo strumento superiore.
Il motivo è semplice: NumPy lavora con i numeri in virgola mobile (floating point), che possono generare errori di arrotondamento rendendo difficile capire se un valore è “zero” o solo un numero molto piccolo. SymPy, invece, esegue calcoli simbolici esatti.
Ecco come implementare il test del DNA del tuo dataset.
Identificare Feature Ridondanti con SymPy
Immaginiamo di avere un dataset dove la terza colonna è esattamente la somma delle prime due (ridondanza perfetta).
import numpy as np
from sympy import Matrix
# 1. Creiamo un dataset di esempio (4 osservazioni, 3 feature)
# Feature 3 = Feature 1 + Feature 2 (Ridondante!)
data = np.array([
[1, 2, 3],
[2, 3, 5],
[3, 4, 7],
[4, 5, 9]
])
# 2. Convertiamo in una matrice SymPy
# Nota: SymPy preferisce lavorare con frazioni esatte
sympy_matrix = Matrix(data)
# 3. Calcoliamo la RREF
# rref() restituisce una tupla: (la matrice a gradini, gli indici dei pivot)
rref_matrix, pivot_indices = sympy_matrix.rref()
print(f"Matrice RREF:\n{rref_matrix}")
print(f"\nIndici delle colonne Pivot (Indipendenti): {pivot_indices}")
# 4. Identifichiamo le colonne da eliminare
all_indices = range(data.shape[1])
redundant_indices = [i for i in all_indices if i not in pivot_indices]
print(f"Colonne ridondanti rilevate: {redundant_indices}")
# 5. Pulizia del dataset originale
clean_data = data[:, pivot_indices]
print(f"\nDataset pulito (solo colonne indipendenti):\n{clean_data}")
Matrice RREF:
Matrix([[1, 0, 1], [0, 1, 1], [0, 0, 0], [0, 0, 0]])
Indici delle colonne Pivot (Indipendenti): (0, 1)
Colonne ridondanti rilevate: [2]
Dataset pulito (solo colonne indipendenti):
[[1 2]
[2 3]
[3 4]
[4 5]]
Perché questo metodo è un “Superpotere” per un Data Scientist
Quando esegui .rref(), SymPy ti restituisce due elementi fondamentali:
-
La Matrice RREF: Ti mostra visivamente come le variabili dipendenti sono costruite. Se una colonna non ha un pivot, vedrai i coefficienti esatti che la legano alle altre.
-
Gli Indici dei Pivot (
pivot_indices): Questa è la tua “lista della spesa” per la Feature Selection. Qualsiasi colonna il cui indice NON è in questa lista è matematicamente superflua. Non aggiunge varianza, aggiunge solo rumore e complessità computazionale.
Quando usare SymPy vs NumPy/Scikit-Learn?
| Situazione | Strumento consigliato | Perché? |
| Debug del Dataset | SymPy.rref() |
Analisi esatta, identifica dipendenze lineari matematiche. |
| Dataset enorme (+10k feature) | SVD (NumPy/SciPy) |
Più veloce, gestisce la “quasi-collinearità” numerica. |
| Produzione / Training | Scikit-learn |
Ottimizzato per la velocità, non per la diagnostica strutturale. |
⚠️ Attenzione: SymPy è lento su matrici gigantesche perché calcola tutto in modo esatto. Usalo nelle fasi di Exploratory Data Analysis (EDA) su un campione significativo del tuo dataset per capire se il tuo processo di data collection sta creando duplicati logici.
I “sintomi” matematici e la loro “malattia” nel ML:
| Sintomo Matematico (Gauss/RREF) | Diagnosi Data Science | Impatto sul Modello |
| Meno Pivot delle Colonne | Multicollinearità / Ridondanza | Pesi w instabili, overfitting. |
| Riga Inconsistente [0..0 \| k | Dati Contraddittori | Errore minimo non nullo (Rumore alto). |
| Righe Nulle [0..0 \| 0 | Record Duplicati | Spreco di memoria e computazione. |
| Matrice Identità I | Feature Ortogonali | Massima interpretabilità dei coefficienti. |
| Variabili Libere | Sotto-determinazione | Il modello “inventa” pattern (Overfitting). |
Articoli di approfondimento
- 👉 Cos’è la multicollinearità: VIF e come risolvere la ridondanza nei dati
- 👉 Regressione lineare semplice e multipla: 6 esercizi per data analysis e business
- 👉 Python: la libreria SymPy e operazioni con le matrici
- 👉 Matrici in Python: dal parcheggio alla computer vision con NumPy
- 👉 Matrici in Python: guida pratica con esercizi di logica e data analysis
- 👉 A cosa servono le matrici? 9 esempi reali (Instagram, AI, videogiochi…)





