Умножение каждого элемента одного массива на каждый элемент другого массива



Скажем, у меня есть два массива,



import numpy as np


x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])


Что самое быстрое, самое Питонское и т. д., прием. способ получения нового массива z с числом элементов, равным x.size * y.size, в котором элементы являются произведениями каждой пары элементов (x_i, y_j) из двух входных массивов.



Перефразируя, я ищу массив z, в котором z[k] является x[i] * y[j].

Простой, но неэффективный способ получить это выглядит следующим образом:



z = np.empty(x.size * y.size)
counter = 0
for i in x:
for j in y:
z[counter] = i * j
counter += 1


Выполнение приведенного выше кода показывает, что z в этом примере is



In [3]: z
Out[3]:
array([ 5., 6., 7., 8., 10., 12., 14., 16., 15., 18., 21.,
24., 20., 24., 28., 32.])
1010   4  

4 ответов:

Может быть предложено здесь более двух подходов.

Использование matrix-multiplication with np.dot:

np.dot(x[:,None],y[None]).ravel()

С np.einsum:

np.einsum('i,j->ij',x,y).ravel()

Тесты во время выполнения

In [31]: N = 10000
    ...: x = np.random.rand(N)
    ...: y = np.random.rand(N)
    ...: 

In [32]: %timeit np.dot(x[:,None],y[None]).ravel()
1 loops, best of 3: 302 ms per loop

In [33]: %timeit np.einsum('i,j->ij',x,y).ravel()
1 loops, best of 3: 274 ms per loop

То же самое, что @BilalAkil's answer но с ravel() вместо flatten() в качестве более быстрой альтернативы -

In [34]: %timeit np.multiply.outer(x, y).ravel() 
1 loops, best of 3: 211 ms per loop

@BilalAkil's answer:

In [35]: %timeit np.multiply.outer(x, y).flatten()
1 loops, best of 3: 451 ms per loop

@Tim Leathart's answer:

In [36]: %timeit np.array([y * a for a in x]).flatten()
1 loops, best of 3: 766 ms per loop

Ну, у меня не так много опыта с numpy, но быстрый поиск дал мне это: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.outer.html

>>> np.multiply.outer([1, 2, 3], [4, 5, 6])
array([[ 4,  5,  6],
   [ 8, 10, 12],
   [12, 15, 18]])

Затем вы можете сгладить этот массив, чтобы получить тот же результат, что и просили: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flatten.html

EDIT: ответ @ Divakar показал нам, что ravel будет делать то же самое, что и flatten, за исключением более быстрого o.O, поэтому используйте его вместо этого.

Итак, в в вашем случае это выглядело бы так:

>>> np.multiply.outer(x, y).ravel()

Бонус: вы можете пойти многомерным с этим!

Вот как это сделать:

import numpy as np

x = np.array([1, 2, 3, 4])
y = np.array([5, 6, 7, 8])
z = np.array([y * a for a in x]).flatten()

Вот один из способов сделать это:

import itertools


z = np.empty(x.size * y.size)
counter = 0
for i, j in itertools.product(x, y):
    z[counter] = i * j
    counter += 1
Было бы неплохо избавиться от этого счетчика, а также от петли for (но, по крайней мере, я избавился от одной из петель).

Обновить

Будучи однолинейными, другие представленные ответы лучше, чем этот (по моим стандартам, которые ценят краткость). Результаты синхронизации ниже показывают, что ответ @BilalAkil быстрее, чем ответ @TimLeathart:

In [10]: %timeit np.array([x * j for j in y]).flatten()
The slowest run took 4.37 times longer than the fastest. This could mean that an intermediate result is being cached 
10000 loops, best of 3: 24.2 µs per loop

In [11]: %timeit np.multiply.outer(x, y).flatten()
The slowest run took 5.59 times longer than the fastest. This could mean that an intermediate result is being cached 
100000 loops, best of 3: 10.5 µs per loop

Comments

    Ничего не найдено.