Heungson
Heungson

Reputation: 61

How to make 1d array multiplied by 2d array resulting in 3d array for python

I am worrying that this might be a really stupid question. However I can't find a solution. I want to do the following operation in python without using a loop, because I am dealing with large size arrays. Is there any suggestion?

import numpy as np
a = np.array([1,2,3,..., N]) # arbitrary 1d array
b = np.array([[1,2,3],[4,5,6],[7,8,9]]) # arbitrary 2d array
c = np.zeros((N,3,3))
c[0,:,:] = a[0]*b
c[1,:,:] = a[1]*b
c[2,:,:] = a[2]*b
c[3,:,:] = ...
...
...
c[N-1,:,:] = a[N-1]*b

Upvotes: 3

Views: 1723

Answers (4)

mins
mins

Reputation: 7504

What you're doing is an outer product. This operator is available in numpy as multiply.outer:

import numpy as np
a = np.array([1,2,3,4,5])
b = np.array([[1,2,3],
              [4,5,6],
              [7,8,9]])
c = np.multiply.outer(a, b)
print(c)

[[[ 1  2  3]
  [ 4  5  6]
  [ 7  8  9]]

 [[ 2  4  6]
  [ 8 10 12]
  [14 16 18]]

 [[ 3  6  9]
  [12 15 18]
  [21 24 27]]

 [[ 4  8 12]
  [16 20 24]
  [28 32 36]]

 [[ 5 10 15]
  [20 25 30]
  [35 40 45]]]

multiply is a ufunc. According to the documentation of ufunc.outer: "Apply the ufunc op to all pairs (a, b) with a in A and b in B" (here that means applying the multiply operator). Still according to the documentation, doing this is equivalent to:

r = empty(len(A),len(B))
for i in range(len(A)):
    for j in range(len(B)):
        r[i,j] = op(A[i], B[j])  # op = ufunc in question

Upvotes: 0

gboffi
gboffi

Reputation: 25023

My answer uses only numpy primitives, in particular for the array multiplication (what you want to do has a name, it is an outer product).

Due to a restriction in numpy's outer multiplication function we have to reshape the result, but this is very cheap because the data block of the ndarray is not involved.

% python
Python 2.7.8 (default, Oct 18 2014, 12:50:18) 
[GCC 4.9.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> a = np.array((1,2))
>>> b = np.array([[n*m for m in (1,2,3,4,5,6)] for n in (10,100,1000)])
>>> print b
[[  10   20   30   40   50   60]
 [ 100  200  300  400  500  600]
 [1000 2000 3000 4000 5000 6000]]
>>> print np.outer(a,b)
[[   10    20    30    40    50    60   100   200   300   400   500   600
   1000  2000  3000  4000  5000  6000]
 [   20    40    60    80   100   120   200   400   600   800  1000  1200
   2000  4000  6000  8000 10000 12000]]
>>> print "Almost there!"
Almost there!
>>> print np.outer(a,b).reshape(a.shape[0],b.shape[0], b.shape[1])
[[[   10    20    30    40    50    60]
  [  100   200   300   400   500   600]
  [ 1000  2000  3000  4000  5000  6000]]

 [[   20    40    60    80   100   120]
  [  200   400   600   800  1000  1200]
  [ 2000  4000  6000  8000 10000 12000]]]
>>> 

Upvotes: 2

DSM
DSM

Reputation: 353069

To avoid Python-level loops, you could use np.newaxis to expand a (or None, which is the same thing):

>>> a = np.arange(1,5)
>>> b = np.arange(1,10).reshape((3,3))
>>> a[:,None,None]*b
array([[[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9]],

       [[ 2,  4,  6],
        [ 8, 10, 12],
        [14, 16, 18]],

       [[ 3,  6,  9],
        [12, 15, 18],
        [21, 24, 27]],

       [[ 4,  8, 12],
        [16, 20, 24],
        [28, 32, 36]]])

Or np.einsum, which is overkill here, but is often handy and makes it very explicit what you want to happen with the coordinates:

>>> c2 = np.einsum('i,jk->ijk', a, b)
>>> np.allclose(c2, a[:,None,None]*b)
True

Upvotes: 1

João Paulo
João Paulo

Reputation: 6680

Didn't understand this multiplication.. but here is a way to make matrix multiplication in python using numpy:

import numpy as np
a = np.matrix([1, 2])
b = np.matrix([[1, 2], [3, 4]])
result = a*b
print(result)

>>>result
matrix([7, 10])

Upvotes: 0

Related Questions