Диаграммы рассеяния в Python
Узнайте, как создавать и читать диаграммы рассеяния в Python с помощью Matplotlib и Seaborn. Корреляция, цветовое кодирование, линии регрессии и ML.
Диаграмма рассеяния размещает точку в каждой паре (x, y) набора данных. Полученное облако точек показывает, связаны ли две числовые переменные, насколько тесно и в каком направлении — что делает диаграммы рассеяния незаменимыми инструментами для разведочного анализа данных и рабочих процессов машинного обучения.
В этой главе рассматривается:
- Что показывают диаграммы рассеяния и как их читать
- Создание диаграмм рассеяния с помощью Matplotlib и Seaborn
- Настройка цветов, размеров и прозрачности
- Кодирование третьей переменной цветом или размером (пузырьковые диаграммы)
- Построение нескольких групп с легендой
- Добавление линии тренда регрессии
- Распространённые варианты использования в машинном обучении
Что показывает диаграмма рассеяния
Каждая точка представляет одно наблюдение. По горизонтальной оси откладывается одна переменная, по вертикальной — другая. Общая форма облака точек говорит о корреляции между двумя переменными.
Чтение паттерна
| Паттерн | Значение |
|---|---|
| Точки поднимаются слева направо | Положительная корреляция — при увеличении X значение Y тоже растёт |
| Точки опускаются слева направо | Отрицательная корреляция — при увеличении X значение Y убывает |
| Нет различимой формы | Нет линейной корреляции между переменными |
| Узкая плотная полоса | Сильная корреляция |
| Широкое размытое облако | Слабая корреляция |
| Точки далеко от основного облака | Выбросы — стоит изучить подробнее |
Коэффициент корреляции Пирсона r выражает этот паттерн одним числом от -1 (идеальная отрицательная) до +1 (идеальная положительная). Значение, близкое к 0, означает отсутствие линейной зависимости. Диаграммы рассеяния позволяют увидеть то, что r не может показать — например, два набора данных могут иметь одинаковый r при совершенно разных формах (см. квартет Анскомба).
Создание диаграммы рассеяния с помощью Matplotlib
plt.scatter() из Matplotlib — наиболее гибкий вариант. Установите Matplotlib, если ещё не сделали этого:
pip install matplotlib numpyБазовый пример
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()Положительный наклон в полученном облаке точек показывает, что большее количество часов учёбы коррелирует с более высокими оценками на экзамене.
Настройка цвета и размера маркеров
Три наиболее полезных параметра plt.scatter():
c— название цвета, строка в формате hex или массив значений (отображаемый через colormap)s— размер маркера в квадратных пунктах (по умолчанию 20); передаётся скаляром или массивомalpha— прозрачность от 0 (невидимый) до 1 (непрозрачный); используйте 0.4–0.7 для перекрывающихся точек
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' с linewidths=0.5 добавляет тонкую белую границу вокруг каждой точки, что облегчает различение отдельных точек при их перекрытии.
Кодирование третьей переменной цветом
Передайте массив в c, чтобы цвет каждой точки отражал третью числовую переменную. Добавьте plt.colorbar(), чтобы читатели понимали, что означают цвета:
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()Используйте перцептивно равномерные цветовые схемы — 'viridis', 'plasma', 'cividis' или 'coolwarm' — вместо 'jet' или 'rainbow', которые искажают восприятие и не подходят для людей с нарушением цветовосприятия.
Кодирование третьей переменной размером пузырька
Передайте массив в s, чтобы площадь каждого маркера была пропорциональна третьей переменной — это называется пузырьковой диаграммой:
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()Создание диаграммы рассеяния с помощью Seaborn
sns.scatterplot() из Seaborn работает напрямую с Pandas DataFrame и добавляет такие возможности, как автоматическая группировка по категориальному столбцу и встроенный параметр hue для цветового кодирования.
Сначала установите Seaborn:
pip install seaborn pandasБазовая диаграмма рассеяния на 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()Цветовое кодирование групп с помощью hue
Параметр hue автоматически назначает разный цвет каждой категории и добавляет легенду:
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 автоматически создаёт легенду. Это эквивалентно многократному вызову plt.scatter() с разными цветами.
Добавление линии регрессии с помощью sns.regplot()
sns.regplot() объединяет диаграмму рассеяния с подогнанной линией регрессии и доверительной полосой:
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()Заштрихованная область вокруг линии — это 95%-й доверительный интервал. Используйте ci=None, чтобы убрать его.
Построение нескольких групп
С помощью Matplotlib
Вызывайте plt.scatter() по одному разу для каждой группы и задавайте label= при каждом вызове:
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()Каждый вызов scatter() автоматически выбирает следующий цвет из стандартного цветового цикла Matplotlib.
С помощью Seaborn
Передайте DataFrame и используйте hue= и, при необходимости, style= для различения групп:
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' назначает каждой группе отдельную форму маркера в дополнение к цвету, что помогает читателям, печатающим графики в чёрно-белом режиме.
Диаграммы рассеяния в машинном обучении
Диаграммы рассеяния используются не только для разведочного анализа — они являются частью основного рабочего процесса машинного обучения.
1. Проверка линейных зависимостей перед регрессией
Перед обучением модели линейной регрессии постройте графики входных признаков относительно целевой переменной. Приблизительно линейное облако точек свидетельствует о том, что линейная регрессия подходит:
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()Если диаграмма рассеяния показывает кривую, а не прямую, возможно, вам потребуются полиномиальные признаки или другая модель.
2. Визуализация кластеров после K-Means
После запуска алгоритма кластеризации, например k-means, раскрасьте каждую точку по метке кластера, чтобы убедиться в разделении:
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()Хорошо разделённые облака подтверждают, что алгоритм нашёл осмысленные группировки.
3. Оценка предсказаний регрессионной модели
После обучения модели постройте график реальных значений против предсказанных. Идеальная модель даёт точки вдоль диагонали 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()Точки, случайно разбросанные вокруг диагонали (без систематического изгиба или веерообразной формы), означают, что ошибки модели несмещённые.
4. Визуализация снижения размерности (PCA / t-SNE)
После уменьшения размерности высокоразмерных данных до двух измерений с помощью PCA или t-SNE диаграмма рассеяния — это естественный способ отобразить результат. Каждая точка — одно наблюдение; цвет обозначает метку класса:
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()Кластеры, которые чётко разделяются после уменьшения размерности, свидетельствуют о том, что классы действительно различимы по исходным признакам.
Сохранение диаграмм рассеяния в файл
Используйте plt.savefig() перед plt.show() — вызов show() первым очищает фигуру:
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()Используйте dpi=300 для изображений PNG, пригодных для печати.
Когда использовать каждую библиотеку
| Ситуация | Рекомендуемый инструмент |
|---|---|
| Быстрый разовый график с массивами NumPy | matplotlib.pyplot.scatter() |
| Работа с Pandas DataFrame | seaborn.scatterplot() |
| Нужно цветовое кодирование или кодирование размером для каждой точки | matplotlib.pyplot.scatter() |
| Нужна автоматическая группировка по столбцу | seaborn.scatterplot(hue=...) |
| Нужна встроенная линия регрессии | seaborn.regplot() |
| Глубокая настройка Matplotlib | fig, ax = plt.subplots(), затем ax.scatter() |
Полное руководство по параметрам plt.scatter() в Matplotlib — включая логарифмические шкалы, аннотации, формы маркеров и сравнение scatter() с plot() — см. в главе Matplotlib Scatter Plots.
Распространённые ошибки
Переменная не определена. Каждый фрагмент кода в этой главе является самодостаточным. Если вы объединяете фрагменты, убедитесь, что x и y определены в одном скрипте перед вызовом plt.scatter().
Фигура не очищена между графиками. После plt.show() Matplotlib очищает фигуру. Если вы запускаете фрагменты в Jupyter Notebook, каждая ячейка автоматически создаёт новую фигуру. В обычном Python-скрипте вызывайте plt.figure(), чтобы начать новый график, если вам нужно несколько отдельных диаграмм.
Перекрытие точек. Когда точек очень много и они накладываются друг на друга, график выглядит как закрашенное пятно. Исправьте это с помощью alpha=0.3 для отображения плотности или переключитесь на plt.hexbin() для двумерного гистограммного биннинга.
Отсутствие цветовой шкалы. Если вы передаёте массив в c, всегда добавляйте plt.colorbar() — без него читатели не смогут расшифровать цветовую шкалу.
Связанные главы
- Matplotlib Scatter Plots — полный справочник по scatter в Matplotlib: логарифмические оси, аннотации, пузырьковые диаграммы, цвета границ, сравнение
scatter()иplot() - Linear Regression — обучение и интерпретация линейной модели в Python
- K-Means Clustering — разбиение данных на группы и визуализация с помощью диаграмм рассеяния
- Data Distribution — понимание формы ваших данных перед моделированием
- Matplotlib Histograms — визуализация распределения одной переменной
- Matplotlib Line Plots — тренды по непрерывной упорядоченной переменной
- Train / Test Split — разделение данных перед обучением и оценкой моделей