Вопрос или проблема
Я пытаюсь вычислить массив “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
по соответствующим индексам, что также позволяет избежать циклов.
Заключение:
Оба подхода позволяют эффективно векторизовать исходное выражение и избежать использования вложенных циклов, что существенно ускоряет выполнение кода. Выберите метод, который вам удобнее использовать в дальнейшей практике, с учетом удобства и читаемости кода.