I have two Numpy arrays x
with shape (m, i)
and y
with shape (m, j)
(so the number of rows is the same). I would like to multiply each column of x
with each column of y
element-wise so that the result is of shape (m, i*j)
.
Example:
import numpy as np
np.random.seed(1)
x = np.random.randint(0, 2, (10, 3))
y = np.random.randint(0, 2, (10, 2))
This creates the following two arrays x
:
array([[1, 1, 0],
[0, 1, 1],
[1, 1, 1],
[0, 0, 1],
[0, 1, 1],
[0, 0, 1],
[0, 0, 0],
[1, 0, 0],
[1, 0, 0],
[0, 1, 0]])
and y
:
array([[0, 0],
[1, 1],
[1, 1],
[1, 0],
[0, 0],
[1, 1],
[1, 1],
[1, 1],
[0, 1],
[1, 0]])
Now the result should be:
array([[0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0]])
Currently, I've implemented this operation with two nested loops over the columns of x
and y
:
def _mult(x, y):
r = []
for xc in x.T:
for yc in y.T:
r.append(xc * yc)
return np.array(r).T
However, I'm pretty sure that there must be a more elegant solution that I can't seem to come up with.
Use
NumPy broadcasting
-Explanation
As inputs, we have -
With
y[:,None]
, we are introducing a new axis between the existing two dims, thus creating a3D
array version of it. This keeps the first axis as the first one in3D
version and pushes out the second axis as the third one.With
x[...,None]
, we are introducing a new axis as the last one by pushing up the two existing dims as the first two dims to result in a3D
array version.To summarize, with the introduction of new axes, we have -
With
y[:,None]*x[...,None]
, there would bebroadcasting
for bothy
andx
, resulting in an output array with a shape of(10,3,2)
. To get to the final output array of shape(10,6)
, we just need to merge the last two axes with that reshape.