2025, Nov 03 00:02
Как построить черно-белую матрицу ошибок в matplotlib для ConfusionMatrixDisplay
Как в scikit-learn получить черно-белую матрицу ошибок: бинарная палитра, единичная маска и читаемые числа для ConfusionMatrixDisplay в matplotlib без цвета
ConfusionMatrixDisplay в scikit-learn удобен для быстрой визуализации, но его стандартная цветовая карта непрерывная и «цветная». Если вам нужен строго черно-белый вид, где диагональные ячейки черные, а недиагональные — белые, готовый график этого не обеспечит. Ниже — точный способ получить бинарное представление матрицы ошибок в matplotlib, не жертвуя читаемостью чисел.
Базовый код, который создает цветную картинку по умолчанию
Обычно используют такой фрагмент — он строит цветовую тепловую карту:
from sklearn.metrics import ConfusionMatrixDisplay as CMDisplay
import matplotlib.pyplot as plt
mx = cm # ваша матрица ошибок
viewer = CMDisplay(confusion_matrix=mx)
viewer.plot()
plt.show()
Что происходит и почему цвета не соответствуют требованию
Стандартный ConfusionMatrixDisplay применяет цветовую карту с непрерывным кодированием значений. Для градиентов это полезно, но к жесткой двухцветной схеме не подходит. Чтобы «пришить» диагональ к черному, а все остальное — к белому, требуется дискретная бинарная палитра и матрица, задающая, где применять черный и белый. Проще всего закодировать такой шаблон единичной матрицей того же размера, что и матрица ошибок: единицы на диагонали и нули вне ее.
Решение: бинарная палитра + единичная маска
Создайте собственный ListedColormap из двух цветов и передайте imshow маску, выровненную с вашей матрицей ошибок. Затем нанесите числовые значения поверх, меняя цвет текста так, чтобы он оставался читаемым на любом фоне.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap as LMap
# пример данных
data_mx = np.array([[12, 1],
[ 2,10]])
def render_bw_confusion(mtx, names=None):
palette = LMap(['white', 'black'])
mask_grid = np.eye(mtx.shape[0], dtype=int)
fig_obj, ax_obj = plt.subplots(figsize=(6, 5))
img = ax_obj.imshow(mask_grid, cmap=palette, aspect='equal', vmin=0, vmax=1)
for r in range(mtx.shape[0]):
for c in range(mtx.shape[1]):
tone = 'white' if r == c else 'black'
ax_obj.text(c, r, str(mtx[r, c]), ha='center', va='center',
color=tone, fontsize=16, fontweight='bold')
if names is None:
names = range(mtx.shape[0])
ax_obj.set_xticks(range(mtx.shape[1]))
ax_obj.set_yticks(range(mtx.shape[0]))
ax_obj.set_xticklabels(names)
ax_obj.set_yticklabels(names)
ax_obj.set_xlabel('Predicted label')
ax_obj.set_ylabel('True label')
plt.tight_layout()
plt.show()
render_bw_confusion(data_mx)
В этой схеме окраску задает единичная матрица, а значения из матрицы ошибок выводятся текстом поверх соответствующих ячеек. На диагонали текст белый — для контраста с черным фоном; вне диагонали текст черный — для контраста с белым.
Отображение: 0 → белый (вне диагонали), 1 → черный (диагональ)
Подробности о механике цветовых отображений — в официальной документации matplotlib: matplotlib color mapping.
Почему это важно
Визуальные соглашения — это не косметика. Во многих отчетах и статьях диагональ означает корректные предсказания, и резкая черная диагональ мгновенно передает качество без дополнительной нагрузки на восприятие градиентов. Такой рисунок хорошо печатается в черно-белых документах и уменьшает неоднозначность при просмотре с ограничениями по цветовому восприятию или на экранах с низкой контрастностью.
Выводы
Если требуется бинарное визуальное разделение в матрице ошибок, не пытайтесь «переучить» стандартную тепловую карту. Вместо этого явно задайте палитру и передайте в imshow бинарную маску. Сохраняйте читаемость чисел, инвертируя цвет текста в каждой ячейке, и выставьте подписи осей под ваши классы. Этот небольшой прием дает детерминированный, готовый к публикации рисунок, который сохраняет смысл во всех форматах.