W3docs

Capire i Grafici a Dispersione in Python

Crea e interpreta grafici a dispersione in Python con Matplotlib e Seaborn. Correlazione, codifica colori, linee di regressione e usi nel ML.

Un grafico a dispersione posiziona un punto per ogni coppia (x, y) in un dataset. La nuvola di punti risultante rivela se due variabili numeriche sono correlate, quanto strettamente e in quale direzione — rendendo i grafici a dispersione indispensabili per l'analisi esplorativa dei dati e i flussi di lavoro di machine learning.

Questo capitolo tratta:

  • Cosa mostrano i grafici a dispersione e come leggerli
  • Creare grafici a dispersione con Matplotlib e Seaborn
  • Personalizzare colori, dimensioni e trasparenza
  • Codificare una terza variabile con colore o dimensione (bubble chart)
  • Tracciare più gruppi con una legenda
  • Aggiungere una linea di tendenza di regressione
  • Casi d'uso comuni nel machine learning

Cosa Mostra un Grafico a Dispersione

Ogni punto rappresenta un'osservazione. L'asse orizzontale contiene una variabile, l'asse verticale ne contiene un'altra. La forma complessiva della nuvola indica la correlazione tra le due variabili.

Leggere il Pattern

PatternSignificato
I punti salgono da sinistra a destraCorrelazione positiva — all'aumentare di X, Y tende ad aumentare
I punti scendono da sinistra a destraCorrelazione negativa — all'aumentare di X, Y tende a diminuire
Nessuna forma riconoscibileNessuna correlazione lineare tra le variabili
Banda stretta e compattaCorrelazione forte
Nuvola ampia e diffusaCorrelazione debole
Punti lontani dalla nuvola principaleOutlier — vale la pena indagarli

Il coefficiente di correlazione di Pearson r riassume questo pattern in un singolo numero da -1 (perfettamente negativo) a +1 (perfettamente positivo). Un valore vicino a 0 indica nessuna relazione lineare. I grafici a dispersione ti permettono di vedere ciò che r non può dirti — ad esempio, due dataset possono condividere lo stesso r pur avendo forme completamente diverse (vedi il quartetto di Anscombe).

Creare un Grafico a Dispersione con Matplotlib

plt.scatter() di Matplotlib è l'opzione più flessibile. Installa Matplotlib se non lo hai già fatto:

pip install matplotlib numpy

Esempio Base

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=42)

# Simulate hours studied vs exam score
hours = rng.uniform(1, 10, 40)
score = 5 * hours + rng.normal(scale=8, size=40)

plt.scatter(hours, score)
plt.xlabel('Hours Studied')
plt.ylabel('Exam Score')
plt.title('Hours Studied vs Exam Score')
plt.tight_layout()
plt.show()

La pendenza positiva nella nuvola risultante mostra che un maggior numero di ore di studio è correlato a punteggi d'esame più alti.

Personalizzare il Colore e la Dimensione dei Marker

I tre parametri più utili di plt.scatter() sono:

  • c — nome del colore, stringa esadecimale, o array di valori (mappati tramite una colormap)
  • s — dimensione del marker in punti quadrati (default 20); passa uno scalare o un array
  • alpha — trasparenza da 0 (invisibile) a 1 (solido); usa 0.4–0.7 per punti sovrapposti
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=7)

x = rng.normal(loc=5, scale=2, size=60)
y = rng.normal(loc=5, scale=2, size=60)

plt.scatter(x, y, c='steelblue', s=80, alpha=0.6, edgecolors='white', linewidths=0.5)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Customized Scatter Plot')
plt.tight_layout()
plt.show()

edgecolors='white' con linewidths=0.5 aggiunge un sottile bordo bianco attorno a ogni punto, rendendo più facile distinguere i singoli punti quando si sovrappongono.

Codificare una Terza Variabile con il Colore

Passa un array a c per colorare ogni punto in base a una terza variabile numerica. Aggiungi plt.colorbar() affinché i lettori sappiano cosa rappresentano i colori:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=3)

x = rng.random(50)
y = rng.random(50)
temperature = rng.uniform(15, 35, 50)   # third variable, e.g. temperature in °C

scatter = plt.scatter(x, y, c=temperature, cmap='coolwarm', s=80, alpha=0.8)
plt.colorbar(scatter, label='Temperature (°C)')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.title('Sensor Readings by Temperature')
plt.tight_layout()
plt.show()

Usa colormap percettivamente uniformi — 'viridis', 'plasma', 'cividis' o 'coolwarm' — anziché 'jet' o 'rainbow', che distorcono la percezione e non sono adatte ai daltonici.

Codificare una Terza Variabile con la Dimensione delle Bolle

Passa un array a s per rendere l'area di ogni marker proporzionale a una terza variabile — questo si chiama bubble chart:

import matplotlib.pyplot as plt
import numpy as np

countries = ['USA', 'China', 'Japan', 'Germany', 'UK']
gdp       = [25.5, 18.0, 4.2, 4.1, 3.1]          # trillion USD
life_exp  = [76.4, 77.1, 84.3, 80.6, 81.3]        # years
population = [334, 1412, 125, 84, 67]             # millions — encoded as size

# Scale population to a visible marker area range
sizes = [p * 1.5 for p in population]

plt.scatter(gdp, life_exp, s=sizes, alpha=0.6, edgecolors='black', linewidths=0.8)

for i, name in enumerate(countries):
    plt.annotate(name, (gdp[i], life_exp[i]), textcoords='offset points',
                 xytext=(6, 4), fontsize=9)

plt.xlabel('GDP (trillion USD)')
plt.ylabel('Life Expectancy (years)')
plt.title('GDP vs Life Expectancy (bubble size = population)')
plt.tight_layout()
plt.show()

Creare un Grafico a Dispersione con Seaborn

sns.scatterplot() di Seaborn funziona direttamente con i DataFrame di Pandas e aggiunge funzionalità come il raggruppamento automatico per colonna categoriale e un parametro hue integrato per la codifica a colori.

Installa Seaborn prima:

pip install seaborn pandas

Grafico a Dispersione Base con Seaborn

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

data = pd.DataFrame({
    'hours':  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'score':  [45, 50, 55, 60, 65, 70, 72, 80, 85, 92],
})

sns.scatterplot(data=data, x='hours', y='score')
plt.xlabel('Hours Studied')
plt.ylabel('Exam Score')
plt.title('Hours Studied vs Exam Score')
plt.tight_layout()
plt.show()

Codifica dei Gruppi con i Colori tramite hue

Il parametro hue assegna automaticamente un colore diverso a ogni categoria e aggiunge una legenda:

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt

data = pd.DataFrame({
    'sepal_length': [5.1, 4.9, 6.3, 5.8, 7.0, 6.4, 6.3, 5.8, 7.1, 6.3],
    'sepal_width':  [3.5, 3.0, 2.9, 2.7, 3.2, 3.2, 3.3, 2.7, 3.0, 2.9],
    'species':      ['setosa', 'setosa', 'versicolor', 'versicolor',
                     'virginica', 'virginica', 'virginica', 'versicolor',
                     'virginica', 'virginica'],
})

sns.scatterplot(data=data, x='sepal_length', y='sepal_width', hue='species')
plt.title('Iris: Sepal Length vs Sepal Width')
plt.tight_layout()
plt.show()

Seaborn crea automaticamente la legenda. Questo equivale a chiamare plt.scatter() più volte con colori diversi.

Aggiungere una Linea di Regressione con sns.regplot()

sns.regplot() combina un grafico a dispersione con una linea di regressione adattata e una banda di confidenza:

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=10)
x = np.linspace(1, 10, 30)
y = 3 * x + rng.normal(scale=4, size=30)

data = pd.DataFrame({'x': x, 'y': y})

sns.regplot(data=data, x='x', y='y', scatter_kws={'alpha': 0.6}, line_kws={'color': 'red'})
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Scatter Plot with Regression Line')
plt.tight_layout()
plt.show()

L'area ombreggiata attorno alla linea è un intervallo di confidenza al 95%. Usa ci=None per rimuoverla.

Tracciare Più Gruppi

Con Matplotlib

Chiama plt.scatter() una volta per gruppo e imposta label= su ogni chiamata:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=0)

groups = {
    'Group A': (2, 3),
    'Group B': (6, 6),
    'Group C': (9, 2),
}

for name, (cx, cy) in groups.items():
    x = rng.normal(loc=cx, scale=0.6, size=30)
    y = rng.normal(loc=cy, scale=0.6, size=30)
    plt.scatter(x, y, s=50, alpha=0.7, label=name)

plt.legend()
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Three Distinct Clusters')
plt.tight_layout()
plt.show()

Ogni chiamata a scatter() sceglie automaticamente il colore successivo dal ciclo di colori predefinito di Matplotlib.

Con Seaborn

Passa un DataFrame e usa hue= e facoltativamente style= per distinguere i gruppi:

import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=1)

rows = []
for group, (cx, cy) in [('A', (2, 3)), ('B', (6, 6)), ('C', (9, 2))]:
    for _ in range(25):
        rows.append({'x': rng.normal(cx, 0.6), 'y': rng.normal(cy, 0.6), 'group': group})

df = pd.DataFrame(rows)

sns.scatterplot(data=df, x='x', y='y', hue='group', style='group')
plt.title('Three Clusters — Seaborn Multi-Group')
plt.tight_layout()
plt.show()

style='group' assegna una forma di marker distinta a ogni gruppo in aggiunta al colore, utile per i lettori che stampano in bianco e nero.

Grafici a Dispersione nel Machine Learning

I grafici a dispersione non servono solo per l'esplorazione — fanno parte del flusso di lavoro ML fondamentale.

1. Verificare le Relazioni Lineari Prima della Regressione

Prima di addestrare un modello di regressione lineare, traccia le feature di input rispetto al target. Una dispersione approssimativamente lineare indica che la regressione lineare è appropriata:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=5)
house_size  = rng.uniform(50, 300, 60)            # square metres
house_price = 2000 * house_size + rng.normal(scale=40000, size=60)  # EUR

plt.scatter(house_size, house_price, alpha=0.6, s=50)
plt.xlabel('House Size (m²)')
plt.ylabel('Price (EUR)')
plt.title('House Size vs Price — linear pattern suggests linear regression')
plt.tight_layout()
plt.show()

Se la dispersione mostra una curva anziché una linea, potresti aver bisogno di feature polinomiali o di un modello diverso.

2. Visualizzare i Cluster Dopo il K-Means

Dopo aver eseguito un algoritmo di clustering come il k-means, colora ogni punto in base alla sua etichetta di cluster per confermare la separazione:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=8)

# Simulate cluster assignments from k-means
centers = [(1, 1), (5, 5), (9, 1)]
X, labels = [], []
for i, (cx, cy) in enumerate(centers):
    X.extend(zip(rng.normal(cx, 0.7, 30), rng.normal(cy, 0.7, 30)))
    labels.extend([i] * 30)

X = np.array(X)
labels = np.array(labels)

colors = ['tab:blue', 'tab:orange', 'tab:green']
for k in range(3):
    mask = labels == k
    plt.scatter(X[mask, 0], X[mask, 1], c=colors[k], s=50, alpha=0.7, label=f'Cluster {k}')

plt.legend()
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.title('K-Means Cluster Assignments')
plt.tight_layout()
plt.show()

Nuvole ben separate confermano che l'algoritmo ha trovato raggruppamenti significativi.

3. Valutare le Previsioni del Modello di Regressione

Traccia i valori effettivi vs previsti dopo aver addestrato un modello. Un modello perfetto produce punti lungo la diagonale y = x:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=2)

# Simulate actual and predicted values from a trained model
actual    = rng.uniform(10, 100, 50)
predicted = actual + rng.normal(scale=8, size=50)   # model with some noise

plt.scatter(actual, predicted, alpha=0.6, s=60, edgecolors='black', linewidths=0.5)
# Draw the ideal y = x line
lim = [min(actual.min(), predicted.min()) - 5, max(actual.max(), predicted.max()) + 5]
plt.plot(lim, lim, 'r--', linewidth=1.5, label='Perfect prediction')
plt.xlim(lim)
plt.ylim(lim)
plt.xlabel('Actual Values')
plt.ylabel('Predicted Values')
plt.title('Actual vs Predicted — regression model evaluation')
plt.legend()
plt.tight_layout()
plt.show()

Punti distribuiti casualmente attorno alla diagonale (senza forma ad arco o a ventaglio sistematica) indicano che gli errori del modello sono non distorti.

4. Visualizzare la Riduzione della Dimensionalità (PCA / t-SNE)

Dopo aver ridotto dati ad alta dimensionalità a due dimensioni con PCA o t-SNE, un grafico a dispersione è il modo naturale per visualizzare il risultato. Ogni punto è un'osservazione; il colore indica la sua etichetta di classe:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=20)

# Simulate 2-D PCA output for three classes
class_data = {
    'Class 0': ((-3, 0), 0.8),
    'Class 1': ((0, 3), 0.8),
    'Class 2': ((3, 0), 0.8),
}

for label, ((cx, cy), spread) in class_data.items():
    x = rng.normal(cx, spread, 40)
    y = rng.normal(cy, spread, 40)
    plt.scatter(x, y, s=30, alpha=0.7, label=label)

plt.legend()
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.title('PCA Projection — 2D visualization of high-dimensional data')
plt.tight_layout()
plt.show()

Cluster che si separano nettamente dopo la riduzione suggeriscono che le classi sono genuinamente distinguibili dalle feature originali.

Salvare i Grafici a Dispersione su File

Usa plt.savefig() prima di plt.show() — chiamare show() prima cancella la figura:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(seed=99)
x = rng.random(50)
y = rng.random(50)

plt.scatter(x, y, alpha=0.7, s=60)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Scatter Plot')
plt.tight_layout()

plt.savefig('scatter.png', dpi=150)    # raster — good for web
plt.savefig('scatter.pdf')              # vector — best for publications
plt.show()

Usa dpi=300 per immagini PNG di qualità da stampa.

Quando Usare Ciascuna Libreria

SituazioneStrumento consigliato
Grafico rapido una tantum con array NumPymatplotlib.pyplot.scatter()
Lavoro con DataFrame Pandasseaborn.scatterplot()
Codifica colore o dimensione per puntomatplotlib.pyplot.scatter()
Raggruppamento automatico per colonnaseaborn.scatterplot(hue=...)
Linea di regressione integrataseaborn.regplot()
Personalizzazione avanzata di Matplotlibfig, ax = plt.subplots() poi ax.scatter()

Per un approfondimento completo dei parametri di scatter plot di Matplotlib — incluse scale logaritmiche, annotazioni, forme dei marker e confronti tra scatter() e plot() — vedi il capitolo Matplotlib Scatter Plots.

Errori Comuni

Variabile non definita. Ogni frammento di codice in questo capitolo è autonomo. Se combini più frammenti, assicurati che x e y siano definiti nello stesso script prima di chiamare plt.scatter().

Figura non azzerata tra i grafici. Dopo plt.show(), Matplotlib azzera la figura. Se esegui frammenti in un notebook Jupyter, ogni cella crea automaticamente una nuova figura. In uno script Python normale, chiama plt.figure() per iniziare un nuovo grafico se vuoi più chart separati.

Sovrapposizione dei punti. Con molti punti tutti sovrapposti, il grafico appare come un blob riempito. Risolvi il problema con alpha=0.3 per mostrare la densità, oppure passa a plt.hexbin() per il binning istogramma 2D.

Nessuna colorbar. Se passi un array a c, aggiungi sempre plt.colorbar() — senza di essa i lettori non possono decodificare la scala dei colori.

Capitoli Correlati

Was this page helpful?