Диаграмма рассеяния (Scatter plot) представляет метод визуализации, используемый для изучения взаимосвязей между двумя числовыми переменными. Она отображает точки данных в виде отдельных маркеров на двумерной плоскости, при этом одна переменная откладывается по оси x, а другая — по оси y. Диаграммы рассеяния особенно полезны для выявления закономерностей, корреляций и потенциальных выбросов в данных. Диаграммы рассеяния могут указывать на различные виды корреляции между переменными с определенным доверительным интервалом. Корреляция может быть положительной (по мере увеличения одной переменной увеличивается и другая), отрицательной (по мере увеличения одной переменной другая уменьшается) или нулевой (отсутствие корреляции).
Диаграмма рассеяния также, как и другие типы диаграмм, строится по двум координатным осям. Причем эти оси представляют две переменные, по которым сравниваются данные.
Каждая точка или метка диаграммы представляет собой отдельную запись из набора данных, отображаемую в соответствии с ее значением по оси x (горизонтальная ось) и значением по оси y (вертикальная ось).
Иногда к диаграмме рассеяния добавляется линия наилучшего соответствия или линия регрессии (regression line)/ линия тренда (trend line), чтобы показать тренд или разброс в данных. Точки, расположенные далеко от основной группы данных, могут указывать на выбросы в данных. Кроме того, расположение точек может указывать на кластеризацию и пробелы, что может указывать на подгруппы или закономерности в данных.
Для создания диаграммы рассеяния применяется функция matplotlib.pyplot.scatter() (или ее аналог Axes.scatter()):
matplotlib.pyplot.scatter(x, y, s=None, c=None, *, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None,
linewidths=None, edgecolors=None, colorizer=None, plotnonfinite=False, data=None, **kwargs)
Основные параметры функции:
x и y: позиции данных
s: размер маркера в точках, возведенный в квадрат (типографические точки - 1/72 дюйма)
c: цвета маркера
marker: стиль маркера
alpha: значение альфа-канала, от 0 (прозрачный) до 1 (непрозрачный)
linewidths: ширина линии маркеров
Все точки представляют маркеры. Для установки стиля маркера библиотека Matplotlib предоставляет ряд встроенных значений:
значение |
описание |
|
точка |
|
пиксель |
|
кружок |
|
треугольник вниз |
|
треугольник вверх |
|
треугольник влево |
|
треугольник вправо |
|
треугольник вниз (не заполненный) |
|
треугольник вверх (не заполненный) |
|
треугольник влево (не заполненный) |
|
треугольник вправо (не заполненный) |
|
восьмиугольник |
|
квадрат |
|
пятиугольник |
|
плюс (заполненный) |
|
звезда |
|
шестиугольник |
|
шестиугольник |
|
плюс |
|
x |
|
x (заполненный) |
|
ромб |
|
тонкий ромб |
|
вертикальная линия |
|
горизонтальная линия |
|
линия слева |
|
линия справа |
|
линия сверху |
|
линия снизу |
|
каре влево |
|
каре вправо |
|
caretup |
|
каре вниз |
|
каре влево (с центрированием) |
|
каре вправо (с центрированием) |
|
каре вверх (с центрированием) |
|
каре вниз (с центрированием) |
|
маркер отсутствует |
Рассмотрим применение на случайных произвольных данных:
import matplotlib.pyplot as plt
import numpy as np
# для генерации случайных данных
np.random.seed(5)
# генерируем случайные данные для оси x
x = np.random.rand(50) * 100
# генерируем данные для оси y на основе данных для оси x с добавлением некоторого шума
y = x * 0.5 + np.random.normal(size=x.size) * 10
# для наглядности смотрим, с какими данными мы работаем
print(x)
print(y)
# определяем саму диаграмму
plt.scatter(x, y, c="blue", marker="o", alpha=0.7)
# метки к осям
plt.xlabel("Переменная X")
plt.ylabel("Переменная Y")
# добавляем заголовок
plt.title("Разброс случайных значений")
plt.show()
Здесь для генерации случайных значений используем функционал библиотеки numpy, которая автоматически устанавливается вместе с matplotlib (поэтому ее не надо отдельно устанавливать):
np.random.seed(5)
Здесь мы фиксируем "зерно" случайности. Это нужно для того, чтобы при каждом запуске программы генерировались одни и те же случайные числа (для повторяемости результата).
x = np.random.rand(50) * 100
Генерируем 50 случайных чисел в диапазоне от 0 до 100 для координат по оси X
y = x * 0.5 + np.random.normal(size=x.size) * 10
Создается набор координат для оси Y на основе X. Формула x * 0.5 задает линейную зависимость, а np.random.normal(...) добавляет "шум", чтобы точки не
лежали на одной идеальной прямой, а были разбросаны.
Затем с помощью вызова plt.scatter(...) собственно рисуем точки. Кроме координат X и Y для рисуемых точек также еще передаем несколько настроек:
c="blue": синий цвет
marker="o": форма точек (круги)
alpha=0.7": делает точки слегка прозрачными
В итоге на графике будет видна область из 50 синих точек, которые стремятся вверх и вправо. Поскольку y напрямую зависит от x (с коэффициентом 0.5), на графике будет заметен четкий положительный тренд: чем больше значение по горизонтали, тем в среднем выше значение по вертикали.
Теперь пойдем дальше и добавим на этот же график линию тренда (линейную регрессию), чтобы лучше видеть зависимость:
import matplotlib.pyplot as plt
import numpy as np
# для генерации случайных данных
np.random.seed(5)
# генерируем случайные данные для оси x
x = np.random.rand(50) * 100
# генерируем данные для оси y на основе данных для оси x с добавлением некоторого шума
y = x * 0.5 + np.random.normal(size=x.size) * 10
# определяем саму диаграмму
plt.scatter(x, y, c="blue", marker="o", alpha=0.7)
# определяем точки для линии тренда
m, b = np.polyfit(x, y, 1)
# добавляем линию тренда к графику
plt.plot(x, m*x + b, color="red")
# метки к осям
plt.xlabel("Переменная X")
plt.ylabel("Переменная Y")
# добавляем заголовок
plt.title("Разброс случайных значений")
plt.show()
По сравнению с предыдущим примером здесь добавлены две строки кода:
m, b = np.polyfit(x, y, 1)
Эта функция находит параметры прямой линии, которая проходит максимально близко ко всем точкам графика (метод наименьших квадратов). Последний аргумент - 1 - это степень полинома. Поскольку нам нужна прямая линия, мы используем единицу. В качестве результата мы получаем два значения:
m (slope) - это коэффициент наклона линии. Он показывает, как быстро растет y при изменении x.
b (intercept) - это точка пересечения с осью Y (смещение).
В математическом виде эта прямая описывается уравнением y = m * x + b
plt.plot(x, m*x + b, color="red")
Этот вызов рисует саму линию. В качестве координат по горизонтали берутся те же значения x. В качестве координат по вертикали вычисляются идеальные значения по формуле m * x + b.
А параметр color="red" делает линию красной, чтобы она контрастировала с синими точками.
В итоге сразу понятно, растет ли величина или падает. Более того, глядя на линию, можно примерно предсказать, какое значение y будет при (x=120), даже если в данных такой точки нет.
Выше мы рассмотрели базовые принципы построения диаграммы и линии тренда на примере случайных данных, теперь посмотрим на более реальном примере:
import matplotlib.pyplot as plt
import numpy as np
days = ["20.01", "21.01", "22.01", "23.01", "24.01", "27.01", "28.01", "29.01", "30.01", "31.01", "03.02", "04.02", "05.02", "06.02", "07.02"]
usd = [77.76, 77.82, 77.52, 76.03, 75.92, 76.01, 76.55, 76.27, 76.02, 75.73, 77.02, 76.98, 76.91, 76.55, 77.05]
# Используем список индексов (0, 1, 2...) для расчетов
all_indices = [index for index, _ in enumerate(days)]
# Рассчитываем коэффициенты линии тренда (m - наклон, b - смещение)
m, b = np.polyfit(all_indices, usd, 1)
# Строим диаграмму рассеяния
plt.scatter(days, usd, c="blue", marker="o", alpha=0.7, label="Курс USD")
# подставляем индексы в уравнение прямой y = mx + b
trend_line = [m * x + b for x in all_indices]
plt.plot(days, trend_line, color="red", linewidth=2, label="Линия тренда")
# Оформление
plt.xlabel("День")
plt.ylabel("Цена")
plt.title("Курс доллара с линией тренда")
plt.xticks(rotation=45) # Наклоним даты, чтобы они не слипались
plt.legend() # Добавляем легенду, чтобы было понятно, где что
plt.grid(True, linestyle="--", alpha=0.6) # Добавим сетку для наглядности
plt.tight_layout() # Автоматически подправит отступы
plt.show()
Здесь мы строим диаграмму рассеяния по дневным значениям курса доллара. Но здесь надо учитывать, что по оси X у нас размещаются строки с датами фиксации курса - список days. Однако для расчета координат точек
линии треда нам нужны не строки, а числовые значения - математические функции типа np.polyfit умеют работать только с числами. Поэтому для расчета мы используем
порядковые номера дней (список all_indices), а для отображения — те же даты.
all_indices = [index for index, _ in enumerate(days)]
Далее передаем этот список в np.polyfit:
m, b = np.polyfit(all_indices, usd, 1)
Для построения линии тренда с помощью функции plt.plot передаем days как X и вычисленные значения trend_line как Y. Matplotlib сопоставит их по порядку:
trend_line = [m * x + b for x in all_indices] plt.plot(days, trend_line, color="red", linewidth=2, label="Линия тренда")
И для улучшения вида делаем ряд действий:
plt.xticks(rotation=45), чтобы даты на оси X не накладывались друг на друга
plt.legend() - покажет подписи "Курс USD" и "Линия тренда"
plt.grid(), чтобы было легче определять значения по осям
В итоге у нас получится следующая диаграмма: