Reputation: 26259
I'm sure this one is easy in numpy
, however I did not find the appropriate method. Basically I need something like outer()
but for subtraction. Here is my working code via LC:
import numpy as np
a = np.array(((1,2,3), (2,3,4), (3,4,5)))
b = np.array(((6,7,8), (6,3,1)))
print np.array([i-j for i in a for j in b])
Output:
[[-5 -5 -5]
[-5 -1 2]
[-4 -4 -4]
[-4 0 3]
[-3 -3 -3]
[-3 1 4]]
Here is the speed comparison of the posted answers. a
has 1000000 entries and b
has 100:
In [22]: %timeit np.array([i-j for i in a for j in b])
1 loops, best of 3: 12.3 s per loop
In [23]: %timeit np.repeat(a,b.shape[0],0)-np.tile(b,(a.shape[0],1))
10 loops, best of 3: 50.1 ms per loop
In [24]: %timeit (a[:,np.newaxis,:]-b).reshape(-1, 3)
10 loops, best of 3: 125 ms per loop
Upvotes: 2
Views: 932
Reputation: 879251
You could take advantage of broadcasting by reshaping a
before subtraction, then reshaping again to get the desired result:
In [97]: (a[:,np.newaxis,:]-b).reshape(-1, 3)
Out[97]:
array([[-5, -5, -5],
[-5, -1, 2],
[-4, -4, -4],
[-4, 0, 3],
[-3, -3, -3],
[-3, 1, 4]])
Explanation:
In [101]: a.shape
Out[101]: (3, 3)
In [99]: a[:,np.newaxis,:].shape
Out[99]: (3, 1, 3)
In [100]: b.shape
Out[100]: (2, 3)
When NumPy evaluates a[:,np.newaxis,:]-b
it broadcasts the shapes of a[:,np.newaxis,:]
and b
both to (3, 2, 3)
before subtraction. Roughly speaking, the first and second axes do not interact. The subtraction occurs only in the 3rd axis. The subtraction is performed for each location with respect to the first and second axes. That's sort of the NumPy equivalent of
for i in a for j in b
The result is
In [102]: a[:,np.newaxis,:]-b
Out[102]:
array([[[-5, -5, -5],
[-5, -1, 2]],
[[-4, -4, -4],
[-4, 0, 3]],
[[-3, -3, -3],
[-3, 1, 4]]])
In [103]: (a[:,np.newaxis,:]-b).shape
Out[103]: (3, 2, 3)
The only thing left to be done is to reshape the result to get it in the desired form.
Upvotes: 7
Reputation: 52646
Use np.repeat() and np.tile() to repeat/tile the array
import numpy as np
a = np.array(((1,2,3), (2,3,4), (3,4,5)))
b = np.array(((6,7,8), (6,3,1)))
c = np.repeat(a,b.shape[0],0)-np.tile(b,(a.shape[0],1))
print c
array([[-5, -5, -5],
[-5, -1, 2],
[-4, -4, -4],
[-4, 0, 3],
[-3, -3, -3],
[-3, 1, 4]])
Upvotes: 3