Нормализация массивов NumPy для графиков Matplotlib

Создано: 08.12.2025

Термин "нормализация" используют в разных областях, при этом в статистике под ней понимают действия, направленные на согласование отдельных наборов данных для облегчения их сравнения, то есть данные разного типа становятся подобными друг другу, сопоставимыми. У нормализованных данных отсутствуют единицы измерения. На практике это означает изменение масштаба реальных числовых значений, приведением их диапазону от 0 до 1. Дополнительными преимуществами нормализации являются снижение избыточности и сложности, ясность и получение более качественных данных.

В Python есть библиотеки (scikit-lean, связанная с машинным обучением, и другие), в которых имеются специально предназначенные для нормализации данных функции. Однако в связке NumPy и Matplotlib, когда сопоставимость данных необходима только лишь, например, для применения цветовой карты, можно просто использовать формулы различных способов нормализации.

Рассмотрим пример, в котором воксели должны выводиться разным цветом в зависимости от значения элементов в массиве:

Нормализация массива для цветовой карты в Matplotlib
import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()
bx = fig.add_subplot(projection='3d')

b = np.array([[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10],
               [10, 9, 8, 7, 6], [5, 4, 3, 2, 10]],
              [[0, 1, 3, 2, 4], [3, 6, 7, 8, 9],
               [5, 7, 3, 8, 1], [1, 3, 5, 7, 2]]])

bx.voxels(b, edgecolors='#678',
          facecolors=plt.cm.plasma_r(b/np.max(b)))
bx.set_xticks([0, 1, 2])
bx.set_xlabel('X'); bx.set_ylabel('Y'); bx.set_zlabel('Z')

plt.show()

Здесь мы сопоставляем числа в массиве цветам по шкале "плазма реверс", которая градуирована в долях единицы. Чтобы подобное было возможно, требуется получить из исходного массива его нормализованный вид, где значения также будут выражены в долях единицы. В примере выше используется метод нормализации под названием "минимальное-максимальное масштабирование". В полном варианте код выглядел бы так:

l = np.min(b)
h = np.max(b)
scale = np.array([(x - l) / (h - l) for x in b])

bx.voxels(b, edgecolors='#678', facecolors=plt.cm.plasma_r(scale))

Однако если минимумом является ноль, то формула нормализации каждого значения массива сокращается до x / h. В случае поэлементных операций с целым массивом в NumPy это выглядит как b/np.max(b).

Другой простой способ нормализации — метод извлечения остатков (residual extraction), когда из каждого значения массива вычитается среднее значение элементов этого массива. Обычно такой подход используют для сравнения данных со схожими диапазонами.

fig, axs = plt.subplots(1, 2, figsize=(10, 4))

a = np.array([20, 34, 8, 18, 49, 35, 64, 32, 69, 11, 54, 61])
b = np.array([48, 29, 35, 70, 15, 40, 50, 90, 85, 31, 74, 20])

axs[0].plot(a, '*-c')
axs[0].plot(b, '^-y')
axs[0].plot(np.arange(0, len(a)), np.full(len(a), np.mean(a)),
            '--c', alpha=0.5)  # линия среднего значения
axs[0].plot(np.arange(0, len(b)), np.full(len(b), np.mean(b)),
            '--y', alpha=0.5)
axs[0].set_title('Исходные данные')

ar = a - int(np.mean(a))
print(ar)
br = b - int(np.mean(b))
print(br)

axs[1].plot(ar, '*-c')
axs[1].plot(br, '^-y')
axs[1].set_title('Нормализованные данные')
Сравнение графиков исходных и нормализованных массивов

По первому плоту с графиками самих массивов сложнее сказать в каких данных выше дисперсия (больше разброс от среднего значения). На втором, где массивы нормализованы, видно, что от нуля (среднего значения для обоих массивов данных) дальше отклоняются остатки второго.

Подмодуль linalg (linear algebra) библиотеки NumPy содержит различные функции для линейных алгебраических вычислений, среди которых есть функция norm. Она возвращает так называемую норму вектора (одномерного массива) или матрицы (двумерного массива).

Норма — это скалярное положительное значение, характеризующее "размер" массива. Она может вычисляться по-разному. Как именно, указывается через параметр ord (для векторов и матриц набор возможных значений отличается). По-умолчанию для одномерных массивов норма вычисляется по форме L2 (евклидова норма, единичный вектор).

a = np.array([20, 34, 8, 18, 49, 35, 64, 32, 69, 11, 54, 61])
b = np.array([48, 29, 35, 70, 15, 40, 50, 90, 85, 31, 74, 20])
an = np.linalg.norm(a)
an2 = np.linalg.norm(a, ord=np.inf)
bn = np.linalg.norm(b)

plt.plot(a/an, '*-b')
plt.plot(a/an2, '^-c')
plt.plot(b/bn, '^-r')
Результат нормализации с помощью функции norm подмодуля linalg