Я пытаюсь умножить каждый из членов двумерного массива на соответствующие члены одномерного массива. Это очень просто, если я хочу умножить каждый столбец на одномерный массив, как показано в функции 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? Большое спасибо Алекс
A * B
вам нужно сделатьA * B[...,None]
транспонированиеB
, добавив новую ось (None
).x = [[1],[2],[3]]
что ли.Ответы:
Нормальное умножение, как вы показали:
>>> 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]])
источник
[a,b] op [c,d] -> [[a*c, b*c], [a*d, b*d]]
.Я сравнил разные варианты скорости и обнаружил, что, к моему большому удивлению, все варианты (кроме
diag
) одинаково быстрые. Я лично используюA * b[:, None]
(или
(A.T * b).T
) потому что он короткий.Код для воспроизведения сюжета:
import numpy import perfplot def newaxis(data): A, b = data return A * b[:, numpy.newaxis] def none(data): A, b = data return A * b[:, None] 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.save( "p.png", setup=lambda n: (numpy.random.rand(n, n), numpy.random.rand(n)), kernels=[ newaxis, none, double_transpose, double_transpose_contiguous, diag_dot, einsum, ], n_range=[2 ** k for k in range(14)], logx=True, logy=True, xlabel="len(A), len(b)", )
источник
Вы также можете использовать матричное умножение (также известное как точечный продукт):
a = [[1,2,3],[4,5,6],[7,8,9]] b = [0,1,2] c = numpy.diag(b) numpy.dot(c,a)
Что изящнее, наверное, дело вкуса.
источник
dot
здесь действительно перебор. Вы просто делаете ненужное умножение на 0 и прибавление к 0.diag
матрицы.Еще одна уловка (начиная с v1.6)
A=np.arange(1,10).reshape(3,3) b=np.arange(3) np.einsum('ij,i->ij',A,b)
Я хорошо разбираюсь в numpy broadcasting (
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)
, по сути, делает двойной транспонирование.источник
einsumm
(25 микро) в два раза быстрее остальных (точка-диагональ тормозит больше). Это np 1.7, недавно скомпилированный с помощью libatlas3gf-sse2 и libatlas-base-dev (Ubuntu 10.4, однопроцессорный).timeit
дает максимум 10000 петель.numpy
версий назад.Для тех потерянных душ в Google, использование
numpy.expand_dims
thennumpy.repeat
будет работать, а также будет работать в случаях более высоких измерений (например, умножение формы (10, 12, 3) на (10, 12)).>>> import numpy >>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]]) >>> b = numpy.array([0,1,2]) >>> b0 = numpy.expand_dims(b, axis = 0) >>> b0 = numpy.repeat(b0, a.shape[0], axis = 0) >>> b1 = numpy.expand_dims(b, axis = 1) >>> b1 = numpy.repeat(b1, a.shape[1], axis = 1) >>> a*b0 array([[ 0, 2, 6], [ 0, 5, 12], [ 0, 8, 18]]) >>> a*b1 array([[ 0, 0, 0], [ 4, 5, 6], [14, 16, 18]])
источник
Почему бы тебе просто не сделать
>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) >>> c = np.array([0,1,2]) >>> (m.T * c).T
??
источник