Entendendo o Gráfico de Dispersão em Python
Aprenda a criar e interpretar gráficos de dispersão em Python com Matplotlib e Seaborn. Inclui correlação, codificação por cor, linhas de regressão e usos em ML.
Um gráfico de dispersão posiciona um ponto em cada par (x, y) de um conjunto de dados. A nuvem de pontos resultante revela se duas variáveis numéricas estão relacionadas, com que intensidade e em qual direção — tornando os gráficos de dispersão indispensáveis para análise exploratória de dados e fluxos de trabalho de machine learning.
Este capítulo abrange:
- O que os gráficos de dispersão mostram e como interpretá-los
- Criação de gráficos de dispersão com Matplotlib e Seaborn
- Personalização de cores, tamanhos e transparência
- Codificação de uma terceira variável com cor ou tamanho (gráficos de bolhas)
- Plotagem de múltiplos grupos com legenda
- Adição de uma linha de tendência por regressão
- Casos de uso comuns em machine learning
O Que um Gráfico de Dispersão Mostra
Cada ponto representa uma observação. O eixo horizontal contém uma variável, o eixo vertical contém outra. A forma geral da nuvem revela a correlação entre as duas variáveis.
Lendo o Padrão
| Padrão | Significado |
|---|---|
| Pontos sobem da esquerda para a direita | Correlação positiva — conforme X aumenta, Y tende a aumentar |
| Pontos caem da esquerda para a direita | Correlação negativa — conforme X aumenta, Y tende a diminuir |
| Nenhuma forma discernível | Nenhuma correlação linear entre as variáveis |
| Faixa estreita e compacta | Correlação forte |
| Nuvem ampla e difusa | Correlação fraca |
| Pontos distantes da nuvem principal | Outliers — vale a pena investigar |
O coeficiente de correlação de Pearson r resume esse padrão em um único número de -1 (perfeita negativa) a +1 (perfeita positiva). Um valor próximo de 0 significa ausência de relação linear. Os gráficos de dispersão permitem ver o que r não consegue revelar — por exemplo, dois conjuntos de dados podem compartilhar o mesmo r com formas completamente diferentes (veja o quarteto de Anscombe).
Criando um Gráfico de Dispersão com Matplotlib
O plt.scatter() do Matplotlib é a opção mais flexível. Instale o Matplotlib se ainda não o fez:
pip install matplotlib numpyExemplo Básico
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()A inclinação positiva na nuvem resultante mostra que mais horas de estudo se correlacionam com notas mais altas.
Personalizando a Cor e o Tamanho do Marcador
Os três parâmetros mais úteis do plt.scatter() são:
c— nome de cor, string hexadecimal ou array de valores (mapeado por um colormap)s— tamanho do marcador em pontos ao quadrado (padrão 20); aceita um escalar ou arrayalpha— transparência de 0 (invisível) a 1 (sólido); use 0.4–0.7 para pontos sobrepostos
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' com linewidths=0.5 adiciona uma borda branca fina ao redor de cada ponto, facilitando a distinção individual quando se sobrepõem.
Codificando uma Terceira Variável com Cor
Passe um array para c para colorir cada ponto por uma terceira variável numérica. Adicione plt.colorbar() para que os leitores saibam o que as cores representam:
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()Use colormaps perceptualmente uniformes — 'viridis', 'plasma', 'cividis' ou 'coolwarm' — em vez de 'jet' ou 'rainbow', que distorcem a percepção e não são amigáveis para pessoas com daltonismo.
Codificando uma Terceira Variável com Tamanho de Bolha
Passe um array para s para tornar a área de cada marcador proporcional a uma terceira variável — isso é chamado de gráfico de bolhas:
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()Criando um Gráfico de Dispersão com Seaborn
O sns.scatterplot() do Seaborn trabalha diretamente com DataFrames do Pandas e adiciona recursos como agrupamento automático por uma coluna categórica e um parâmetro hue integrado para codificação por cor.
Instale o Seaborn primeiro:
pip install seaborn pandasGráfico de Dispersão Básico com 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()Codificando Grupos por Cor com hue
O parâmetro hue atribui automaticamente uma cor diferente a cada categoria e adiciona uma 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()O Seaborn cria a legenda automaticamente. Isso equivale a chamar plt.scatter() várias vezes com cores diferentes.
Adicionando uma Linha de Regressão com sns.regplot()
sns.regplot() combina um gráfico de dispersão com uma linha de regressão ajustada e uma banda de confiança:
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()A área sombreada ao redor da linha é um intervalo de confiança de 95%. Use ci=None para removê-lo.
Plotando Múltiplos Grupos
Com Matplotlib
Chame plt.scatter() uma vez por grupo e defina label= em cada chamada:
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()Cada chamada a scatter() seleciona automaticamente a próxima cor do ciclo de cores padrão do Matplotlib.
Com Seaborn
Passe um DataFrame e use hue= e, opcionalmente, style= para distinguir grupos:
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' atribui uma forma de marcador distinta a cada grupo além da cor, o que ajuda leitores que imprimem em preto e branco.
Gráficos de Dispersão em Machine Learning
Os gráficos de dispersão não servem apenas para exploração — eles fazem parte do fluxo de trabalho central de ML.
1. Verificando Relações Lineares Antes da Regressão
Antes de treinar um modelo de regressão linear, plote as variáveis de entrada em relação ao alvo. Uma dispersão aproximadamente linear indica que a regressão linear é adequada:
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 a dispersão mostrar uma curva em vez de uma linha reta, pode ser necessário usar features polinomiais ou um modelo diferente.
2. Visualizando Clusters Após K-Means
Após executar um algoritmo de clusterização como o k-means, colora cada ponto pelo rótulo do cluster para confirmar a separação:
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()Nuvens bem separadas confirmam que o algoritmo encontrou agrupamentos significativos.
3. Avaliando Previsões de Modelos de Regressão
Plote os valores reais vs previstos após treinar um modelo. Um modelo perfeito produz pontos ao longo da diagonal 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()Pontos distribuídos aleatoriamente ao redor da diagonal (sem curvatura ou forma de leque sistemática) indicam que os erros do modelo são não-viesados.
4. Visualizando a Redução de Dimensionalidade (PCA / t-SNE)
Após reduzir dados de alta dimensionalidade para duas dimensões com PCA ou t-SNE, um gráfico de dispersão é a forma natural de exibir o resultado. Cada ponto é uma observação; a cor indica seu rótulo de 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()Clusters que se separam claramente após a redução sugerem que as classes são genuinamente distinguíveis pelas features originais.
Salvando Gráficos de Dispersão em Arquivo
Use plt.savefig() antes de plt.show() — chamar show() primeiro limpa a 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()Use dpi=300 para imagens PNG com qualidade de impressão.
Quando Usar Cada Biblioteca
| Situação | Ferramenta recomendada |
|---|---|
| Gráfico rápido com arrays NumPy | matplotlib.pyplot.scatter() |
| Trabalhando com DataFrames do Pandas | seaborn.scatterplot() |
| Precisa de codificação de cor ou tamanho por ponto | matplotlib.pyplot.scatter() |
| Quer agrupamento automático por coluna | seaborn.scatterplot(hue=...) |
| Quer uma linha de regressão integrada | seaborn.regplot() |
| Personalização avançada do Matplotlib | fig, ax = plt.subplots() e depois ax.scatter() |
Para um mergulho completo nos parâmetros do gráfico de dispersão do Matplotlib — incluindo escalas logarítmicas, anotações, formas de marcador e comparações entre scatter() e plot() — veja o capítulo Gráficos de Dispersão com Matplotlib.
Erros Comuns
Variável não definida. Cada trecho de código neste capítulo é autocontido. Se você combinar trechos, certifique-se de que x e y estejam definidos no mesmo script antes de chamar plt.scatter().
Figura não limpa entre os gráficos. Após plt.show(), o Matplotlib limpa a figura. Se você estiver executando trechos em um notebook Jupyter, cada célula cria uma nova figura automaticamente. Em um script Python simples, chame plt.figure() para iniciar um novo gráfico quando quiser múltiplos gráficos separados.
Sobreplotagem. Com muitos pontos empilhados uns sobre os outros, o gráfico parece um blob preenchido. Corrija com alpha=0.3 para mostrar a densidade, ou troque para plt.hexbin() para agrupamento em histograma 2D.
Sem barra de cores. Se você passar um array para c, sempre adicione plt.colorbar() — sem ela, os leitores não conseguem decodificar a escala de cores.
Capítulos Relacionados
- Gráficos de Dispersão com Matplotlib — referência completa de dispersão no Matplotlib: eixos logarítmicos, anotações, gráficos de bolhas, cores de borda,
scatter()vsplot() - Regressão Linear — ajuste e interprete um modelo linear em Python
- Clusterização K-Means — particione dados em grupos e visualize com gráficos de dispersão
- Distribuição de Dados — entenda a forma dos seus dados antes de modelar
- Histogramas com Matplotlib — visualize a distribuição de uma única variável
- Gráficos de Linha com Matplotlib — tendências ao longo de uma variável ordenada contínua
- Divisão Treino / Teste — divida os dados antes de treinar e avaliar modelos