Ti è mai capitato di aprire un dataset, magari un export dal CRM o una tabella clinica, e sentirti sopraffatto? Colonne su colonne di numeri. Se provi a creare un grafico, vedi solo una nuvola di punti senza senso. Il problema quasi sempre non è che ti mancano i dati; è che ne hai troppi, e molti dicono la stessa cosa con parole diverse.
È come cercare di riconoscere il volto di un amico guardando cento foto scattate da angolazioni quasi identiche: invece di chiarirti le idee, ti confondono.
Qui entra in gioco la PCA (Analisi delle Componenti Principali). Non è una formula magica astratta, ma uno strumento pragmatico per smettere di fare il “contabile di numeri” e iniziare a vedere la struttura nascosta delle cose. La PCA prende quel caos, lo ruota e ti mostra l’angolazione perfetta: quella dove il segnale è forte e il rumore sparisce. In questo articolo vedremo come funziona, perché è la salvezza di chi lavora con i Big Data e come implementarla in Python senza perdersi nella teoria.
Cos’è la PCA: Il concetto geometrico
La PCA non “cancella” le variabili a caso; costruisce nuove variabili (chiamate componenti principali) come combinazioni delle originali.
Dal punto di vista geometrico, la PCA ruota lo spazio delle osservazioni in modo che:
- La prima componente principale (PC1) sia allineata nella direzione di massima dispersione dei dati (dove c’è più informazione).
- La seconda componente (PC2) sia ortogonale (perpendicolare) alla prima e spieghi la varianza rimanente.
Il risultato? Variabili nuove, indipendenti tra loro e ordinate per importanza.
Esempio Pratico Risolto: Altezza e Peso
Facciamo un’analisi dettagliata passo-passo. Immagina di avere i dati di 5 persone. Intuitivamente, sappiamo che altezza e peso sono correlati: chi è più alto tende a pesare di più.
1. Dati Originali
| Persona | Altezza (cm) | Peso (kg) |
|---|---|---|
| A | 170 | 65 |
| B | 180 | 80 |
| C | 160 | 55 |
| D | 190 | 90 |
| E | 155 | 50 |
Passo 1: Standardizzare i dati
La PCA è estremamente sensibile alla scala dei numeri. Se non standardizziamo, l’altezza (che ha valori intorno a 170) dominerà matematicamente il peso (valori intorno a 70) solo perché l’unità di misura è più grande.
Usiamo la formula dello Z-score:
[math]z = \frac{x – \mu}{\sigma}[/math]
Dove [math]\mu[/math] è la media e [math]\sigma[/math] è la deviazione standard.
- Altezza: [math]\mu = 171[/math], [math]\sigma = 13.69[/math]
- Peso: [math]\mu = 68[/math], [math]\sigma = 16.58[/math]
Esempio di calcolo per la Persona A:
[math]\displaystyle \begin{aligned}
\text{Altezza}_{std} &= \frac{170 – 171}{13.69} \\
&{} = -0.073
\end{aligned}[/math]
[math]\displaystyle \begin{aligned}
\text{Peso}_{std} &= \frac{65 – 68}{16.58} \\
&{} = -0.181
\end{aligned}[/math]
Ecco la tabella dei dati trasformati (che ora hanno media 0 e varianza 1):
| Persona | Altezza_std | Peso_std |
|---|---|---|
| A | -0.073 | -0.181 |
| B | 0.657 | 0.723 |
| C | -0.803 | -0.784 |
| D | 1.387 | 1.326 |
| E | -1.168 | -1.084 |
Passo 2: Matrice di Covarianza
Calcoliamo quanto le due variabili “si muovono insieme”. Poiché i dati sono standardizzati, la matrice di covarianza coincide con la matrice di correlazione.
La formula per la covarianza è:
[math]\displaystyle \begin{aligned}
\text{cov}(Z_1, Z_2) &= \frac{1}{n-1} \sum_{i=1}^{n} (z_{i,1} \cdot z_{i,2})
\end{aligned}[/math]
Il calcolo numerico ci dà:
[math]\displaystyle \begin{aligned}
\text{cov} &= \frac{(-0.073 \cdot -0.181) + \dots}{4} \\
&{} = 0.985
\end{aligned}[/math]
Cosa significa? Un valore di 0.985 (vicinissimo a 1) indica che le due variabili contengono informazioni quasi identiche.
Passo 3: Autovalori e Autovettori
Qui avviene la “magia”. Cerchiamo le direzioni (autovettori) e la quantità di varianza spiegata (autovalori [math]\lambda[/math]).
Risolviamo l’equazione caratteristica per la matrice [math]2 \times 2[/math]:
[math]\det(A – \lambda I) = 0[/math]
Sviluppando il determinante:

Risolvendo l’equazione quadratica otteniamo gli autovalori:
[math]\displaystyle \begin{aligned}
\lambda_1 &= 1.985 \quad \text{(PC1)} \\
\lambda_2 &= 0.015 \quad \text{(PC2)}
\end{aligned}[/math]
Interpretazione:
- La PC1 spiega il [math]99.25\%[/math] della varianza ([math]1.985 / 2[/math]).
- La PC2 spiega solo lo [math]0.75\%[/math] (è praticamente rumore).
L’autovettore associato alla PC1 risulta essere [math][0.707, 0.707][/math]. Essendo i valori uguali, significa che Altezza e Peso contribuiscono equamente alla “dimensione complessiva” della persona.
Passo 4: Proiezione dei Dati
Ora trasformiamo le coordinate originali nella nuova componente principale (PC1).
Formula di proiezione:
[math]\displaystyle \begin{aligned}
\text{PC1} &= (0.707 \cdot \text{Altezza}_{std}) \\
&{} \quad + (0.707 \cdot \text{Peso}_{std})
\end{aligned}[/math]
Calcolo per la Persona A:
[math]\displaystyle \begin{aligned}
\text{PC1}_A &= (0.707 \cdot -0.073) \\
&{} \quad + (0.707 \cdot -0.181) \\
&{} = -0.0516 – 0.1279 \\
&{} = -0.179
\end{aligned}[/math]
Ripetendo per tutti, otteniamo un singolo valore che riassume la “stazza” della persona, riducendo le colonne da 2 a 1 senza perdere informazioni reali.
Esempio pratico in Python con Scikit-learn
Ecco uno script pronto all’uso per applicare la PCA su un dataset reale (il dataset “Wine”).
# ====================================
# Esempio PCA con scikit-learn (Python)
# ====================================
import numpy as np
import pandas as pd
from sklearn.datasets import load_wine
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# --- 1. Carico dataset di esempio (Wine) ---
data = load_wine()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target
print("Shape originale:", X.shape)
# --- 2. Standardizzo i dati ---
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# --- 3. PCA (tutte le componenti) ---
pca = PCA()
X_pca = pca.fit_transform(X_scaled)
# --- 4. Spiegazione della varianza ---
explained = pca.explained_variance_ratio_
cum_var = np.cumsum(explained)
print("Varianza spiegata dalle prime componenti:", cum_var[:5])
# Plot varianza cumulativa
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(cum_var) + 1), cum_var, marker='o')
plt.title("Varianza cumulativa spiegata dalle componenti")
plt.xlabel("Numero di componenti")
plt.ylabel("Varianza cumulativa")
plt.grid(True)
plt.show()
# --- 5. Proiezione su prime 2 componenti ---
pca_2 = PCA(n_components=2)
X_pca2 = pca_2.fit_transform(X_scaled)
plt.figure(figsize=(7, 5))
for label in np.unique(y):
plt.scatter(
X_pca2[y == label, 0],
X_pca2[y == label, 1],
label=f"Classe {label}"
)
plt.title("Proiezione PCA su prime 2 componenti")
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.legend()
plt.grid(True)
plt.show()
Spiegazione
-
Step 1: carichiamo il dataset Wine, con 13 variabili chimiche.
-
Step 2: standardizziamo perché PCA è sensibile alle scale diverse.
-
Step 3–4: calcoliamo tutte le componenti e osserviamo quanta varianza cumulativa catturano.
-
Grafico: la curva di varianza cumulativa aiuta a scegliere quante componenti mantenere.
-
Step 5: riduzione a 2 componenti e visualizzazione in un grafico 2D.
Varianza spiegata dalle prime componenti: [0.36198848 0.55406338 0.66529969 0.73598999 0.80162293]


6 Esercizi Progressivi sulla PCA
Questi esercizi simulano problemi reali di analisi dati.
Esercizio 1: La Logica della Varianza
Scenario: Hai un dataset con “Ore di studio” e “Voto esame”. I punti formano quasi una retta perfetta.
Soluzione: La [math]PC1[/math] si posizionerebbe esattamente lungo la retta di regressione. Se la correlazione è [math]r=0.95[/math], la PC1 catturerebbe quasi il [math]100\%[/math] della varianza. Potresti sostituire due variabili con una sola (“Performance”) senza perdere dati.
Esercizio 2: L’Incubo delle Scale
Scenario: Analizzi “Stipendio” ([math]20.000 – 150.000[/math]) e “Figli” ([math]0 – 5[/math]) senza standardizzare.
Soluzione: La PCA fallirà. Poiché la varianza dello stipendio è in milioni e quella dei figli è minuscola, la PC1 ignorerà completamente i figli e diventerà una copia della colonna stipendio. Standardizzare è obbligatorio.
Esercizio 3: Interpretazione del Gomito
Scenario: Autovalori: [math]4.5, 2.8, 1.2, 0.5 \dots[/math] su 10 variabili totali.
Soluzione: Somma totale autovalori = 10.
Varianza PC1: [math]45\%[/math].
Varianza PC2: [math]28\%[/math].
Totale primi due: [math]73\%[/math]. Secondo il “Criterio di Kaiser” (autovalori [math]>1[/math]), dovresti tenere 3 componenti.
Esercizio 4: I “Loadings” (Interpretazione Business)
Scenario: La PC1 ha pesi alti su Altezza e Spalle, ma peso quasi zero sul Colore Occhi.
Interpretazione: Questa componente rappresenta la “Struttura Fisica”. Dare un nome alle componenti aiuta a trasformare i numeri in insight di business.
Esercizio 5: Ricostruzione e Errore
Domanda: Se riduci da 100 a 5 dimensioni (spiegando l’85% della varianza) e poi ricostruisci i dati, ottieni i valori originali esatti?
Risposta: No. Hai perso il 15% di informazione (dettagli minori o rumore). La ricostruzione sarà una versione “ripulita” (denoised) dei dati.
Esercizio 6: PCA e Outlier
Scenario: Un punto isolato in un angolo del grafico PCA.
Soluzione: Quell’outlier sta probabilmente “tirando” gli assi verso di sé. La PCA cerca di massimizzare la varianza quadratica, quindi un singolo errore estremo può falsare l’intera rotazione degli assi. In questi casi, serve una pulizia preventiva dei dati.
Approfondimento: L’Impatto degli Outlier
La PCA teme gli outlier perché la covarianza si basa sul quadrato delle distanze. Un punto molto lontano “pesa” moltissimo nel calcolo.
In questo script genereremo un dataset correlato e vedremo come cambia la direzione della prima componente principale (PC1) aggiungendo un solo outlier.
import numpy as np import matplotlib.pyplot as plt from sklearn.decomposition import PCA # 1. Creiamo dati puliti molto correlati np.random.seed(10) x = np.random.normal(0, 1, 50) y = x * 1.5 + np.random.normal(0, 0.3, 50) # Forte pendenza data_clean = np.vstack([x, y]).T # 2. Creiamo un dataset con un outlier "laterale" massiccio # Un punto che ha molta varianza su X ma poca su Y, per "tirare" la PCA outlier = np.array([[15, 2]]) data_outlier = np.vstack([data_clean, outlier]) def plot_pca_direction(data, ax, title): pca = PCA(n_components=1) pca.fit(data) # La componente principale (direzione) v1 = pca.components_[0] # La varianza (lunghezza per il grafico) s1 = np.sqrt(pca.explained_variance_[0]) # Calcoliamo il centro dei dati (Media) mean = data.mean(axis=0) ax.scatter(data[:, 0], data[:, 1], alpha=0.5, label="Dati") # Disegniamo la freccia partendo dalla MEDIA dei dati ax.quiver(mean[0], mean[1], v1[0]*s1, v1[1]*s1, angles='xy', scale_units='xy', scale=0.5, color='red', width=0.015, label="Direzione PC1") ax.set_title(title) ax.grid(True) ax.set_aspect('equal') fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6)) plot_pca_direction(data_clean, ax1, "PCA Dati Puliti\n(PC1 allineata ai dati)") plot_pca_direction(data_outlier, ax2, "PCA con Outlier\n(PC1 deviata verso l'errore)") plt.legend() plt.show()
Cosa osserviamo nel grafico?
-
A sinistra (Dati puliti): La linea rossa (PC1) taglia perfettamente la nuvola di punti lungo la sua lunghezza. Descrive correttamente la relazione tra X e Y.
-
A destra (Con outlier): Nonostante ci siano 100 punti che vanno in una direzione e solo 1 che va nell’altra, la freccia rossa si è inclinata verso il basso.
-
L’effetto: La PCA ora “crede” che la varianza principale sia un mix tra la diagonale e il punto isolato. Se usassimo questa PC1 per comprimere i dati, perderemmo molta precisione sugli altri 100 punti.
-
Consiglio pratico: Prima di lanciare una PCA, usa sempre metodi come l’IQR (Interquartile Range) per rimuovere anomalie estreme, oppure utilizza varianti come la Robust PCA.
Machine Learning & Customer Analytics
📘 Segmentazione clienti con Python: guida completa (K-Means, PCA, t-SNE)
📘 Segmentazione clienti avanzata: RFM, PCA e predittivi per il modello di Abell
📘 Tutorial completo Scikit-Learn (sklearn): guida al machine learning in Python
📘 Machine Learning essenziale: 6 algoritmi chiave con esempi in Python
📘 Analisi dati customer-centrica con Python: 4 metodi (CLV, sentiment, churn)






