Умножение числа по оси - PullRequest
1 голос
/ 04 июля 2019

У меня есть 2 массива, один из которых имеет форму (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 для умножения на заданную ось?

Я пробовал numpy.multiply, поскольку он говорит, что 'axis' является недопустимым ключевым словом для 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.

Ответы [ 3 ]

1 голос
/ 04 июля 2019
[[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 голос
/ 04 июля 2019

Один из способов сделать это, предполагая, что вы в порядке с 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)
0 голосов
/ 04 июля 2019

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

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)

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...