У меня есть 2 массива numpy, один из них имеет форму (2, 5, 10), а другой имеет форму (2, 5, 10, 10). Мне нужно умножение [[x1[i][j] * x2[i][j] for j in range(5)] for i in range(2)] Он работает как задумано, но довольно медленно, и я хотел умножить непосредственно x1 * x2, но numpy это не нравится. Есть ли метод умножения для умножения по заданной оси?

Я пробовал numpy.multiply, потому что он говорит, что ось является недопустимым ключевым словом для ufunc 'multiply'

x1 = np.arange(100).reshape((2, 5, 10))
x2 = np.arange(1000).reshape((2, 5, 10, 10))
x = [[x1[i][j] * x2[i][j] for j in range(5)] for i in range(2)] # slow method that works
x = np.multiply(x1, x2, axis=2) # What I'm looking for but doesn't work.
1
Aurélien 4 Июл 2019 в 18:45

3 ответа

Лучший ответ

Один из способов сделать это, предполагая, что с x в порядке типа np.array у вас все в порядке, - лучше использовать Трансляция NumPy (см. ответ @ hpaulj):

import numpy as np

x1 = np.arange((2 * 3 * 4)).reshape((2, 3, 4))
x2 = np.arange((2 * 3 * 4 * 4)).reshape((2, 3, 4, 4))
x = [[x1[i][j] * x2[i][j] for j in range(3)] for i in range(2)]) # slow method that works

# : using NumPy broadcasting
y = x1[:, :, None, :] * x2

np.all(np.array(x) == y)
# True

Timewise - это ~ 10-кратное ускорение:

%timeit np.array([[x1[i][j] * x2[i][j] for j in range(3)] for i in range(2)])
# 13.6 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit x1[:, :, None, :] * x2
# 1.4 µs ± 10.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
2
norok2 4 Июл 2019 в 16:45

Используя ваш вклад, мы имеем

x1.shape (2, 5, 10) x2.shape (2, 5, 10, 10)

Вы можете использовать np.tensordot для умножения вдоль произвольных осей - до тех пор, пока они совпадают по размеру.

x3 = np.tensordot(x1, x2, (1,1)) x3.shape (2, 10, 2, 10, 10)

Тензордот также позволяет вам умножать и добавлять по нескольким осям. В этом случае, например.

x4 = np.tensordot(x1,x2, ((0,1), (0,1))) x4.shape (10, 10, 10)

Здесь аргумент ((0,1), (0,1)) относится к осям x1 и x2 соответственно.

0
rohrdr 4 Июл 2019 в 16:40
[[x1[i][j] * x2[i][j] for j in range(5)] for i in range(2)]

Использует вещание также.

x1[i,j].shape    # (10,)
x2[i,j].shape    # (10,10)

Чтобы умножить их, правила вещания добавляют измерение:

(10,), (10,10) => (1,10), (10,10) => (10,10)

Но если бы вы использовали x1[i,j,:,None], вещание пошло бы

(10,1), (10,10) => (10,10)

Производя разные номера.

В формате @ norok2 это разница между:

x1[:, :, None, :] * x2
x1[:, :, :, None] * x2

Разница была бы более очевидной, если бы x2 имел форму (2,5,8,10) или (2,5,10,8).

1
hpaulj 4 Июл 2019 в 16:36