Feature Scaling in Python: StandardScaler vs MinMaxScaler
Capita quasi a tutti i data scientist alle prime armi: pulisci i dati, scegli l’algoritmo con cura, fai partire l’addestramento e… i risultati sono disastrosi.
Eppure il codice è perfetto.
Il problema, quasi sempre, si nasconde in un dettaglio noioso ma fondamentale che hai saltato: non hai messo le variabili sulla stessa scala. Se chiedi a un modello di confrontare l’età di un cliente (che va da 18 a 90) con il suo conto in banca (che va da zero a milioni), l’algoritmo darà tutto il peso ai soldi, semplicemente perché i numeri sono “più grossi”.
È qui che entra in gioco il Feature Scaling. Fortunatamente, Python ci semplifica la vita con due strumenti pronti all’uso: StandardScaler e MinMaxScaler. Sembrano simili, ma fanno cose completamente diverse.
Entrambi trasformano i dati, ma con obiettivi differenti.
In questo articolo vedremo:
- cosa significa fare Feature Scaling;
- quando utilizzare StandardScaler;
- quando preferire MinMaxScaler;
- quali algoritmi ne beneficiano;
- confronti grafici;
- esempi pratici completamente commentati;
- esercizi svolti in Python.
Cos’è il Feature Scaling?
Supponiamo di avere un dataset di clienti.
| Età | Reddito (€) |
|---|---|
| 22 | 22000 |
| 35 | 65000 |
| 58 | 120000 |
Osserviamo subito un problema.
L’età varia tra:
[math]22[/math] e [math]58[/math]
mentre il reddito varia tra
[math]22.000[/math] e [math]120.000[/math]
Se calcoliamo una distanza euclidea:
[math]\displaystyle d = \sqrt{(x_1 – x_2)^2 + (y_1 – y_2)^2}[/math]
il reddito peserà enormemente più dell’età.
L’algoritmo finirà quindi per considerare quasi esclusivamente il reddito.
Il Feature Scaling serve proprio a riportare tutte le variabili su una scala confrontabile.
Due approcci differenti
Scikit-learn offre principalmente due trasformazioni.
1. StandardScaler
Trasforma ogni variabile in modo che abbia:
- media = 0
- deviazione standard = 1
La formula è
[math]\displaystyle z = \frac{x – \mu}{\sigma}[/math]
dove
- [math]\mu[/math] è la media
- [math]\sigma[/math] è la deviazione standard.
2. MinMaxScaler
Trasforma i valori nell’intervallo
[math][0,1][/math]
utilizzando
[math]\displaystyle x’ = \frac{x – x_{\min}}{x_{\max} – x_{\min}}[/math]
Il valore minimo diventa 0.
Il massimo diventa 1.
Tutti gli altri vengono distribuiti proporzionalmente.
Visualizziamo la differenza
Consideriamo i dati
import numpy as np
eta = np.array([22, 30, 40, 55, 60])
Valori originali
22
30
40
55
60
Con StandardScaler otteniamo ad esempio
-1.28
-0.67
0.08
1.20
1.57
Con MinMaxScaler
0.00
0.21
0.47
0.87
1.00
Le due trasformazioni sono completamente differenti.
Implementazione con Scikit-Learn
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
df = pd.DataFrame({
"Eta": [22, 30, 40, 55, 60],
"Reddito": [22000, 35000, 52000, 85000, 120000]
})
standard = StandardScaler()
minmax = MinMaxScaler()
df_standard = pd.DataFrame(
standard.fit_transform(df),
columns=df.columns
)
df_minmax = pd.DataFrame(
minmax.fit_transform(df),
columns=df.columns
)
print(df_standard)
print(df_minmax)
Output
StandardScaler
| Età | Reddito |
|---|---|
| -1.28 | -1.18 |
| -0.67 | -0.82 |
| 0.08 | -0.34 |
| 1.20 | 0.58 |
| 1.57 | 1.76 |
MinMaxScaler
| Età | Reddito |
|---|---|
| 0.00 | 0.00 |
| 0.21 | 0.13 |
| 0.47 | 0.34 |
| 0.87 | 0.72 |
| 1.00 | 1.00 |
Rappresentazione grafica
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 3, figsize=(15, 4))
ax[0].scatter(df["Eta"], df["Reddito"])
ax[0].set_title("Originale")
ax[1].scatter(df_standard["Eta"], df_standard["Reddito"])
ax[1].set_title("StandardScaler")
ax[2].scatter(df_minmax["Eta"], df_minmax["Reddito"])
ax[2].set_title("MinMaxScaler")
plt.show()
Il grafico evidenzia come la geometria relativa dei dati venga preservata, ma cambi completamente la scala delle coordinate.
Quando usare StandardScaler?
È generalmente la scelta migliore quando l’algoritmo assume dati distribuiti attorno alla media.
È consigliato per:
- Regressione Logistica
- Regressione Lineare con regolarizzazione
- Support Vector Machine
- PCA
- K-Means
- K-NN
- Reti neurali
Il motivo è semplice.
Molti algoritmi lavorano con:
- distanze
- prodotti scalari
- gradienti
Avere media zero rende il training molto più stabile.
Quando usare MinMaxScaler?
MinMaxScaler è ideale quando vogliamo mantenere la forma della distribuzione limitando i dati in un intervallo fisso.
È spesso utilizzato con:
- reti neurali
- autoencoder
- immagini
- dati normalizzati
- algoritmi che utilizzano funzioni sigmoidali
Molte reti neurali convergono più rapidamente con dati compresi tra 0 e 1.
Attenzione agli Outlier
Immaginiamo questo dataset
| Valore |
|---|
| 10 |
| 12 |
| 13 |
| 15 |
| 1000 |
Con MinMaxScaler
- 10 -> 0
- 12 -> 0.002
- 13 -> 0.003
- 15 -> 0.005
- 1000 -> 1
Quasi tutti i dati vengono compressi.
StandardScaler invece distribuisce meglio i valori attorno alla media, anche se rimane comunque influenzato dagli outlier.
Per dataset con molti valori anomali spesso è preferibile utilizzare RobustScaler, che utilizza mediana e intervallo interquartile (IQR), risultando molto meno sensibile agli estremi.
Impatto su K-Nearest Neighbors
Consideriamo due clienti
Cliente A
- Età = 25
- Reddito = 25000
Cliente B
- Età = 30
- Reddito = 26000
Cliente C
- Età = 28
- Reddito = 100000
Senza scaling, la distanza sarà dominata dal reddito.
K-NN considererà clienti con reddito simile anche se molto differenti per età.
Dopo lo scaling entrambe le caratteristiche contribuiscono in modo equilibrato.
Questo rende il classificatore significativamente più accurato.
Impatto su K-Means
K-Means minimizza la distanza dai centroidi.
Se una variabile possiede valori cento volte maggiori delle altre, il clustering verrà costruito quasi esclusivamente su quella variabile.
Lo scaling permette ai centroidi di rappresentare tutte le feature.
Algoritmi che NON richiedono Scaling
Esistono anche algoritmi praticamente insensibili alla scala.
Tra questi:
- Decision Tree
- Random Forest
- XGBoost
- LightGBM
- CatBoost
Gli alberi decisionali effettuano divisioni basate su soglie e non sul concetto di distanza.
Lo scaling raramente modifica le prestazioni.
Tabella riassuntiva
| Algoritmo | Scaling consigliato |
|---|---|
| KNN | ✔ |
| KMeans | ✔ |
| SVM | ✔ |
| PCA | ✔ |
| Logistic Regression | ✔ |
| Neural Network | ✔ |
| Random Forest | ✖ |
| Decision Tree | ✖ |
| XGBoost | ✖ |
Errori comuni
I principianti commettono spesso questi errori:
- eseguire lo scaling anche sulla variabile target senza motivo;
- adattare (fit) lo scaler sia sul training sia sul test set, causando data leakage;
- scegliere MinMaxScaler solo perché produce valori compresi tra 0 e 1, senza considerare la presenza di outlier;
- dimenticare di applicare la stessa trasformazione ai nuovi dati in fase di predizione.
La procedura corretta è:
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
In questo modo il test set viene trasformato utilizzando esclusivamente le statistiche apprese dal training.
Esercizio svolto 1 – Confronto tra StandardScaler e MinMaxScaler
Supponiamo di avere il seguente dataset relativo ad alcuni clienti.
import pandas as pd
from sklearn.preprocessing import StandardScaler, MinMaxScaler
df = pd.DataFrame({
"Eta": [20, 25, 30, 35, 40],
"Reddito": [20000, 30000, 45000, 70000, 100000]
})
print("Dataset originale")
print(df)
# Standardizzazione
standard = StandardScaler()
df_standard = pd.DataFrame(
standard.fit_transform(df),
columns=df.columns
)
print("\nDataset standardizzato")
print(df_standard)
# Normalizzazione
minmax = MinMaxScaler()
df_minmax = pd.DataFrame(
minmax.fit_transform(df),
columns=df.columns
)
print("\nDataset normalizzato")
print(df_minmax)
Dataset originale
Eta Reddito
0 20 20000
1 25 30000
2 30 45000
3 35 70000
4 40 100000
Dataset standardizzato
Eta Reddito
0 -1.414214 -1.141329
1 -0.707107 -0.795472
2 0.000000 -0.276686
3 0.707107 0.587957
4 1.414214 1.625529
Dataset normalizzato
Eta Reddito
0 0.00 0.0000
1 0.25 0.1250
2 0.50 0.3125
3 0.75 0.6250
4 1.00 1.0000
Spiegazione
Nel dataset originale le due variabili hanno ordini di grandezza molto diversi: l’età varia tra 20 e 40, mentre il reddito tra 20.000 e 100.000 euro. Un algoritmo basato sulle distanze attribuirebbe un peso quasi esclusivo al reddito.
Con StandardScaler, entrambe le colonne vengono centrate sulla media e scalate rispetto alla deviazione standard. I valori negativi indicano osservazioni sotto la media, quelli positivi sopra la media.
Con MinMaxScaler, invece, ogni variabile viene trasformata nell’intervallo [math][0, 1][/math]. Il valore minimo diventa 0 e il massimo 1, mantenendo inalterata la posizione relativa degli altri valori.
Questo esercizio mostra che le due tecniche non sono intercambiabili: producono trasformazioni diverse e possono influenzare il comportamento degli algoritmi.
Dietro le quinte della trasformazione
Dal punto di vista applicativo, questo script smonta una falsa credenza comune: molti pensano che StandardScaler porti i dati tra [math]-1[/math] e [math]1[/math]. Questo esercizio dimostra visivamente, stampando il DataFrame, che non c’è un limite prefissato (l’età [math]40[/math] diventa [math]1.41[/math], il reddito [math]100k[/math] diventa [math]1.62[/math]). Dimostra inoltre che MinMaxScaler distrugge la varianza reale dei dati per confinarli in una “scatola” perfetta tra [math]0[/math] e [math]1[/math]. In produzione, usare l’uno o l’altro cambia completamente il modo in cui i pesi di una Rete Neurale verranno aggiornati nella prima epoca di training.
Esercizio svolto 2 – Effetto dello scaling su K-NN
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# Dataset
wine = load_wine()
X = wine.data
y = wine.target
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.30,
random_state=42
)
# -----------------------------
# KNN senza scaling
# -----------------------------
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
pred = knn.predict(X_test)
print("Accuracy senza scaling:",
accuracy_score(y_test, pred))
# -----------------------------
# KNN con StandardScaler
# -----------------------------
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
knn_scaled = KNeighborsClassifier(n_neighbors=5)
knn_scaled.fit(X_train_scaled, y_train)
pred_scaled = knn_scaled.predict(X_test_scaled)
print("Accuracy con scaling:",
accuracy_score(y_test, pred_scaled))
Accuracy senza scaling: 0.7407407407407407
Accuracy con scaling: 0.9629629629629629
Commento
Il dataset Wine contiene variabili con scale molto differenti (ad esempio concentrazione di alcol, flavonoidi, intensità del colore). K-NN calcola la distanza euclidea tra le osservazioni: senza scaling, le feature con valori più grandi dominano il calcolo della distanza.
Dopo la standardizzazione, ogni caratteristica contribuisce in modo più equilibrato. Nella maggior parte delle esecuzioni si osserva un aumento dell’accuratezza, a dimostrazione dell’importanza del preprocessing.
L’aspetto fondamentale non è tanto il valore numerico finale dell’accuratezza, che può variare in base alla suddivisione del dataset e al numero di vicini scelti, quanto il principio: quando un algoritmo misura distanze, lo scaling è spesso determinante per ottenere prestazioni affidabili.
L’impatto reale sui modelli basati su distanza (K-NN)
Questo è il cuore pratico dell’articolo. Non si limita a dire “K-NN migliora con lo scaling”, ma lo dimostra passando da un modesto 74% a un eccellente 96% di accuratezza sullo stesso identico dataset. Applicativamente, questo snippet di codice insegna il workflow corretto e inattaccabile per la messa in produzione di un modello: lo scaler deve “imparare” (tramite il metodo
fit) le statistiche solo sui dati di training. Applicare ilfitanche sul test set causerebbe Data Leakage, ovvero fornirebbe all’algoritmo informazioni dal futuro (i dati di test) durante l’addestramento, invalidando l’intera metrica di accuratezza.
Il tocco da professionista: automatizzare tutto con le Pipeline
Fino a qui abbiamo visto come applicare lo scaler manualmente: prima sul training set, e poi sul test set. Dal punto di vista didattico è fondamentale per capire il meccanismo, ma nel mondo reale (e in produzione) quasi nessun Data Scientist scrive il codice in questo modo.
Gestire gli step separatamente diventa rischioso, specialmente quando si introduce la Cross-Validation: è facilissimo confondersi e causare data leakage.
La soluzione moderna ed elegante offerta da Scikit-Learn si chiama Pipeline. Una Pipeline incatena la fase di trasformazione (lo scaling) e la fase di predizione (il modello) in un unico oggetto.
Vediamo come riscrivere l’Esercizio 2 (quello su K-NN) utilizzando le Pipeline:
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
# 1. Caricamento Dati
wine = load_wine()
X_train, X_test, y_train, y_test = train_test_split(
wine.data, wine.target, test_size=0.30, random_state=42
)
# 2. Creazione della Pipeline
pipeline = Pipeline([
("scaler", StandardScaler()),
("knn", KNeighborsClassifier(n_neighbors=5))
])
# 3. Addestramento in un solo passaggio!
# La pipeline applicherà in automatico fit_transform() allo scaler e fit() a K-NN
pipeline.fit(X_train, y_train)
# 4. Predizione
# La pipeline applicherà in automatico transform() allo scaler usando le
# statistiche del training, per poi passare i dati scalati al predict() di K-NN
pred = pipeline.predict(X_test)
print("Accuracy con Pipeline:", accuracy_score(y_test, pred))
Accuracy con Pipeline: 0.9629629629629629
Perché usare le Pipeline ti cambia la vita?
- Zero Data Leakage garantito: Ci pensa Scikit-Learn a chiamare
fit_transformin fase di addestramento e solotransformin fase di predizione. Non puoi più sbagliare. - Codice pulito: Riduci le righe di codice e rendi la logica del tuo script immediatamente leggibile per i colleghi.
- Deploy immediato: Quando devi salvare il modello per metterlo in produzione (ad esempio esportandolo con
joblibopickle), esporti l’intera Pipeline. Se avessi tenuto scaler e modello separati, avresti dovuto salvare due file distinti e ricaricarli entrambi nel tuo server di produzione, raddoppiando le possibilità di errore.
Come si usa realmente in produzione: Pipeline + GridSearchCV + Cross-Validation
Negli esempi precedenti abbiamo separato manualmente i passaggi per capire cosa succede sotto il cofano. Nel mondo reale, applicare lo scaling a mano prima della Cross-Validation è uno degli errori più frequenti e gravi: causa Data Leakage, perché lo scaler calcolerebbe media e deviazione standard sull’intero dataset prima che i fold vengano divisi.
Per lavorare in modo professionale si integra tutto in un unico flusso automatizzato:
- Isolare il Test Set: Trattenere una porzione di dati non vista per la valutazione finale. Si separa subito una quota di dati (es. 20%) che il modello non vedrà mai né durante lo scaling né durante l’ottimizzazione dei parametri.
- Definire la Pipeline: Incatenare trasformazione dei dati e modello. Si crea la struttura con uno scaler temporaneo e l’algoritmo di classificazione scelto.
- Configurare la Param Grid: Confronto dinamico tra StandardScaler e MinMaxScaler. Si definisce la griglia includendo sia i parametri del modello sia i due tipi di scaler per testarli direttamente sul campo.
- Eseguire la Cross-Validation: K-Fold sicuro e senza contaminazione dei dati. GridSearchCV applica lo scaling esclusivamente sui fold di addestramento di ogni split della Cross-Validation.
- Valutazione Finale: Misurazione dell’accuracy sul test set di riserva. Si calcolano le metriche sul test set ricalcolando la trasformazione in automatico sul modello migliore.
Il Codice Completo
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report, accuracy_score
# 1. Caricamento Dati e Split Iniziale (Holdout Test Set)
wine = load_wine()
X_train, X_test, y_train, y_test = train_test_split(
wine.data,
wine.target,
test_size=0.20,
random_state=42,
stratify=wine.target
)
# 2. Definizione della Pipeline base
# Mettiamo StandardScaler come placeholder iniziale
pipeline = Pipeline([
("scaler", StandardScaler()),
("knn", KNeighborsClassifier())
])
# 3. Griglia dei Parametri
# Protip: possiamo testare entrambi gli scaler dentro la griglia!
param_grid = {
"scaler": [StandardScaler(), MinMaxScaler()], # GridSearchCV sceglierà lo scaler migliore
"knn__n_neighbors": [3, 5, 7, 9, 11],
"knn__weights": ["uniform", "distance"],
"knn__metric": ["euclidean", "manhattan"]
}
# 4. Configurazione ed Esecuzione di GridSearchCV con Cross-Validation (5-Fold)
grid_search = GridSearchCV(
estimator=pipeline,
param_grid=param_grid,
cv=5,
scoring="accuracy",
n_jobs=-1
)
# L'addestramento gestisce automaticamente lo scaling interno per ogni fold della CV
grid_search.fit(X_train, y_train)
# 5. Risultati della Ricerca
print("=== RISULTATI OPTIMIZATION ===")
print("Migliori parametri trovati:")
for param, value in grid_search.best_params_.items():
print(f" - {param}: {value}")
print(f"\nMiglior Accuracy media in Cross-Validation: {grid_search.best_score_:.4f}")
# 6. Valutazione Finale sul Test Set
# grid_search applica automaticamente il modello migliore (già ri-addestrato) sui dati di test
y_pred = grid_search.predict(X_test)
test_accuracy = accuracy_score(y_test, y_pred)
print(f"\nAccuracy sul Test Set (dati mai visti): {test_accuracy:.4f}")
print("\nReport di Classificazione:")
print(classification_report(y_test, y_pred, target_names=wine.target_names))
=== RISULTATI OPTIMIZATION ===
Migliori parametri trovati:
- knn__metric: manhattan
- knn__n_neighbors: 9
- knn__weights: uniform
- scaler: StandardScaler()
Miglior Accuracy media in Cross-Validation: 0.9862
Accuracy sul Test Set (dati mai visti): 1.0000
Report di Classificazione:
precision recall f1-score support
class_0 1.00 1.00 1.00 12
class_1 1.00 1.00 1.00 14
class_2 1.00 1.00 1.00 10
accuracy 1.00 36
macro avg 1.00 1.00 1.00 36
weighted avg 1.00 1.00 1.00 36
Analisi dei risultati: perché la Pipeline ha scelto StandardScaler
Questo output dimostra in modo empirico l’efficacia del flusso Pipeline + GridSearchCV: la ricerca automatica non ha solo individuato gli iperparametri ideali per l’algoritmo K-NN, ma ha risolto scientificamente il dubbio iniziale selezionando StandardScaler al posto di MinMaxScaler.
1. La scelta automatica dello Scaler
scaler: StandardScaler(): Tra le due opzioni fornite nella griglia, la Cross-Validation ha stabilito che la standardizzazione ([math]z[/math]-score) produce risultati migliori rispetto alla compressione nell’intervallo [math][0, 1][/math] di MinMaxScaler. Questo accade perché le feature del dataset Wine (come concentrazione alcolica, ceneri, flavonoidi) hanno distribuzioni continue e approssimativamente gaussiane, dove la media zero e la varianza unitaria facilitano il calcolo delle distanze.
2. Gli iperparametri ottimali di K-NN
- knn__metric: manhattan: La distanza di Manhattan (L1) ha superato la classica distanza Euclidea (L2). Calcolando la somma delle differenze assolute lungo ciascun asse, la metrica Manhattan risente meno dell’accumulo dei quadrati delle differenze sulle dimensioni a valori più elevati, risultando più robusta in uno spazio a 13 feature.
- knn__n_neighbors: 9: Un valore di [math]k=9[/math] rappresenta l’equilibrio ideale per questo dataset. Valori di [math]k[/math] troppo bassi ([math]k=1[/math] o [math]3[/math]) avrebbero reso il modello sensibile al rumore nei dati, mentre un [math]k[/math] troppo alto avrebbe smussato eccessivamente i confini tra le tre classi di vino.
- knn__weights: uniform: Assegnare un peso eguale a tutti i 9 vicini (invece di pesarli in base all’inverso della distanza) è risultato sufficiente, indicando che la standardizzazione ha posizionato i punti in cluster ben definiti e compatti.
3. Cross-Validation (98.62%) vs Test Set (100.00%)
- CV Accuracy (0.9862): Rappresenta la performance media reale del modello calcolata su 5 fold distinti durante l’addestramento. È la metrica più affidabile per valutare la stabilità dell’architettura.
- Test Accuracy (1.0000): Il modello ha classificato correttamente tutti i 36 campioni del test set (dati mai visti). La lieve discrepanza con la CV è dovuta al numero contenuto di campioni nel test set ([math]N=36[/math]), ma conferma che non vi è stato overfitting e che lo scaling applicato senza data leakage ha permesso la perfetta generalizzazione del modello.
4. Bilanciamento delle Metriche nel Classification Report
- Precision, Recall ed F1-Score a 1.00: Indicano che per tutte e tre le classi (class_0, class_1, class_2) non si sono verificati né falsi positivi né falsi negativi.
- Support (12, 14, 10): Conferma che il test set era equamente distribuito tra le tre tipologie di vino, escludendo che il risultato sia stato alterato da uno sbilanciamento delle classi.
Perché questo approccio è imbattibile?
- Elimina il bias umano nella scelta dello scaler: Invece di tirare a indovinare se per il tuo dataset sia meglio StandardScaler o MinMaxScaler, lasci che sia la metrica di Cross-Validation a stabilire empiricamente quale dei due offre le prestazioni migliori.
- Previene matematicamente il Data Leakage: Quando GridSearchCV divide i dati di training in 5 fold, ad ogni iterazione calcola le statistiche dello scaler solo su 4 fold e trasforma il 5° fold (di validazione) usando quelle stesse statistiche. Effettuare uno scaling manuale prima della CV viola questa regola e genera stime di accuratezza troppo ottimistiche.
- Messa in produzione con una riga di codice: L’oggetto
grid_search.best_estimator_contiene l’intera pipeline già addestrata. Per salvarlo su disco e usarlo su un server Web o una API basta esportare quell’unico oggetto.
Esercizio svolto 3 – Visualizzare l’effetto di un outlier
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler, MinMaxScaler
df = pd.DataFrame({
"Valore": [10, 12, 13, 15, 18, 20, 1000]
})
standard = StandardScaler()
minmax = MinMaxScaler()
df["Standard"] = standard.fit_transform(df[["Valore"]])
df["MinMax"] = minmax.fit_transform(df[["Valore"]])
print(df)
plt.figure(figsize=(8, 4))
plt.plot(df["Valore"], "o-", label="Originale")
plt.plot(df["Standard"], "s-", label="StandardScaler")
plt.plot(df["MinMax"], "^-", label="MinMaxScaler")
plt.legend()
plt.title("Effetto di un outlier sulle trasformazioni")
plt.show()
Commento
Questo esercizio evidenzia uno dei limiti più importanti di MinMaxScaler. La presenza del valore estremo pari a 1000 costringe tutti gli altri dati a concentrarsi in una porzione molto ridotta dell’intervallo [math][0, 1][/math], riducendo la capacità di distinguere le osservazioni “normali”.
StandardScaler è anch’esso influenzato dall’outlier, poiché utilizza media e deviazione standard, ma la compressione risulta generalmente meno marcata. In presenza di numerosi valori anomali, una soluzione ancora migliore è rappresentata da RobustScaler, che utilizza mediana e IQR.
La trappola degli Outlier
Nella vita reale, i dataset sono sporchi e pieni di errori di battitura o anomalie (come quel “1000” in mezzo a valori da [math]10[/math] a [math]20[/math]). Dal punto di vista applicativo, questo grafico salva i data scientist da ore di debugging. Mostra che se usi MinMaxScaler su un dataset che non è stato pulito dagli outlier, annienti totalmente le informazioni utili: tutti i valori reali si appiattiscono sullo zero ([math]0.002[/math], [math]0.003[/math]…) rendendoli indistinguibili per il modello di Machine Learning. Fa capire che lo scaling non sostituisce mai una buona analisi esplorativa dei dati (EDA).
Conclusioni
Il Feature Scaling non è un dettaglio implementativo, ma una fase essenziale della pipeline di Machine Learning. Una scelta corretta tra StandardScaler e MinMaxScaler può migliorare sensibilmente accuratezza, stabilità e velocità di addestramento del modello.
In sintesi:
- StandardScaler è la scelta predefinita per la maggior parte degli algoritmi basati su distanze, prodotti scalari o ottimizzazione tramite gradienti.
- MinMaxScaler è indicato quando è necessario vincolare i dati a un intervallo fisso, come nelle reti neurali con attivazioni sigmoidi o nei dati di immagine.
- Nessuno dei due è ideale in presenza di forti outlier: in questi casi è opportuno valutare RobustScaler.
Ricorda sempre di eseguire fit() solo sul training set e transform() sul test set per evitare il data leakage.
Comprendere il motivo matematico alla base dello scaling permette di costruire pipeline di Machine Learning più robuste, interpretabili e generalizzabili, evitando errori che possono compromettere le prestazioni del modello ben prima della scelta dell’algoritmo.
📚 Data Science, Analisi dei Dati e Machine Learning con Python
Prima di costruire modelli di Machine Learning è fondamentale comprendere, pulire e trasformare correttamente i dati. Questi approfondimenti affrontano la gestione degli outlier, la riduzione della dimensionalità con PCA, la segmentazione dei clienti e gli algoritmi fondamentali di apprendimento automatico attraverso esempi pratici in Python.
👉Identificare gli outlier: guida pratica e 6 esercizi su metodo IQR e MAD
👉Outlier: cosa sono, come trovarli e rimuoverli con Pandas, IQR e Z-score
👉PCA – Analisi delle Componenti Principali: mettere ordine nel caos dei dati con Python
👉Segmentazione clienti con Python: marketing comportamentale, K-Means, PCA e t-SNE
👉Tutorial completo Scikit-Learn: guida al Machine Learning in Python per principianti
👉KNN Regressione: guida completa all’algoritmo K-Nearest Neighbors con esempi pratici in Python





