Умножение в массив numpy
Я пытаюсь умножить каждое из терминов в 2D-массиве на соответствующие члены в 1D-массиве. Это очень просто, если я хочу умножить каждый столбец на массив 1D, как показано в numpy.multiply. Но я хочу сделать наоборот, умножить каждый член в строке.
Другими словами, я хочу умножить:
[1,2,3] [0]
[4,5,6] * [1]
[7,8,9] [2]
и получим
[0,0,0]
[4,5,6]
[14,16,18]
но вместо этого я получаю
[0,2,6]
[0,5,12]
[0,8,18]
Кто-нибудь знает, есть ли элегантный способ сделать это с помощью numpy?
Большое спасибо,
Alex
Ответы
Ответ 1
Нормальное умножение, как вы показали:
>>> import numpy as np
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> m * c
array([[ 0, 2, 6],
[ 0, 5, 12],
[ 0, 8, 18]])
Если вы добавите ось, она будет умножаться так, как вы хотите:
>>> m * c[:, np.newaxis]
array([[ 0, 0, 0],
[ 4, 5, 6],
[14, 16, 18]])
Вы также можете транспонировать дважды:
>>> (m.T * c).T
array([[ 0, 0, 0],
[ 4, 5, 6],
[14, 16, 18]])
Ответ 2
Вы также можете использовать матричное умножение (aka dot product):
a = [[1,2,3],[4,5,6],[7,8,9]]
b = [0,1,2]
c = numpy.diag(b)
numpy.dot(c,a)
Что более элегантно, вероятно, дело вкуса.
Ответ 3
Еще один трюк (по версии 1.6)
A=np.arange(1,10).reshape(3,3)
b=np.arange(3)
np.einsum('ij,i->ij',A,b)
Я разбираюсь в вещании numpy (newaxis
), но я все еще нахожу свой путь вокруг этого нового инструмента einsum
. Поэтому я немного поиграл, чтобы найти это решение.
Сроки (с использованием Ipython timeit):
einsum: 4.9 micro
transpose: 8.1 micro
newaxis: 8.35 micro
dot-diag: 10.5 micro
Кстати, при изменении a i
до j
, np.einsum('ij,j->ij',A,b)
получается матрица, которую Алекс не хочет. И np.einsum('ji,j->ji',A,b)
делает, по сути, двойную транспонирование.
Ответ 4
Я сравнивал различные варианты скорости и обнаружил, что, к моему удивлению, все опции (кроме diag
) одинаково быстрые:
![введите описание изображения здесь]()
Код для воспроизведения сюжета:
import numpy
import perfplot
def newaxis(data):
A, b = data
return A * b[:, numpy.newaxis]
def double_transpose(data):
A, b = data
return (A.T * b).T
def double_transpose_contiguous(data):
A, b = data
return numpy.ascontiguousarray((A.T * b).T)
def diag_dot(data):
A, b = data
return numpy.dot(numpy.diag(b), A)
def einsum(data):
A, b = data
return numpy.einsum('ij,i->ij', A, b)
perfplot.show(
setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)),
kernels=[
newaxis, double_transpose, double_transpose_contiguous, diag_dot,
einsum
],
n_range=[2**k for k in range(10)],
logx=True,
logy=True,
xlabel='len(A), len(b)'
)
Ответ 5
Почему бы вам просто не сделать
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> c = np.array([0,1,2])
>>> (m.T * c).T
??