C’è una bugia che ci raccontiamo spesso davanti ai report di fine mese:
se il grafico del fatturato sale, va tutto bene.
Non è vero.
Ho visto aziende investire budget enormi per acquisire clienti che, a conti fatti, costavano più di quanto rendessero. Il problema non è la mancanza di dati, anzi. Ne abbiamo troppi e spesso guardiamo quelli sbagliati.
Ci ossessioniamo sul volume (quanto comprano?) ignorando quasi sempre l’efficienza (quanto ci costa servirli?).
Un cliente che spende 1.000€ ma ne restituisce 400€ e acquista solo col 30% di sconto non è una risorsa: è un danno logistico.
Ho visto e-commerce festeggiare record di vendite al Black Friday, per poi andare in crisi di liquidità a gennaio quando il 40% della merce è tornata indietro danneggiata.
Ma in un foglio Excel classico, quel cliente appare identico a uno che ne spende 600€ a prezzo pieno e non fa mai un reso. Oggi vediamo come smettere di farsi ingannare dai numeri aggregati, usando la Data Science non per fare accademia, ma per pulire la lente con cui guardiamo il business.
In questo scenario, il Data Scientist non è un semplice “masticatore di numeri”, ma un traduttore: deve prendere un groviglio di 5 o 10 variabili e sintetizzarle in direzioni strategiche chiare. La PCA (Principal Component Analysis) non serve a fare calcoli eleganti, serve a pulire la lente con cui osserviamo il business, separando chi porta valore reale da chi erode i margini.
Il Caso Studio: Trasformare 5 Variabili in Strategia
Immaginiamo un dataset di 1.000 clienti di un e-commerce di moda, definiti da:
-
X1 (Ordini): Frequenza d’acquisto.
-
X2 (Spesa): Valore monetario.
-
X3 (Varietà): Ampiezza del catalogo esplorato.
-
X4 (Sconti): Dipendenza dalle promozioni.
-
X5 (Resi): Impatto logistico.
1. La Selezione: Quanta informazione è “abbastanza”?
La PCA trasforma queste variabili in Componenti Principali (PC). Ecco i risultati:
| Componente | Autovalore (λ) | Varianza Spiegata | Varianza Cumulativa |
| PC1 | 2,40 | 48% | 48% |
| PC2 | 1,30 | 26% | 74% |
| PC3 | 0,80 | 16% | 90% |
| PC4 | 0,35 | 7% | 97% |
| PC5 | 0,15 | 3% | 100% |
L’occhio critico del Data Scientist:
Se seguissimo il Criterio di Kaiser (lambda > 1), ci fermeremmo a 2 componenti. Ma attenzione: con 2 componenti copriamo il 74% della varianza. Se il business richiede una precisione chirurgica sui resi (che spesso finiscono nelle componenti “minori”), dovremmo includere la terza (PC3) per arrivare al 90%.
Tuttavia, per la visualizzazione e la semplicità di marketing, la struttura a 2 dimensioni (PC1 e PC2) è il compromesso ideale.
2. Interpretazione: Dare un nome ai nuovi assi
Non chiamiamole PC1 e PC2. In un report direzionale, queste diventano:
-
PC1 – “Indice di Vitalità” (Loadings positivi su Ordini, Spesa, Varietà): Rappresenta quanto il cliente è “dentro” l’ecosistema del brand.
-
PC2 – “Indice di Rischio Operativo” (Loadings alti su Sconti e Resi): Identifica chi compra solo se stimolato dal prezzo e chi restituisce troppo, gravando sui costi di spedizione.
3. I Segmenti: Chi stiamo premiando?
Dalla proiezione dei dati sui nuovi assi, emergono tre figure chiare:
-
Cluster A: I Top Clients (PC1+, PC2-). Sono la spina dorsale dell’azienda. Comprano a prezzo pieno e tengono i prodotti.
-
Strategia: Non disturbateli con sconti. Offrite loro privilegi immateriali (anteprime, community, eventi).
-
-
Cluster B: I Serial Returners (PC1-, PC2+). Spesso scambiati per “buoni clienti” perché fanno volumi, ma il loro margine netto è vicino allo zero o negativo.
-
Strategia: Introdurre policy di reso più restrittive o eliminare la spedizione gratuita per questo specifico segmento.
-
-
Cluster C: I Potenziali (PC1 media, PC2 media). La classe media dell’e-commerce.
-
Strategia: Cross-selling. L’obiettivo è aumentare la loro varietà di acquisto (PC1) senza farli scivolare nel vizio del reso (PC2).
-
Implementazione Python: PCA + K-means Clustering
Per passare dalla teoria alla pratica, ecco uno script Python completo che simula 1.000 clienti, riduce le dimensioni e identifica automaticamente i segmenti di mercato.
# ============================================
# PCA + K-means: Segmentazione Avanzata (Coerente con la Strategia)
# ============================================
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import seaborn as sns
# --------------------------------------------
# 1. Creazione Dataset con Archetipi Definiti
# --------------------------------------------
np.random.seed(42)
# Definiamo 3 archetipi comportamentali per garantire che i pattern esistano
# A: VIP (Tanti ordini, Spesa alta, Resi bassi, Sconti bassi)
# B: Serial Returners (Tanti ordini, Spesa media, Resi altissimi, Cacciatori di sconti)
# C: Standard (Pochi ordini, Spesa bassa, Resi medi)
n_vip = 200
n_ret = 200
n_std = 600
# Generazione VIP
vip_data = pd.DataFrame({
"Ordini": np.random.poisson(12, n_vip),
"Spesa": np.random.normal(120, 15, n_vip),
"Varieta": np.random.normal(8, 1, n_vip),
"Sconti": np.random.normal(5, 2, n_vip), # Poco sconto
"Resi": np.random.normal(5, 2, n_vip) # Reso fisiologico
})
# Generazione Serial Returners
ret_data = pd.DataFrame({
"Ordini": np.random.poisson(10, n_ret), # Comprano molto anche loro
"Spesa": np.random.normal(90, 10, n_ret),
"Varieta": np.random.normal(5, 2, n_ret),
"Sconti": np.random.normal(30, 5, n_ret), # Molto sconto
"Resi": np.random.normal(45, 5, n_ret) # Reso patologico
})
# Generazione Utenti Standard
std_data = pd.DataFrame({
"Ordini": np.random.poisson(3, n_std),
"Spesa": np.random.normal(40, 10, n_std),
"Varieta": np.random.normal(2, 1, n_std),
"Sconti": np.random.normal(15, 5, n_std),
"Resi": np.random.normal(10, 5, n_std)
})
df = pd.concat([vip_data, ret_data, std_data]).reset_index(drop=True)
# Correzione valori negativi non realistici
df[df < 0] = 0
print("Statistiche descrittive del dataset simulato:")
print(df.describe().round(1))
# --------------------------------------------
# 2. Standardizzazione e PCA
# --------------------------------------------
scaler = StandardScaler()
X_scaled = scaler.fit_transform(df)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
# --- CORREZIONE DEL SEGNO (Step Cruciale per la coerenza) ---
# Vogliamo assicurarci che:
# PC1 cresca con la Spesa/Ordini (Vitalità)
# PC2 cresca con i Resi/Sconti (Rischio)
# Controlliamo il peso (loading) della variabile 'Spesa' sulla PC1
idx_spesa = 1
if pca.components_[0, idx_spesa] < 0:
X_pca[:, 0] = -X_pca[:, 0] # Invertiamo asse PC1
pca.components_[0] = -pca.components_[0]
# Controlliamo il peso della variabile 'Resi' sulla PC2
idx_resi = 4
if pca.components_[1, idx_resi] < 0:
X_pca[:, 1] = -X_pca[:, 1] # Invertiamo asse PC2
pca.components_[1] = -pca.components_[1]
# Salviamo i risultati nel DataFrame
df["Indice_Vitalita"] = X_pca[:, 0] # Ex PC1
df["Indice_Rischio"] = X_pca[:, 1] # Ex PC2
print(f"\nVarianza spiegata cumulativa: {np.sum(pca.explained_variance_ratio_)*100:.1f}%")
# --------------------------------------------
# 3. K-means Clustering e Auto-Labeling
# --------------------------------------------
kmeans = KMeans(n_clusters=3, random_state=42, n_init=10)
df["Cluster_ID"] = kmeans.fit_predict(X_pca)
# Calcolo dei centroidi per capire chi è chi
centroidi = df.groupby("Cluster_ID")[["Indice_Vitalita", "Indice_Rischio"]].mean()
# --- MAPPATURA INTELLIGENTE (Dal numero al nome business) ---
# Logica:
# 1. Il cluster con Rischio (PC2) più alto è "Serial Returner"
# 2. Tra i rimanenti, quello con Vitalità (PC1) più alta è "Top Client"
# 3. L'ultimo è "Standard/Potential"
cluster_map = {}
# Trova i Serial Returners (Max PC2)
id_serial = centroidi["Indice_Rischio"].idxmax()
cluster_map[id_serial] = "Serial Returners (Rischio Alto)"
# Escludiamo i serial returners per trovare i VIP
rimanenti = centroidi.drop(id_serial)
id_vip = rimanenti["Indice_Vitalita"].idxmax()
cluster_map[id_vip] = "Top Clients (Valore Alto)"
# L'ultimo rimasto
id_std = list(set(centroidi.index) - {id_serial, id_vip})[0]
cluster_map[id_std] = "Potentials (Segmento Medio)"
# Applichiamo le etichette
df["Segmento"] = df["Cluster_ID"].map(cluster_map)
# --------------------------------------------
# 4. Visualizzazione Strategica
# --------------------------------------------
plt.figure(figsize=(12, 8))
sns.scatterplot(
data=df,
x="Indice_Vitalita",
y="Indice_Rischio",
hue="Segmento",
palette={"Top Clients (Valore Alto)": "#2ecc71", # Verde
"Serial Returners (Rischio Alto)": "#e74c3c", # Rosso
"Potentials (Segmento Medio)": "#3498db"}, # Blu
style="Segmento",
s=80,
alpha=0.7
)
# Aggiungiamo linee per dividere i quadranti (origine degli assi)
plt.axhline(0, color='grey', linestyle='--', linewidth=0.8)
plt.axvline(0, color='grey', linestyle='--', linewidth=0.8)
plt.title("Mappa Strategica Clienti: Valore vs Rischio Operativo", fontsize=15)
plt.xlabel("Indice di Vitalità (Volumi e Varietà) →", fontsize=12)
plt.ylabel("Indice di Rischio (Resi e Sconti) →", fontsize=12)
plt.legend(title="Strategia Assegnata", loc='upper right')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# --------------------------------------------
# 5. Output per il Marketing (Actionable Insights)
# --------------------------------------------
print("\n--- ANALISI DEI SEGMENTI PER IL CRM ---")
summary = df.groupby("Segmento")[["Ordini", "Spesa", "Resi", "Sconti"]].mean().round(1)
print(summary)
Sintesi: Perchè usiamo PC1 e PC2 per il Clustering?
Eseguire il K-means direttamente sulle 5 variabili originali soffrirebbe della multicollinearità. In un e-commerce, “Ordini annui” e “Spesa media” dicono quasi la stessa cosa (Volume). Usarli entrambi darebbe un peso doppio alla dimensione “Volume”, schiacciando variabili critiche ma con valori numerici diversi come i “Resi”.
La PCA “pulisce” queste sovrapposizioni. Il valore reale sta nella capacità di isolare matematicamente il comportamento d’acquisto dal costo logistico, permettendoci di vedere i clienti per quello che sono veramente: profitto o perdita.
Machine Learning & Customer Analytics
📘 PCA: Analisi componenti principali – guida completa con Python
📘 Segmentazione clienti con Python: guida completa (K-Means, PCA, t-SNE)
📘 Segmentazione clienti avanzata: RFM, PCA e metodi predittivi
📘 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: CLV, sentiment, churn





