Тепловые карты и pairplot: heatmap и матрицы диаграмм
Пять строк — и весь датасет на экране: heatmap рисует корреляционную матрицу цветом, pairplot раскладывает все пары переменных в матрицу диаграмм. Разведочный анализ, который раньше занимал день, теперь занимает минуту.
Редакция Питоники
На почту упал файл: десять квартир, пять параметров — площадь, комнаты, этаж, цена, минуты до метро. Заказчик просит «понять, от чего зависит цена». Классический разведочный анализ (EDA, exploratory data analysis) — это десять диаграмм рассеяния и пара часов возни. Seaborn сжимает его до пяти строк: sns.heatmap покажет все связи чисел одной картинкой, sns.pairplot — каждым столбиком против каждым. В этом уроке собираем протокол «первый взгляд на датасет», который вы будете применять к каждой новой таблице.
Корреляционная матрица: df.corr() одной строкой
Корреляция Пирсона r — число от −1 до 1, которое меряет линейную связь двух величин: r = 1 — растут строго вместе, r = −1 — одна растёт, другая падает синхронно, r = 0 — линейной связи не видно. У pandas есть метод corr(): вызываете его на таблице — и он посчитает r для каждой пары числовых столбцов. Вот наш файл с квартирами:
import pandas as pd
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"floor": [3, 7, 2, 5, 9, 4, 1, 8, 6, 11],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
})
corr = apts.corr(numeric_only=True)
print(corr.round(2))
area rooms floor price metro_min area 1.00 0.98 -0.05 0.99 -0.50 rooms 0.98 1.00 -0.13 0.97 -0.55 floor -0.05 -0.13 1.00 -0.09 -0.18 price 0.99 0.97 -0.09 1.00 -0.43 metro_min -0.50 -0.55 -0.18 -0.43 1.00
Матрица отвечает на вопрос заказчика ещё до всяких графиков: цена почти идеально ходит за площадью (r = 0.99) и комнатами (r = 0.97), минуты до метро давят на цену в обратную сторону (r = −0.43 у пары с ценой), а этаж — посторонний (r = −0.09). Диагональ сплошных единиц — это каждый столбец с самим собой, матрица симметрична: r площади с ценой равен r цены с площадью.
Числа есть. Но 25 ячеек глазами сравнивать утомительно, а на двадцати колонках их будет четыреста. Тут и приходит тепловая карта.
heatmap: тепловая карта корреляций с аннотациями
sns.heatmap заливает каждую ячейку таблицы цветом: большие значения — одним концом палитры, малые — другим. Четыре параметра делают её читаемой: annot=True рисует сами числа в ячейках, fmt=".2f" оставляет два знака после запятой, cmap="coolwarm" берёт расходимую палитру (минус — синий, плюс — красный, ноль — белый), а vmin=−1 и vmax=1 фиксируют шкалу ровно на диапазоне корреляций.
Как построить тепловую карту в Python?
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"floor": [3, 7, 2, 5, 9, 4, 1, 8, 6, 11],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
})
corr = apts.corr(numeric_only=True)
sns.set_theme()
ax = sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm",
vmin=-1, vmax=1, square=True, linewidths=0.5)
ax.set_title("Корреляции параметров квартир")
plt.show()
График отображается под редактором
Теперь матрица читается за секунду: красный блок площадь-комнаты-цена кричит о сильной прямой связи, синяя полоска metro_min — об обратной, этаж выглядит серо-белым — связи нет. square=True держит ячейки квадратными, linewidths=0.5 разделяет их тонкими линиями. Цветовая шкала справа (colorbar) пришла автоматически — она же служит легендой.
Как выбрать cmap и зачем vmin и vmax
Палитры делятся на два семейства. Расходимые (diverging): coolwarm, RdBu_r, PiYG — с явным центром посередине; их место — корреляции и любые отклонения от нуля, потому что «ниже нуля» и «выше нуля» честно красятся в разные цвета. Последовательные (sequential): viridis, rocket, Blues — от тёмного к светлому, для величин, у которых нет отрицательных значений: население, выручка, частоты. Расходимую палитру на частотах и последовательную на корреляциях использовать можно, но читатель потратит лишние секунды на расшифровку.
vmin и vmax — это якоря шкалы. Без них Seaborn растянет палитру от минимума до максимума именно ваших данных, и две тепловые карты — до рефакторинга и после — окажутся в неравных условиях: 0.5 на одной будет ярким, на другой блёклым. Для корреляций диапазон известен заранее, −1 и 1, — фиксируйте его всегда.
Бонус-приём: срежьте у матрицы один столбец — и получите «рейтинг влияния» на целевую переменную:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"floor": [3, 7, 2, 5, 9, 4, 1, 8, 6, 11],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
})
corr = apts.corr(numeric_only=True)
sns.set_theme()
ax = sns.heatmap(corr[["price"]].drop(index="price"),
annot=True, fmt=".2f", cmap="coolwarm", vmin=-1, vmax=1)
ax.set_title("Корреляции с ценой: кто влияет")
plt.show()
График отображается под редактором
corr[["price"]] оставляет одну колонку матрицы, drop(index="price") убирает тривиальную единицу цены с самой собой. Такая вертикальная полоска — быстрый ответ на вопрос «какие признаки вообще смотреть»: площадь и комнаты — да, этаж — мимо.
На презентациях половину матрицы можно спрятать: верхний треугольник повторяет нижний зеркально. Параметр mask принимает булеву маску той же формы — там, где True, ячейка не рисуется. Собирается маска двумя numpy-функциями:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"floor": [3, 7, 2, 5, 9, 4, 1, 8, 6, 11],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
})
corr = apts.corr(numeric_only=True)
mask = np.triu(np.ones_like(corr, dtype=bool), k=1)
sns.set_theme()
ax = sns.heatmap(corr, mask=mask, annot=True, fmt=".2f",
cmap="coolwarm", vmin=-1, vmax=1, square=True,
linewidths=0.5)
ax.set_title("Корреляции: только нижний треугольник")
plt.show()
График отображается под редактором
ones_like построил решётку единиц той же формы, что и corr, np.triu превратил её в верхний треугольник, а k=1 срезал ещё и диагональ с её бессмысленными единицами. Остались десять уникальных пар — читатель не тратит взгляд на дубли.
pairplot: весь датасет на одном рисунке
Тепловая карта говорит, что связи есть, но не показывает их форму — а форма бывает коварной. sns.pairplot рисует матрицу диаграмм: по диагонали — распределение каждой переменной, вне диагонали — диаграмма рассеяния для каждой пары. Пять колонок — 25 панелей, и всё это два вызова функций:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"floor": [3, 7, 2, 5, 9, 4, 1, 8, 6, 11],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
})
sns.set_theme()
g = sns.pairplot(apts, diag_kind="kde", plot_kws={"s": 40, "alpha": 0.7})
g.figure.suptitle("Параметры квартир: матрица диаграмм", y=1.02)
plt.show()
График отображается под редактором
Читать матрицу просто: строка area, колонка price — это облако точек «площадь против цены», и оно вытянуто в линию: r = 0.99 подтверждается глазами. Диагональ мы переключили с гистограмм на kde-кривые параметром diag_kind="kde" — так форма распределения видна лучше. Верхняя половина зеркальна нижней, оси подписаны именами колонок, plot_kws передал размеры точек и прозрачность внутрь каждой панели.
Параметры pairplot, которые экономят время
- vars=["area", "price", "metro_min"] — рисовать только выбранные колонки: с 20 переменных снимает 400-панельную стену.
- hue="district" — раскрасить все панели по категориальному столбцу, легенда появится сама.
- diag_kind="kde" — на диагонали кривые плотности вместо гистограмм.
- corner=True — оставить только нижний треугольник: зеркальные пары не несут новой информации.
- plot_kws={"s": 20, "alpha": 0.4} — мелкие полупрозрачные точки против оверплоттинга на больших данных.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
"district": ["Центр", "Спальный", "Центр", "Спальный", "Центр",
"Центр", "Спальный", "Спальный", "Центр", "Спальный"],
})
sns.set_theme()
g = sns.pairplot(apts, vars=["area", "price", "metro_min"],
hue="district", diag_kind="kde", corner=True)
plt.show()
График отображается под редактором
hue сработал как в седьмом уроке про основы Seaborn: каждый scatter и каждая кривая расщепились по районам, легенда встроилась сама. Если цвет разделил облака — переменная полезна для классификации; если цвета перемешались — признаки различают группы слабо. Это уже машинное обучение на минималях, а выглядит как три строки кода.
jointplot: пара переменных крупным планом
Когда pairplot указал на интересную пару, переходите к jointplot: scatter в центре плюс гистограммы каждой переменной по краям — связь и распределения на одном рисунке. Три строки:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
})
sns.set_theme()
g = sns.jointplot(data=apts, x="area", y="price", height=4.5)
g.ax_joint.set_title("Площадь и цена: пара крупным планом")
plt.show()
График отображается под редактором
Края рассказывают то, что теряется в чистом scatter: справа — распределение площади, сверху — цены. Параметр kind меняет центральную панель: kind="hex" складывает плотность точек в шестиугольники (спасение от оверплоттинга), kind="kde" рисует уровни плотности, как изолинии на карте, kind="reg" добавляет прямую регрессии.
EDA за пять строк: протокол разведочного анализа
Соберём всё в порядок действий, который я применяю к каждой новой таблице — от файла с продажами до выгрузки из датчика:
- df.head() и df.describe() — что за колонки, какие масштабы, есть ли пропуски.
- corr = df.corr(numeric_only=True) — матрица связей числовых колонок.
- sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm", vmin=-1, vmax=1) — связи одной картинкой.
- sns.pairplot(df, vars=[3-4 самые связанные колонки], corner=True) — форма связей глазами.
- sns.jointplot для пары-чемпиона — детали с распределениями по краям.
import pandas as pd
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"rooms": [1, 2, 3, 3, 4, 5, 3, 1, 5, 2],
"floor": [3, 7, 2, 5, 9, 4, 1, 8, 6, 11],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
"metro_min": [14, 9, 21, 16, 7, 8, 24, 19, 5, 23],
})
target = apts.corr(numeric_only=True)["price"].round(2).sort_values()
print(target)
metro_min -0.43 floor -0.09 rooms 0.97 area 0.99 price 1.00 Name: price, dtype: float64
Отсортированный столбец corr()["price"] — готовый шорт-лист для модели и для отчёта: цена держится на площади и комнатах, метро тянет вниз слабо, этаж не влияет вообще. Пять строк, а заказчик уже получил черновой ответ на свой вопрос.
Корреляция не причинность: как heatmap помогает врать
Красная ячейка r = 0.99 так и провоцирует вывод «площадь влияет на цену». Иногда так и есть. Но корреляция фиксирует только синхронность: обе величины могут быть следствием третьей (комнаты растут с площадью — и обе с ценой), совпасть случайно на короткой выборке или искажаться выбросом. Самое опасное — r, посчитанный по грязным данным:
import pandas as pd
apts = pd.DataFrame({
"area": [28, 42, 55, 60, 75, 88, 64, 35, 96, 51],
"price": [8.5, 11.0, 15.5, 14.0, 19.5, 23.0, 18.0, 9.5, 24.0, 14.5],
})
print(apts["area"].corr(apts["price"]).round(2))
apts.loc[8, "price"] = 52.0 # выброс: срочная продажа элитного пентхауса
print(apts["area"].corr(apts["price"]).round(2))
0.99 0.83
Одна ячейка таблицы — и корреляция просела на 16 сотых, а на маленькой выборке она бы рухнула куда сильнее. Обратная ловушка: у нелинейных связей r бывает равен нулю при очевидной зависимости — парабола U-формы симметрична, и линейная корреляция её не видит. Для монотонных, но нелинейных связей берите method="spearman": df.corr(method="spearman") меряет не прямую линию, а согласованность рангов — «растут ли величины вместе, пусть и с разной скоростью». И не забывайте про третью переменную: классика учебников — продажи мороженого и число утоплений ходят в паре с r около 0.7, но топит не мороженое, а жара, которая гонит людей и в воду, и за мороженым.
Поэтому протокол и заканчивается pairplot, а не heatmap: числа показывают силу, глаза — форму. Если ячейка красная, а облако точек — хаос, верьте облаку; если ячейка серая, а облако выгнулось дугой — у вас нелинейная связь, и r её спрятал.
Корреляция — это две величины, танцующие в паре. Причинность — когда один ведёт. По матрице видно только танец.
Что дальше
Арсенал разведочного анализа собран: распределения показывают каждую переменную, heatmap и pairplot — связи между ними. Осталось собрать всё в презентабельную форму: в десятом, финальном уроке строим дашборд 2×2 по данным о фильмах — четыре панели, suptitle, чек-лист «график готов к показу заказчику». Пришли из поиска за одной heatmap? Полный маршрут из десяти уроков — самоучитель Matplotlib, и связи между переменными здесь девятая ступень. Возьмите с этого урока привычку: любая новая таблица сначала проходит пять строк EDA, потом обсуждаются выводы. Цветная матрица экономит часы споров — там, где вчера спорили на ощупь, теперь красная ячейка.
Сначала предскажи ответ в голове — это главный навык программиста.
import pandas as pd
df = pd.DataFrame({"x": [1, 2, 3, 4], "y": [10, 20, 30, 40]})
print(round(df["x"].corr(df["y"]), 2))
import pandas as pd
import seaborn as sns
df = pd.DataFrame({"a": [1, 2, 3, 4], "b": [2, 4, 5, 9], "c": [3, 1, 4, 2]})
g = sns.pairplot(df, vars=["a", "b"])
print(g.axes.shape)
1. Что рисуется на диагонали матрицы pairplot?
2. Корреляция r = −0.9 между минутами до метро и ценой. Что это значит?
3. Зачем в heatmap корреляций указывать vmin=-1 и vmax=1?
4. Что делает параметр annot=True в sns.heatmap?
5. Сколько панелей рисует sns.pairplot(df, vars=["a", "b", "c", "d"])?
В редакторе — таблица квартир: area (метры), rooms, price (млн руб.), metro_min (минуты до метро). Постройте тепловую карту корреляций: corr = df.corr(numeric_only=True), затем heatmap с annot=True, fmt=".2f", cmap="coolwarm", vmin=-1, vmax=1, заголовком «Корреляции параметров квартир» и square=True. По карте ответьте: какой параметр сильнее всех связан с ценой?
Что показывает тепловая карта (heatmap) в Seaborn?
Таблицу, где каждая ячейка окрашена по значению: чем «горячее» цвет, тем больше число. Чаще всего её строят по корреляционной матрице, но подойдёт любая двумерная таблица — продажи по месяцам и регионам, посещаемость по дням недели и часам.
Как построить heatmap по корреляционной матрице pandas?
Две строки: corr = df.corr(numeric_only=True) и sns.heatmap(corr, annot=True, fmt=".2f", cmap="coolwarm", vmin=-1, vmax=1). Аннотации показывают числа, шкала от −1 до 1 делает картинку сравнимой с другими графиками.
Что показывает pairplot в Seaborn?
Матрицу диаграмм: на диагонали — распределение каждой переменной, вне диагонали — диаграммы рассеяния всех пар. Это способ за один взгляд увидеть форму всех связей в датасете; на широких таблицах сужайте набор параметром vars=.
Что означает отрицательная корреляция и может ли r быть равен нулю?
Отрицательный r — обратная связь: одна величина растёт, другая падает (минуты до метро и цена). r = 0 означает отсутствие именно линейной связи — нелинейные зависимости вроде параболы корреляция Пирсона может не заметить, поэтому матрицу дополняют pairplot.
Когда использовать method="spearman" вместо Пирсона в pandas?
Пирсон меряет прямую линию, Спирман — согласованность рангов. Если связь монотонная, но не по прямой (растут вместе, но с разной скоростью), передайте df.corr(method="spearman"): параболу U-формы Пирсон может оценить нулём, а ранги её увидят. Матрицу всё равно дополняйте pairplot: если ячейка красная, а облако точек — хаос, верьте облаку.
Понравился урок? Сошлитесь на него
«Корреляция — это две величины, танцующие в паре. Причинность — когда один ведёт. По матрице видно только танец.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что читать дальше
Matplotlib / Seaborn · Урок 8
Распределения в Seaborn: histplot, boxplot и violinplot
Boxplot отвечает на вопрос «где медиана, каков разброс и кто выбивается» быстрее любой таблицы. Разбираем histplot с kde, ящик с усами и violinplot на ценах квартир — и учимся сравнивать группы через hue.
Matplotlib / Seaborn · Урок 4
Диаграммы рассеяния scatter: ищем связи между величинами
scatter для поиска связей между величинами: форма облака точек, цвет и размер как третье измерение, alpha против оверплоттинга и кейс с 300 измерениями.
Matplotlib / Seaborn · Урок 10
Проект по визуализации: дашборд данных о фильмах на Matplotlib и Seaborn
Финальный проект курса: датасет из 200 фильмов, EDA, дашборд 2x2 с трендом, жанрами, гистограммой и scatter — плюс чек-лист «график готов к показу» и итоги десяти уроков.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Pandas · Урок 1
Что такое Pandas и как установить через pip: первые Series и DataFrame
Первая таблица DataFrame в библиотеке pandas, умный столбец Series и быстрый осмотр данных через head, info и describe — старт сквозного анализа данных интернет-магазина.
pandas для начинающихpandas python
Pandas · Урок 10
Проект на Pandas: полный анализ продаж интернет-магазина
Финальный проект раздела: сырая выгрузка заказов, чистка по чек-листу, выручка и средний чек, топ-товары, сводные по городам, тренд по месяцам и выводы для руководителя.
проект pandasанализ данных python pandas
Matplotlib / Seaborn · Урок 7
Seaborn для начинающих: красивые графики одной строкой
Seaborn рисует статистические графики из DataFrame одной строкой: темы set_theme, countplot, barplot с доверительными интервалами и разбивка hue — прямо в браузере.
seabornseaborn для начинающих
Проверьте знания по Matplotlib / Seaborn
В челлендже — 20 задач по Matplotlib / Seaborn, по 2 из каждого урока этого раздела. Формат: фрагмент кода и четыре варианта — что напечатает. После ответа — вердикт и объяснение со ссылкой на урок-источник.
Тест по Matplotlib / Seaborn: 20 задач