2013-08-29 3 views
36

Я пытаюсь умножить каждый из терминов в 2D-массиве на соответствующие члены в 1D-массиве. Это очень просто, если я хочу умножить каждый столбец на массив 1D, как показано в функции numpy.multiply. Но я хочу сделать наоборот, умножить каждый член в строке. Другими словами я хочу умножать:Умножение в массив numpy

[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

+2

Я понял это, как только я представил вопрос. Сначала перенесите квадратную матрицу, умножьте ее, а затем транспонируйте ответ. –

+0

Лучше переносить строку в матрицу столбцов, тогда вам не нужно повторно транспонировать ответ. Если 'A * B', вам нужно будет сделать A * B [..., None]', который переносит 'B', добавляя новую ось (' None'). – askewchan

+0

Спасибо, это правда. Проблема в том, что когда у вас есть 1D-массив, вызывающий .transpose() или .T, он не превращает его в массив столбцов, он оставляет его как строку, так как, насколько я знаю, вы должны определить его как столбец с места в карьер. Как 'x = [[1], [2], [3]]' или что-то. –

ответ

49

Нормальный Умножение, как вы показали:

>>> 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]]) 
+0

Спасибо, именно то, что я искал. –

+0

С помощью нового метода оси можно умножить два 1D массива и сгенерировать 2D-массив. Например, '[a, b] op [c, d] -> [[a * c, b * c], [a * d, b * d]]'. –

15

Вы также можете использовать матрицу multip (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) 

Какой изящный, вероятно, вопрос вкуса.

+2

хороший, +1, не думал об этом – jterrace

+8

'dot' действительно переборщил здесь. Вы просто делаете ненужное умножение на 0 и добавляете к 0. –

+1

, это также может вызвать проблемы с памятью, если вы хотите перемножить вектор nx1 в матрицу nxd, где d больше n. – Jonasson

11

Еще один трюк (как в v1.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 

Кстати, изменение i к j, np.einsum('ij,j->ij',A,b), производит матрицу, что Алекс не хочет. И np.einsum('ji,j->ji',A,b) делает, по сути, двойную транспозицию.

+0

Если вы потратите время на компьютер с массивами, достаточно большими, чтобы потребовалось не менее нескольких миллисекунд и опубликовать результаты [здесь] (http://stackoverflow.com/questions/18365073/why-is-numpys-einsum-faster- чем-numpys-built-in-functions) вместе с вашей соответствующей системной информацией было бы очень признательно. – Daniel

+1

с большим массивом (100x100) относительные числа примерно одинаковы. 'einsumm' (25 микро) в два раза быстрее других (точка-диаг замедляет больше). Это np 1.7, недавно скомпилированный с помощью libatlas3gf-sse2 и libatlas-base-dev (Ubuntu 10.4, один процессор). 'timeit' дает лучшее из 10000 циклов. – hpaulj

+1

Это отличный ответ, и я думаю, что это тот, который должен был быть принят. Однако код, написанный выше, фактически дает матрицу, которую Алекс пытался избежать (на моей машине). Один hpaulj сказал, что это неправильно, на самом деле правильный. –

-2

Почему вы не просто делать

>>> m = np.array([[1,2,3],[4,5,6],[7,8,9]]) 
>>> c = np.array([0,1,2]) 
>>> (m.T * c).T 

??

+2

Этот точный подход уже показан в принятом ответе, я не вижу, как это добавляет что-либо. –

5

Я сравнил различные варианты скорости и обнаружили, что - к моему удивлению - все варианты (кроме einsum для малого n и diag для больших n) одинаково быстро:

enter image description here


Код для воспроизведения сюжет:

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)' 
    ) 
Смежные вопросы