Как векторизовать это выражение с помощью Numpy?

Вопрос или проблема

Я пытаюсь вычислить массив “matrix” ниже. Как я могу сделать это, используя векторизованные функции NumPy?

x = np.array([
    [2, 1, 0],
    [1, 1, 0],
    [3, 2, 1],
    [1, 0, 0],
    [2, 3, 0]
])

y = np.array([
    [405, 200, 150],
    [200, 300, 150],
    [150, 100, 105],
    [425, 200, 250],
    [500, 620, 300]
])

matrix = np.zeros((5,3,4))  
for i in range(5):
    for j in range(3):
       matrix[i,j,x[i,j]] = y[i,j]

Я пробовал это:

vmatrix = np.zeros((5,3,4))

vmatrix[:,:,x] = y

Но это не сработало…

Вы можете сделать это в одной строке, превратив x в одноразовый вектор (используя методы, вдохновленные этим ответом), и изменив размер y, чтобы подготовить размеры для трансляции:

matrix2 = np.eye(4)[x] * np.expand_dims(y, axis=-1)

print(np.equal(matrix, matrix2).all()) # True

Используйте замысловатую индексацию с meshgrid:

ix, iy = np.ogrid[:5, :3]
matrix = np.zeros((5, 3, 4))
matrix[ix, iy, x] = y

Ответ или решение

Векторизация выражений с использованием NumPy позволяет значительно ускорить операции с массивами и избежать использования вложенных циклов. В данном случае мы хотим создать массив matrix, где значения из массива y будут помещены в соответствии с индексами, заданными массивом x.

В понимании задачи, x определяет, в каком слое третьего измерения итогового массива matrix должно находиться соответствующее значение из массива y. Для выполнения этой задачи можно воспользоваться несколькими подходами.

Подход 1: Использование одноразовых векторов и broadcasting

import numpy as np

x = np.array([
    [2, 1, 0],
    [1, 1, 0],
    [3, 2, 1],
    [1, 0, 0],
    [2, 3, 0]
])

y = np.array([
    [405, 200, 150],
    [200, 300, 150],
    [150, 100, 105],
    [425, 200, 250],
    [500, 620, 300]
])

matrix = np.eye(4)[x] * np.expand_dims(y, axis=-1)

print(matrix)

Объяснение:

В этом решении используется метод создания одноразовых (one-hot) векторов с помощью np.eye(4)[x], что позволяет получить кота-матрицу, где строки соответствуют значениям из массива x, а оставшиеся элементы нули. Затем y изменяется с помощью np.expand_dims(y, axis=-1) для добавления дополнительного измерения, что делает его соответствующим для умножения (broadcasting).

Подход 2: Использование массовых индексов с помощью meshgrid

import numpy as np

# Исходные массивы
x = np.array([
    [2, 1, 0],
    [1, 1, 0],
    [3, 2, 1],
    [1, 0, 0],
    [2, 3, 0]
])

y = np.array([
    [405, 200, 150],
    [200, 300, 150],
    [150, 100, 105],
    [425, 200, 250],
    [500, 620, 300]
])

# Создаем массив нулей
matrix = np.zeros((5, 3, 4))

# Используем ogrid для создания индексов
ix, iy = np.ogrid[:5, :3]

# Заполняем массив значениями из y в нужных местах
matrix[ix, iy, x] = y

print(matrix)

Объяснение:

В этом варианте мы используем np.ogrid, чтобы создать массив индексов для первой двухмерной размерности matrix. Затем, используя массовую индексацию, мы можем напрямую заполнить значения из y по соответствующим индексам, что также позволяет избежать циклов.

Заключение:

Оба подхода позволяют эффективно векторизовать исходное выражение и избежать использования вложенных циклов, что существенно ускоряет выполнение кода. Выберите метод, который вам удобнее использовать в дальнейшей практике, с учетом удобства и читаемости кода.

Оцените материал
Добавить комментарий

Капча загружается...