Умножение через в массиве 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

62
задан 30 August 2013 в 02:53

6 ответов

Нормальное умножение как Вы показало:

>>> 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]])
87
ответ дан 31 October 2019 в 13:39

Я сравнил различные варианты для скорости и нашел, что †“к моему большому удивлению †“все опции (кроме diag) одинаково быстры. Я лично использую

A * b[:, None]

(или (A.T * b).T), потому что это коротко.

enter image description here

<час>

Код для репродуцирования графика:

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)",
)
24
ответ дан 31 October 2019 в 13:39

Для тех потерянных душ на Google, с помощью numpy.expand_dims затем numpy.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]])
1
ответ дан 31 October 2019 в 13:39

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

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

??

-4
ответ дан 31 October 2019 в 13:39

Вы могли также использовать умножение матриц (иначе скалярное произведение):

a = [[1,2,3],[4,5,6],[7,8,9]]
b = [0,1,2]
c = numpy.diag(b)

numpy.dot(c,a)

то, Которое более изящно, является, вероятно, вопросом вкуса.

15
ответ дан 31 October 2019 в 13:39

Еще один прием (с 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), производит матрицу, которую не хочет Alex. И np.einsum('ji,j->ji',A,b) делает, в действительности, двойные транспонируют.

15
ответ дан 31 October 2019 в 13:39

Другие вопросы по тегам:

Похожие вопросы: